HM变化量化中的Scaling 操作(解码器)

news/2024/10/5 13:31:03/文章来源:https://www.cnblogs.com/jhzj/p/18447786

(1)xIntraRecBlk调用invTransformNxN处理TU块

if (pcCU->getCbf(uiAbsPartIdx, compID, rTu.GetTransformDepthRel()) != 0){m_pcTrQuant->invTransformNxN( rTu, compID, piResi, uiStride, pcCoeff, cQP DEBUG_STRING_PASS_INTO(psDebug) );}

(2)invTransformNxN 用于执行逆量化逆变换操作,将编码时的变换系数(Transform Coefficients)转换回原始的残差值(Residuals)

Void TComTrQuant::invTransformNxN(      TComTU        &rTu,const ComponentID    compID,Pel          *pcResidual,const UInt           uiStride,TCoeff       * pcCoeff,const QpParam       &cQPDEBUG_STRING_FN_DECLAREP(psDebug))
{TComDataCU* pcCU=rTu.getCU();const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();const TComRectangle &rect = rTu.getRect(compID);const UInt uiWidth = rect.width;const UInt uiHeight = rect.height;
// 对于非正方形的 TU,需要进一步递归分割处理
if (uiWidth != uiHeight) //for intra, the TU will have been split above this level, so this condition won't be true, hence this only affects inter {TComTURecurse subTURecurse(rTu, false, TComTU::VERTICAL_SPLIT, true, compID);do{const UInt lineOffset = subTURecurse.GetSectionNumber() * subTURecurse.getRect(compID).height;Pel *subTUResidual = pcResidual + (lineOffset * uiStride);TCoeff *subTUCoefficients = pcCoeff + (lineOffset * subTURecurse.getRect(compID).width);invTransformNxN(subTURecurse, compID, subTUResidual, uiStride, subTUCoefficients, cQP DEBUG_STRING_PASS_INTO(psDebug)); } while (subTURecurse.nextSection(rTu));return;}#if DEBUG_STRINGif (psDebug){std::stringstream ss(stringstream::out);printBlockToStream(ss, (compID==0)?"###InvTran ip Ch0: " : ((compID==1)?"###InvTran ip Ch1: ":"###InvTran ip Ch2: "), pcCoeff, uiWidth, uiHeight, uiWidth);DEBUG_STRING_APPEND((*psDebug), ss.str())} #endif

// 如果开启了旁路模式,直接将系数复制为残差if(pcCU->getCUTransquantBypass(uiAbsPartIdx)){const Bool rotateResidual = rTu.isNonTransformedResidualRotated(compID);const UInt uiSizeMinus1 = (uiWidth * uiHeight) - 1;for (UInt y = 0, coefficientIndex = 0; y<uiHeight; y++){for (UInt x = 0; x<uiWidth; x++, coefficientIndex++){pcResidual[(y * uiStride) + x] = Pel(pcCoeff[rotateResidual ? (uiSizeMinus1 - coefficientIndex) : coefficientIndex]);}}}else{ #if DEBUG_TRANSFORM_AND_QUANTISEstd::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU at input to dequantiser\n";printBlock(pcCoeff, uiWidth, uiHeight, uiWidth); #endif
// xDeQuant 对变换系数进行反量化,结果存储在 m_plTempCoeff 中。xDeQuant(rTu, pcCoeff, m_plTempCoeff, compID, cQP);
#if DEBUG_TRANSFORM_AND_QUANTISEstd::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU between dequantiser and inverse-transform\n";printBlock(m_plTempCoeff, uiWidth, uiHeight, uiWidth); #endif#if DEBUG_STRINGif (psDebug){std::stringstream ss(stringstream::out);printBlockToStream(ss, "###InvTran deq: ", m_plTempCoeff, uiWidth, uiHeight, uiWidth);(*psDebug)+=ss.str();} #endif // 是否使用了变换跳过(Transform Skip)模式if(pcCU->getTransformSkip(uiAbsPartIdx, compID)){xITransformSkip( m_plTempCoeff, pcResidual, uiStride, rTu, compID );#if DEBUG_STRINGif (psDebug){std::stringstream ss(stringstream::out);printBlockToStream(ss, "###InvTran resi: ", pcResidual, uiWidth, uiHeight, uiStride);(*psDebug)+=ss.str();(*psDebug)+="(<- was a Transform-skipped block)\n";} #endif}else{ #if O0043_BEST_EFFORT_DECODINGconst Int channelBitDepth = pcCU->getSlice()->getSPS()->getStreamBitDepth(toChannelType(compID)); #elseconst Int channelBitDepth = pcCU->getSlice()->getSPS()->getBitDepth(toChannelType(compID)); #endif

 // 调用 xIT 执行逆变换

      xIT( channelBitDepth, rTu.useDST(compID), m_plTempCoeff, pcResidual, uiStride, uiWidth, uiHeight, pcCU->getSlice()->getSPS()->getMaxLog2TrDynamicRange(toChannelType(compID)) );#if DEBUG_STRINGif (psDebug){std::stringstream ss(stringstream::out);printBlockToStream(ss, "###InvTran resi: ", pcResidual, uiWidth, uiHeight, uiStride);(*psDebug)+=ss.str();(*psDebug)+="(<- was a Transformed block)\n";}
#endif}#if DEBUG_TRANSFORM_AND_QUANTISEstd::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU at output of inverse-transform\n";printBlock(pcResidual, uiWidth, uiHeight, uiStride);g_debugCounter++;
#endif}invRdpcmNxN( rTu, compID, pcResidual, uiStride );
}

(3)量化

(4)xIT 用于执行二维逆变换

Void TComTrQuant::xIT( const Int channelBitDepth, Bool useDST, TCoeff* plCoef, Pel* pResidual, UInt uiStride, Int iWidth, Int iHeight, const Int maxLog2TrDynamicRange )
{
#if MATRIX_MULTif( iWidth == iHeight ){
// 对于方形矩阵,使用高效的 NxN 逆变换函数(默认关闭)xITr(channelBitDepth, plCoef, pResidual, uiStride, (UInt)iWidth, useDST, maxLog2TrDynamicRange);
return;} #endifTCoeff block[ MAX_TU_SIZE * MAX_TU_SIZE ];TCoeff coeff[ MAX_TU_SIZE * MAX_TU_SIZE ];memcpy(coeff, plCoef, (iWidth * iHeight * sizeof(TCoeff))); // 对于非方形块,调用 xITrMxN 函数,处理 MxN 的逆变换。xITrMxN( channelBitDepth, coeff, block, iWidth, iHeight, useDST, maxLog2TrDynamicRange );for (Int y = 0; y < iHeight; y++){for (Int x = 0; x < iWidth; x++){pResidual[(y * uiStride) + x] = Pel(block[(y * iWidth) + x]);}} }

(5)xITrMxN 实现 MxN 矩阵的二维逆变换。主要根据输入矩阵的宽度 (iWidth) 和高度 (iHeight),应用逆变换算法(如部分蝶形逆变换、DST)

注意函数中的:

 Int shift_1st = TRANSFORM_MATRIX_SHIFT + 1; //1 has been added to shift_1st at the expense of shift_2ndInt shift_2nd = (TRANSFORM_MATRIX_SHIFT + maxLog2TrDynamicRange - 1) - bitDepth;
在 HEVC 中需要进行六次会导致计算结果数量级增大的操作,分别为 2 次 DCT(一次二维 DCT 可以被分为两次一维 DCT)、1 次量化、1 次反量化以及 2 次反 DCT。
在 HEVC 中同样设置了六次对应位置的 Scaling 操作,其 Scaling 系数分别为 ST1,ST2,SQ,SIQ,SIT1,SIT2。
这里的shift_1st,shift_2nd 分别对应 SIT1,SIT2。TRANSFORM_MATRIX_SHIFT默认为6。
  • STI=2−(B+M−9)
  • ST2=2−(M+6)
  • SQ=2−(29−M−B)
  • SIT1=2−7
  • SIT2=2−(20−B)
  • SIQ=2−(M−5+B)
Void xITrMxN(Int bitDepth, TCoeff *coeff, TCoeff *block, Int iWidth, Int iHeight, Bool useDST, const Int maxLog2TrDynamicRange)
{const Int TRANSFORM_MATRIX_SHIFT = g_transformMatrixShift[TRANSFORM_INVERSE];Int shift_1st = TRANSFORM_MATRIX_SHIFT + 1; //1 has been added to shift_1st at the expense of shift_2ndInt shift_2nd = (TRANSFORM_MATRIX_SHIFT + maxLog2TrDynamicRange - 1) - bitDepth;const TCoeff clipMinimum = -(1 << maxLog2TrDynamicRange);const TCoeff clipMaximum =  (1 << maxLog2TrDynamicRange) - 1;assert(shift_1st >= 0);assert(shift_2nd >= 0);TCoeff tmp[MAX_TU_SIZE * MAX_TU_SIZE];switch (iHeight){case 4:{if ((iWidth == 4) && useDST)    // Check for DCT or DST
        {fastInverseDst( coeff, tmp, shift_1st, clipMinimum, clipMaximum);}else{partialButterflyInverse4 ( coeff, tmp, shift_1st, iWidth, clipMinimum, clipMaximum);}}break;case  8: partialButterflyInverse8 ( coeff, tmp, shift_1st, iWidth, clipMinimum, clipMaximum); break;case 16: partialButterflyInverse16( coeff, tmp, shift_1st, iWidth, clipMinimum, clipMaximum); break;case 32: partialButterflyInverse32( coeff, tmp, shift_1st, iWidth, clipMinimum, clipMaximum); break;default:assert(0); exit (1); break;}switch (iWidth){// Clipping here is not in the standard, but is used to protect the "Pel" data type into which the inverse-transformed samples will be copiedcase 4:{if ((iHeight == 4) && useDST)    // Check for DCT or DST
        {fastInverseDst( tmp, block, shift_2nd, std::numeric_limits<Pel>::min(), std::numeric_limits<Pel>::max() );}else{partialButterflyInverse4 ( tmp, block, shift_2nd, iHeight, std::numeric_limits<Pel>::min(), std::numeric_limits<Pel>::max());}}break;case  8: partialButterflyInverse8 ( tmp, block, shift_2nd, iHeight, std::numeric_limits<Pel>::min(), std::numeric_limits<Pel>::max()); break;case 16: partialButterflyInverse16( tmp, block, shift_2nd, iHeight, std::numeric_limits<Pel>::min(), std::numeric_limits<Pel>::max()); break;case 32: partialButterflyInverse32( tmp, block, shift_2nd, iHeight, std::numeric_limits<Pel>::min(), std::numeric_limits<Pel>::max()); break;default:assert(0); exit (1); break;}
}

再看看对应的变换函数:

其中g_aucConvertToBit[iHeight]函数:from width to log2(width)-2

Void xTrMxN(Int bitDepth, TCoeff *block, TCoeff *coeff, Int iWidth, Int iHeight, Bool useDST, const Int maxLog2TrDynamicRange)
{const Int TRANSFORM_MATRIX_SHIFT = g_transformMatrixShift[TRANSFORM_FORWARD];const Int shift_1st = ((g_aucConvertToBit[iWidth] + 2) +  bitDepth + TRANSFORM_MATRIX_SHIFT) - maxLog2TrDynamicRange;const Int shift_2nd = (g_aucConvertToBit[iHeight] + 2) + TRANSFORM_MATRIX_SHIFT;assert(shift_1st >= 0);assert(shift_2nd >= 0);TCoeff tmp[ MAX_TU_SIZE * MAX_TU_SIZE ];switch (iWidth){case 4:{if ((iHeight == 4) && useDST)    // Check for DCT or DST
        {fastForwardDst( block, tmp, shift_1st );}else{partialButterfly4 ( block, tmp, shift_1st, iHeight );}}break;case 8:     partialButterfly8 ( block, tmp, shift_1st, iHeight );  break;case 16:    partialButterfly16( block, tmp, shift_1st, iHeight );  break;case 32:    partialButterfly32( block, tmp, shift_1st, iHeight );  break;default:assert(0); exit (1); break;}switch (iHeight){case 4:{if ((iWidth == 4) && useDST)    // Check for DCT or DST
        {fastForwardDst( tmp, coeff, shift_2nd );}else{partialButterfly4 ( tmp, coeff, shift_2nd, iWidth );}}break;case 8:     partialButterfly8 ( tmp, coeff, shift_2nd, iWidth );    break;case 16:    partialButterfly16( tmp, coeff, shift_2nd, iWidth );    break;case 32:    partialButterfly32( tmp, coeff, shift_2nd, iWidth );    break;default:assert(0); exit (1); break;}
}

 

(6)对于4*4使用DST变换的块:

Void fastInverseDst(TCoeff *tmp, TCoeff *block, Int shift, const TCoeff outputMinimum, const TCoeff outputMaximum)  // input tmp, output block
{Int i;TCoeff c[4];TCoeff rnd_factor = (shift > 0) ? (1<<(shift-1)) : 0;for (i=0; i<4; i++){// Intermediate Variablesc[0] = tmp[   i];c[1] = tmp[4 +i];c[2] = tmp[8 +i];c[3] = tmp[12+i];for (Int column = 0; column < 4; column++){TCoeff &result = block[(i * 4) + column];result = 0;for (Int row = 0; row < 4; row++){result += c[row] * g_as_DST_MAT_4[TRANSFORM_INVERSE][row][column]; // use the defined matrix, rather than hard-wired numbers
      }result = Clip3( outputMinimum, outputMaximum, rightShift((result + rnd_factor), shift));}}
}

 

SIT1,SIT2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/808452.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

织梦php数据库配置文件

织梦CMS(DedeCMS)的数据库配置文件通常位于安装目录下的 include 文件夹中,具体文件名为 config.inc.php。这个文件包含了数据库连接的所有必要信息。下面详细说明如何配置这个文件。 步骤 1: 备份现有配置文件 在修改任何配置文件之前,最好先备份现有的配置文件,以防万一…

连接到数据库,你可以查看织梦CMS的相关表结构和数据

一旦连接到数据库,你可以查看织梦CMS的相关表结构和数据。 使用phpMyAdmin查看数据库表在phpMyAdmin中,选择你的织梦CMS数据库。 点击左侧的数据库名称,可以看到所有的表列表。 点击每个表,可以查看表结构和数据。使用MySQL命令行查看数据库表进入数据库后,运行以下命令查…

【嘉立创】SMT过程PCB载具和夹具有什么用?

SMT焊接时为什么会用到“载具、夹具” 2022-04-13 17:37 31437 4SMT焊接时为什么会用到“载具、夹具”一、 载具与夹具的使用场景载具: 主要是在印刷及贴片机贴装时,辅助生产使用。0.8mm以上的如拼板不合理会断板也需要使用。使用场景 1.PCB板薄: PCB板厚在0.4mm、 0.6mm、…

找到织梦CMS的数据库配置文件,以便了解数据库的具体连接信息

首先,找到织梦CMS的数据库配置文件,以便了解数据库的具体连接信息。 数据库配置文件路径织梦CMS安装目录假设织梦CMS安装在 /var/www/html 目录下。 数据库配置文件位于 include/config.inc.php。打开配置文件使用FTP工具或服务器上的文件管理器,打开织梦CMS安装目录下的 in…

织梦的数据库在哪,告诉我路径

织梦CMS(DedeCMS)的数据库并不是直接存储在文件系统中的某个特定路径下,而是存储在MySQL数据库服务器中。不过,织梦CMS的数据库配置文件和一些相关文件还是有固定的路径。以下是一些关键路径及其说明: 织梦CMS安装目录 假设你的织梦CMS安装在 /var/www/html 目录下,那么以…

vs code如何配置C/C++环境,实现完美运行.c/.cpp文件,以及终端乱码问题

环境配置 在 Visual Studio Code (VS Code) 中安装了 C/C++ Extension Pack 后,你可以通过以下步骤来运行 C++ 文件:安装编译器配置编译任务:在 VS Code 中,你可以创建一个编译任务来编译你的 C++ 文件。这通常通过创建一个 tasks.json 文件来完成。你可以通过以下步骤创建…

blender拖动视角到一定程度很慢

配置 win11 - blender3.6点击 编辑 - 偏好设置视图切换 - 旋转&平移 - 自动 - 深度(勾选)后期可根据需要进行勾选和取消勾选

查看织梦CMS源码中的数据库相关文件

如果你想查看织梦CMS源码中的数据库相关文件,可以参考以下路径:织梦CMS安装目录/var/www/html 这里包含织梦CMS的所有文件。核心文件/var/www/html/inc 包含一些核心配置文件。 /var/www/html/include 包含数据库配置文件 config.inc.php 和其他核心文件。数据库表前缀默认表…

uv --- replacement of conda + pip (python version + package version install) python版本和包管理集大成者

uv https://docs.astral.sh/uv/An extremely fast Python package and project manager, written in Rust. Installing Trios dependencies with a warm cache. Highlights🚀 A single tool to replace pip, pip-tools, pipx, poetry, pyenv, virtualenv, and more. ⚡️ 10…

织梦怎么进数据库,织梦网站源码在哪里看数据库

假设你的织梦CMS安装在 /var/www/html 目录下,且数据库配置如下:织梦CMS安装目录:/var/www/html数据库配置文件:/var/www/html/include/config.inc.php数据库配置:$cfg_dbhost = localhost; $cfg_dbname = mydatabase; $cfg_dbuser = myusername; $cfg_dbpw = mypassword;…

blender贴图丢失,贴图显示紫色

闲言 一般在模型复制粘贴或转移过程中, 发生贴图加载失败, 导致模型贴图位置显示紫色. 如果是上述相关情况, 那么本文章应能为你提供相关帮助. 本人配置: win11 - blender3.6(本案例演示版本) - blender4.2 打开丢失材质模型(.blend).fbx导入也是一样的, 这里不赘述.打开材质预…

R3CTF2024 WP

一、PWN1.Nullullullllu在直接给 libc_base 的情况下,一次任意地址写 \x00 。直接修改 IO_2_1_stdin 的 _IO_buf_base 末尾为 \x00 ,那么 _IO_buf_base 就会指向 IO_2_1_stdin 的 _IO_write_base,接下来就是利用 getchar 函数触发写操作修改 IO_buf_base 为 IO_2_1_stdout ,…