首页 > 其他分享 >HM变化量化中的Scaling 操作(解码器)

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

时间:2024-10-05 13:21:59浏览次数:11  
标签:tmp const Int shift Scaling 解码器 HM iWidth iHeight

(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       &cQP
                                        DEBUG_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_STRING if (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_QUANTISE std::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_QUANTISE std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU between dequantiser and inverse-transform\n"; printBlock(m_plTempCoeff, uiWidth, uiHeight, uiWidth); #endif #if DEBUG_STRING if (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_STRING if (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_DECODING const Int channelBitDepth = pcCU->getSlice()->getSPS()->getStreamBitDepth(toChannelType(compID)); #else const 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_STRING
      if (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_QUANTISE
    std::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_MULT
  if( iWidth == iHeight )
  {
// 对于方形矩阵,使用高效的 NxN 逆变换函数(默认关闭) xITr(channelBitDepth, plCoef, pResidual, uiStride, (UInt)iWidth, useDST, maxLog2TrDynamicRange); return; } #endif TCoeff 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_2nd
 Int 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_2nd
  Int 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 copied
    case 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 Variables
    c[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

标签:tmp,const,Int,shift,Scaling,解码器,HM,iWidth,iHeight
From: https://www.cnblogs.com/jhzj/p/18447786

相关文章

  • 【THM】Res练习
    【THM】Res练习与本文相关的TryHackMe实验房间链接:TryHackMe|Res简介:在这个半引导式挑战中,使用内存中的数据结构入侵易受攻击的数据库服务器!你准备好接受挑战了吗?第一题:扫描机器,有多少端口是开放的?第一步端口扫描首先使用nmap对端口进行扫描nmap-sV-sC-p-10.10......
  • linux系统下修改文件夹目录权限-chmod
    很多人开始接触Linux时都很头痛Linux的文件权限问题。这里告诉大家如何修改Linux文件-文件夹权限。以主文件夹下的一个名为“cc”的文件夹为例。下面一步一步介绍如何修改权限:1.打开终端。输入su2.接下来会要你输入密码,输入你的root密码。3.假设我的文件夹在主目录里,地址为 ......
  • 【THM】Git Happens练习
    【THM】GitHappens练习与本文相关的TryHackMe实验房间链接:TryHackMe|GitHappens简介:老板让我创建一个原型代码,所以它就在这里!我们甚至使用了一种叫做“版本控制”的东西,使部署变得非常容易!你能找到应用程序的密码吗?第一题:找到超级机密的密码第一步端口扫描首先使......
  • Study Plan For Algorithms - Part48
    1.不同的二叉搜索树II给定一个整数n,请生成并返回所有由n个节点组成且节点值从1到n互不相同的不同二叉搜索树。classSolution:defgenerateTrees(self,n:int)->List[Optional[TreeNode]]:ifn==0:return[]returnself.g......
  • Study Plan For Algorithms - Part47
    1.复原IP地址有效IP地址正好由四个整数(每个整数位于0到255之间组成,且不能含有前导0),整数之间用'.'分隔。给定一个只包含数字的字符串s,用以表示一个IP地址,返回所有可能的有效IP地址,这些地址可以通过在s中插入'.'来形成。classSolution:defrestoreI......
  • HashMap原理
    HashMap原理在很多地方都会利用到hash表来提高查找效率。在Java的Object类中有一个方法:publicnativeinthashCode();```根据这个方法的声明可知,该方法返回一个int类型的数值,并且是本地方法,因此在Object类中并没有给出具体的实现。为何Object类需要这样一个方法?它......
  • ConcurrentHashMap是怎么实现的?
    1.是什么    ConcurrentHashMap 是Java并发包(java.util.concurrent)中的一个线程安全的哈希表实现。与 HashMap 相比,ConcurrentHashMap 在并发环境下具有更高的性能,因为它允许多个线程并发地进行读写操作而不会导致数据不一致。以下是 ConcurrentHashMap 实现的一......
  • CVEN9612 – Catchment Modelling
    CVEN9612–CatchmentModellingAssignment1Part1–Rainfall-RunoffModelingandRoutinghispartoftheassignmentisworth15%ofthetotalgradeforCVEN9612.TheassignmentanswersaretobesubmittedonlineinMoodleasashortreport.Assignment1......
  • UIOTOS前端组态跟中控等SCADA、HMI有什么区别?
    UIOTOS不是SCADA,不过可以拿去开发SCADA,在绘图、HMI、交互界面搭建能力上,是uiotos的强项,毕竟定位是一站式IoT应用无代码搭建工具。尤其是嵌套、继承、连线,基本上组态一样搭建,能做到代码定制开发的效果。这点跟一般的前端低代码组态大屏设计器还是有很大不一样。另外,SCADA一般跟协......
  • HashMap和ConcurrentHashMap的区别
    1.是什么    HashMap和ConcurrentHashMap都是Java集合框架中的成员,它们用于存储键值对,但它们在并发场景下的表现和行为有很大的不同。以下是它们之间的一些主要区别:1.并发安全性HashMap: HashMap不是线程安全的。如果多个线程同时访问HashMap,并且至少有一个线程在结......