HEVC学习(五) —— 帧内预测系列之三

由于研究的需要,现将一晨不变大神的关于HEVC帧内预测的相关博客进行转载,方便自己查阅。一直都看一晨不变大神的帖子,受益匪浅。原著博客地址:http://blog.csdn.net/HEVC_CJL/article/list/1


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

  1. Void TComPattern::initAdiPattern( TComDataCU* pcCU, UInt uiZorderIdxInPart, UInt uiPartDepth, Int* piAdiBuf, Int iOrgBufStride, Int iOrgBufHeight, Bool& bAbove, Bool& bLeft, Bool bLMmode )  
  2. {//! bLMmode is usually false   
  3.   Pel*  piRoiOrigin;  
  4.   Int*  piAdiTemp;  
  5.   UInt  uiCuWidth   = pcCU->getWidth(0) >> uiPartDepth; //!< CU的宽度  
  6.   UInt  uiCuHeight  = pcCU->getHeight(0)>> uiPartDepth; //!< CU的高度  
  7.   UInt  uiCuWidth2  = uiCuWidth<<1;  
  8.   UInt  uiCuHeight2 = uiCuHeight<<1;  
  9.   UInt  uiWidth;  
  10.   UInt  uiHeight;  
  11.   Int   iPicStride = pcCU->getPic()->getStride();  
  12.   Int   iUnitSize = 0;  
  13.   Int   iNumUnitsInCu = 0;  
  14.   Int   iTotalUnits = 0;  
  15.   Bool  bNeighborFlags[4 * MAX_NUM_SPU_W + 1];  //!< 用于存放4个方向上的相邻样点值的可用性, 4 x 32 + 1  
  16.   Int   iNumIntraNeighbor = 0; //!< 给可用邻块进行计数  
  17.     
  18.   UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;  
  19.   
  20.   //! 获取当前PU左上角LT,右上角RT以及左下角LB 以4x4块为单位的Zorder  
  21.   pcCU->deriveLeftRightTopIdxAdi( uiPartIdxLT, uiPartIdxRT, uiZorderIdxInPart, uiPartDepth );  
  22.   pcCU->deriveLeftBottomIdxAdi  ( uiPartIdxLB,              uiZorderIdxInPart, uiPartDepth );  
  23.     
  24.   iUnitSize      = g_uiMaxCUWidth >> g_uiMaxCUDepth;  
  25.   iNumUnitsInCu  = uiCuWidth / iUnitSize;  
  26.   iTotalUnits    = (iNumUnitsInCu << 2) + 1; // Top + RightTop + Left + LeftBottom + LeftTop = iNumUnitsInCu + iNumUnitsInCu + iNumUnitsInCu + iNumUnitsInCu + 1  
  27.   //! 扫描顺序是从左下到左上,再从左上到右上  
  28.   bNeighborFlags[iNumUnitsInCu*2] = isAboveLeftAvailable( pcCU, uiPartIdxLT );  
  29.   iNumIntraNeighbor  += (Int)(bNeighborFlags[iNumUnitsInCu*2]);  
  30.   iNumIntraNeighbor  += isAboveAvailable     ( pcCU, uiPartIdxLT, uiPartIdxRT, bNeighborFlags+(iNumUnitsInCu*2)+1 );  
  31.   iNumIntraNeighbor  += isAboveRightAvailable( pcCU, uiPartIdxLT, uiPartIdxRT, bNeighborFlags+(iNumUnitsInCu*3)+1 );  
  32.   iNumIntraNeighbor  += isLeftAvailable      ( pcCU, uiPartIdxLT, uiPartIdxLB, bNeighborFlags+(iNumUnitsInCu*2)-1 );  
  33.   iNumIntraNeighbor  += isBelowLeftAvailable ( pcCU, uiPartIdxLT, uiPartIdxLB, bNeighborFlags+ iNumUnitsInCu   -1 );  
  34.     
  35.   bAbove = true;  
  36.   bLeft  = true;  
  37.   
  38.   uiWidth=uiCuWidth2+1;  
  39.   uiHeight=uiCuHeight2+1;  
  40.     
  41.   if (((uiWidth<<2)>iOrgBufStride)||((uiHeight<<2)>iOrgBufHeight))  
  42.   {  
  43.     return;  
  44.   }  
  45.   //! piRoiOrigin指向当前PU左上角  
  46.   piRoiOrigin = pcCU->getPic()->getPicYuvRec()->getLumaAddr(pcCU->getAddr(), pcCU->getZorderIdxInCU()+uiZorderIdxInPart);  
  47.   piAdiTemp   = piAdiBuf;  
  48.   
  49.   fillReferenceSamples ( pcCU, piRoiOrigin, piAdiTemp, bNeighborFlags, iNumIntraNeighbor, iUnitSize, iNumUnitsInCu, iTotalUnits, uiCuWidth, uiCuHeight, uiWidth, uiHeight, iPicStride, bLMmode);  
  50.     
  51.   Int   i;  
  52.   // generate filtered intra prediction samples  
  53.   Int iBufSize = uiCuHeight2 + uiCuWidth2 + 1;  // left and left above border + above and above right border + top left corner = length of 3. filter buffer  
  54.   
  55.   UInt uiWH = uiWidth * uiHeight;               // number of elements in one buffer  
  56.   
  57.   //! 下面所进行的工作主要是对参考样点进行3抽头的滤波。piAdiBuf指向滤波前的参考样点的首地址,在滤波前,先将所有参考样点  
  58.   //! 拷贝到piFilterBuf指向的区域,经滤波后的样点值保存在piFilterBufN指向的区域,最终将滤波后的样点值拷贝到piFilterBuf1  
  59.   //! 值得一提的是,最终的结果是,piAdiBuf指向的区域是未经滤波的样点值,而piFilterBuf1指向的区域是经过滤波的样点值,  
  60.   //! 两者的地址相差uiWH = uiWidth * uiHeight = (uiCuWidth2 + 1) * (uiCuHeight2 + 1),这就解释了在进行真正的帧内预测时,  
  61.   //! 在需要滤波时,指向piAdiBuf的指针需要加上uiWH的偏移量  
  62.   Int* piFilteredBuf1 = piAdiBuf + uiWH;        // 1. filter buffer  
  63.   Int* piFilteredBuf2 = piFilteredBuf1 + uiWH;  // 2. filter buffer  
  64.   Int* piFilterBuf = piFilteredBuf2 + uiWH;     // buffer for 2. filtering (sequential)  
  65.   Int* piFilterBufN = piFilterBuf + iBufSize;   // buffer for 1. filtering (sequential) //!<存放的是参考样点经3抽头滤波后的值  
  66.   
  67.   // draft 8.4.4.2.3 Filtering process of neighbouring samples  
  68.   Int l = 0;  
  69.   // left border from bottom to top  
  70.   for (i = 0; i < uiCuHeight2; i++)  
  71.   {  
  72.     piFilterBuf[l++] = piAdiTemp[uiWidth * (uiCuHeight2 - i)]; //!< 左边界,存储顺序为从下往上  
  73.   }  
  74.   // top left corner  
  75.   piFilterBuf[l++] = piAdiTemp[0];  //!< 左上边界  
  76.   // above border from left to right  
  77.   for (i=0; i < uiCuWidth2; i++)  
  78.   {  
  79.     piFilterBuf[l++] = piAdiTemp[1 + i];  //!<上边界,存储顺序为从左往右  
  80.   }  
  81.   
  82.   // 1. filtering with [1 2 1]  
  83.   piFilterBufN[0] = piFilterBuf[0]; //!< 第1个点直接保存,不滤波  
  84.   piFilterBufN[iBufSize - 1] = piFilterBuf[iBufSize - 1]; //!< 最后一个点也直接保存,不滤波  
  85.   for (i = 1; i < iBufSize - 1; i++) //!< 对中间样点值进行3抽头[1 2 1] / 4 的平滑滤波  
  86.   {  
  87.     piFilterBufN[i] = (piFilterBuf[i - 1] + 2 * piFilterBuf[i]+piFilterBuf[i + 1] + 2) >> 2;  
  88.   }  
  89.   
  90.   // fill 1. filter buffer with filtered values  
  91.   l=0;  
  92.   for (i = 0; i < uiCuHeight2; i++)  
  93.   {  
  94.     piFilteredBuf1[uiWidth * (uiCuHeight2 - i)] = piFilterBufN[l++];  // left border from bottom to top //!< 左边界  
  95.   }  
  96.   piFilteredBuf1[0] = piFilterBufN[l++]; //!< 左上边界  
  97.   for (i = 0; i < uiCuWidth2; i++)  
  98.   {  
  99.     piFilteredBuf1[1 + i] = piFilterBufN[l++]; // above border from left to right //!< 上边界  
  100.   }  
  101. }  
  102. <span style="BACKGROUND-COLOR: #ffffff"> </span>  

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值