HM模型学习(三)

来源:互联网 发布:网络女作家富豪行榜 编辑:程序博客网 时间:2024/06/11 00:09

原文出处:http://blog.csdn.net/hevc_cjl/article/details/8184276

今天主要介绍帧内预测一个很重要的函数initAdiPattern,它的主要功能有三个,(1)检测当前PU的相邻样点包括左上、上、右上、左、左下邻域样点值的可用性,或者说检查这些点是否存在;(2)参考样点的替换过程,主要实现的是JCTVC-J1003即draft 8.4.4.2.2的内容,主要由函数fillReferenceSamples来完成,这个在之前的文章已经讨论过了;(3)相邻样点即参考样点的平滑滤波,主要实现draft 8.4.4.2.3的内容。话不多说,下面给出initAdiPattern的实现和我个人的一些注释,供大家参考。


在HM16.9中,该部分函数被拆分成两个函数对应于工程中的:


其中主要是最下面的函数,上面的函数作用是给出是否滤波的布尔值,然后该值作为参数传入下面的函数中。

对应的HM16.9的解释如下,有些地方不能很好地理解。9.0可参考原文出处。

Void TComPrediction::initIntraPatternChType( TComTU &rTu, const ComponentID compID, const Bool bFilterRefSamples DEBUG_STRING_FN_DECLARE(sDebug)){  const ChannelType chType    = toChannelType(compID);  TComDataCU *pcCU=rTu.getCU();  const TComSPS &sps = *(pcCU->getSlice()->getSPS());  const UInt uiZorderIdxInPart=rTu.GetAbsPartIdxTU();  const UInt uiTuWidth        = rTu.getRect(compID).width;//!< CU的宽度  const UInt uiTuHeight       = rTu.getRect(compID).height;//!< CU的高度  const UInt uiTuWidth2       = uiTuWidth  << 1;  const UInt uiTuHeight2      = uiTuHeight << 1;  const Int  iBaseUnitSize    = sps.getMaxCUWidth() >> sps.getMaxTotalCUDepth();  const Int  iUnitWidth       = iBaseUnitSize  >> pcCU->getPic()->getPicYuvRec()->getComponentScaleX(compID);  const Int  iUnitHeight      = iBaseUnitSize  >> pcCU->getPic()->getPicYuvRec()->getComponentScaleY(compID);  const Int  iTUWidthInUnits  = uiTuWidth  / iUnitWidth;  const Int  iTUHeightInUnits = uiTuHeight / iUnitHeight;  const Int  iAboveUnits      = iTUWidthInUnits  << 1;//上方相邻unit个数  const Int  iLeftUnits       = iTUHeightInUnits << 1;//左方相邻unit个数  const Int  bitDepthForChannel = sps.getBitDepth(chType);  assert(iTUHeightInUnits > 0 && iTUWidthInUnits > 0);  //! 获取当前PU左上角LT,右上角RT以及左下角LB 以4x4块为单位的Zorder  const Int  iPartIdxStride   = pcCU->getPic()->getNumPartInCtuWidth();  const UInt uiPartIdxLT      = pcCU->getZorderIdxInCtu() + uiZorderIdxInPart;  const UInt uiPartIdxRT      = g_auiRasterToZscan[ g_auiZscanToRaster[ uiPartIdxLT ] +   iTUWidthInUnits  - 1                   ];  const UInt uiPartIdxLB      = g_auiRasterToZscan[ g_auiZscanToRaster[ uiPartIdxLT ] + ((iTUHeightInUnits - 1) * iPartIdxStride)];  Int   iPicStride = pcCU->getPic()->getStride(compID);  Bool  bNeighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1]; //!< 用于存放4个方向上的相邻样点值的可用性, 4 x 32 + 1  Int   iNumIntraNeighbor = 0; //!< 给可用邻块进行计数  //! 扫描顺序是从左下到左上,再从左上到右上  bNeighborFlags[iLeftUnits] = isAboveLeftAvailable( pcCU, uiPartIdxLT );//为每个邻块的可用性进行  iNumIntraNeighbor += bNeighborFlags[iLeftUnits] ? 1 : 0;//邻块可用则+1计数  iNumIntraNeighbor  += isAboveAvailable     ( pcCU, uiPartIdxLT, uiPartIdxRT, (bNeighborFlags + iLeftUnits + 1)                    );  iNumIntraNeighbor  += isAboveRightAvailable( pcCU, uiPartIdxLT, uiPartIdxRT, (bNeighborFlags + iLeftUnits + 1 + iTUWidthInUnits ) );  iNumIntraNeighbor  += isLeftAvailable      ( pcCU, uiPartIdxLT, uiPartIdxLB, (bNeighborFlags + iLeftUnits - 1)                    );  iNumIntraNeighbor  += isBelowLeftAvailable ( pcCU, uiPartIdxLT, uiPartIdxLB, (bNeighborFlags + iLeftUnits - 1 - iTUHeightInUnits) );  const UInt         uiROIWidth  = uiTuWidth2+1;  const UInt         uiROIHeight = uiTuHeight2+1;  // number of elements in one buffer  assert(uiROIWidth*uiROIHeight <= m_iYuvExtSize);//assert作用是如果它的条件返回错误,则终止程序执行#if DEBUG_STRING  std::stringstream ss(stringstream::out);#endif  {    Pel *piIntraTemp   = m_piYuvExt[compID][PRED_BUF_UNFILTERED];    Pel *piRoiOrigin = pcCU->getPic()->getPicYuvRec()->getAddr(compID, pcCU->getCtuRsAddr(), pcCU->getZorderIdxInCtu()+uiZorderIdxInPart); //! piRoiOrigin指向当前PU左上角 #if O0043_BEST_EFFORT_DECODING    const Int  bitDepthForChannelInStream = sps.getStreamBitDepth(chType);    fillReferenceSamples (bitDepthForChannelInStream, bitDepthForChannelInStream - bitDepthForChannel,#else    fillReferenceSamples (bitDepthForChannel,#endif                          piRoiOrigin, piIntraTemp, bNeighborFlags, iNumIntraNeighbor,  iUnitWidth, iUnitHeight, iAboveUnits, iLeftUnits,                          uiROIWidth, uiROIHeight, iPicStride);//填充参考样点#if DEBUG_STRING    if (DebugOptionList::DebugString_Pred.getInt()&DebugStringGetPredModeMask(MODE_INTRA))    {      ss << "###: generating Ref Samples for channel " << compID << " and " << rTu.getRect(compID).width << " x " << rTu.getRect(compID).height << "\n";      for (UInt y=0; y<uiROIHeight; y++)      {        ss << "###: - ";        for (UInt x=0; x<uiROIWidth; x++)        {          if (x==0 || y==0)          {            ss << piIntraTemp[y*uiROIWidth + x] << ", ";//          if (x%16==15) ss << "\nPart size: ~ ";          }        }        ss << "\n";      }    }#endif    if (bFilterRefSamples)//需要进行滤波处理    {      // generate filtered intra prediction samples            Int          stride    = uiROIWidth;      const Pel         *piSrcPtr  = piIntraTemp                           + (stride * uiTuHeight2); // bottom left            Pel         *piDestPtr = m_piYuvExt[compID][PRED_BUF_FILTERED] + (stride * uiTuHeight2); // bottom left      //------------------------------------------------      Bool useStrongIntraSmoothing = isLuma(chType) && sps.getUseStrongIntraSmoothing();      const Pel bottomLeft = piIntraTemp[stride * uiTuHeight2];      const Pel topLeft    = piIntraTemp[0];      const Pel topRight   = piIntraTemp[uiTuWidth2];//左下/左侧、左上、上侧/右上的 filter buffer      if (useStrongIntraSmoothing)      {#if O0043_BEST_EFFORT_DECODING        const Int  threshold     = 1 << (bitDepthForChannelInStream - 5);#else        const Int  threshold     = 1 << (bitDepthForChannel - 5);//强滤波阈值#endif        const Bool bilinearLeft  = abs((bottomLeft + topLeft ) - (2 * piIntraTemp[stride * uiTuHeight])) < threshold; //difference between the        const Bool bilinearAbove = abs((topLeft    + topRight) - (2 * piIntraTemp[         uiTuWidth ])) < threshold; //ends and the middle解释看参考书CA CE方向进行滤波        if ((uiTuWidth < 32) || (!bilinearLeft) || (!bilinearAbove))//只针对32*32,并且满足上述两个条件才需要进行强滤波        {          useStrongIntraSmoothing = false;        }      }  //顺序执行,从左下到右上进行滤波,需要对每个点判断是否需要进行强滤波,且第一个点即左下和最后一个点右上不需要进行滤波      *piDestPtr = *piSrcPtr; // bottom left is not filtered      piDestPtr -= stride;      piSrcPtr  -= stride;      //------------------------------------------------      //left column (bottom to top)      if (useStrongIntraSmoothing)      {        const Int shift = g_aucConvertToBit[uiTuHeight] + 3; //log2(uiTuHeight2)        for(UInt i=1; i<uiTuHeight2; i++, piDestPtr-=stride)        {          *piDestPtr = (((uiTuHeight2 - i) * bottomLeft) + (i * topLeft) + uiTuHeight) >> shift;        }        piSrcPtr -= stride * (uiTuHeight2 - 1);      }      else      {        for(UInt i=1; i<uiTuHeight2; i++, piDestPtr-=stride, piSrcPtr-=stride)        {          *piDestPtr = ( piSrcPtr[stride] + 2*piSrcPtr[0] + piSrcPtr[-stride] + 2 ) >> 2;//!< 对中间样点值进行3抽头[1 2 1] / 4 的平滑滤波        }      }      //------------------------------------------------      //top-left      if (useStrongIntraSmoothing)      {        *piDestPtr = piSrcPtr[0];      }      else      {        *piDestPtr = ( piSrcPtr[stride] + 2*piSrcPtr[0] + piSrcPtr[1] + 2 ) >> 2;      }      piDestPtr += 1;      piSrcPtr  += 1;      //------------------------------------------------      //top row (left-to-right)      if (useStrongIntraSmoothing)      {        const Int shift = g_aucConvertToBit[uiTuWidth] + 3; //log2(uiTuWidth2)        for(UInt i=1; i<uiTuWidth2; i++, piDestPtr++)        {          *piDestPtr = (((uiTuWidth2 - i) * topLeft) + (i * topRight) + uiTuWidth) >> shift;        }        piSrcPtr += uiTuWidth2 - 1;      }      else      {        for(UInt i=1; i<uiTuWidth2; i++, piDestPtr++, piSrcPtr++)        {          *piDestPtr = ( piSrcPtr[1] + 2*piSrcPtr[0] + piSrcPtr[-1] + 2 ) >> 2;        }      }      //------------------------------------------------      *piDestPtr=*piSrcPtr; // far right is not filtered

最后附上图,以帮助大家更好地理解代码,我就不对图多作解释了,相信大家对着代码能比较容易看明白的。

 (注,上图中,uiWidth和uiHeight实际上对应的是代码中的uiCUWidth和uiCUHeight,因画图的时候发生了遗漏,特此说明)


原创粉丝点击