帧内预测——initAdiPattern

近期开始接触HEVC,看了一些综述性的文章后开始看平台,可总感觉效果不佳,所以打算把每天看的东西都写一下,巩固巩固。首先是讲一下initAdiPattern这个函数,在看了hevc_cjl的博客:  http://blog.csdn.net/hevc_cjl/article/details/8184276?reload 之后,受益良多。

首先分析下这个函数的用途:这个函数位于帧内预测的亮度预测estIntraPredQT中,主要是用于初始化帧内模式。

细化其功能:(1)检测当前的PU相邻点的可用性(2)参考样点的替换 (3)参考样点的平滑滤波

通过下面这幅图能很好地理解代码的信息。如:

 // ----- 先进行样点值拷贝  
  Int l = 0;  
  // left border from bottom to top【左下->左上,滤波前参考样点值拷贝】  
  for (i = 0; i < uiCuHeight2; i++)  
  {  
    piFilterBuf[l++] = piAdiTemp[uiWidth * (uiCuHeight2 - i)];  
  }  
  // top left corner  
  piFilterBuf[l++] = piAdiTemp[0]; //【左上角点, 拷贝】  
  // above border from left to right  
  for (i=0; i < uiCuWidth2; i++)  // 【上->右上, 拷贝】  
  {  
    piFilterBuf[l++] = piAdiTemp[1 + i];  //l此时初始为uiCuHeight2+1

  }  
以上代码为样本点信息拷贝过程,拷贝的过程是自左下而上,过AboveLeft而向右的过程


Void TComPattern::initAdiPattern( TComDataCU* pcCU, UInt uiZorderIdxInPart, UInt uiPartDepth, Int* piAdiBuf, Int iOrgBufStride, Int iOrgBufHeight, Bool& bAbove, Bool& bLeft, Bool bLMmode )  
{  
  Pel*  piRoiOrigin;//piRoiOrgin指向重建Yuv图像对应于当前PU所在位置的首地址  
  Int*  piAdiTemp;  //  
  UInt  uiCuWidth   = pcCU->getWidth(0) >> uiPartDepth; //CU宽  
  UInt  uiCuHeight  = pcCU->getHeight(0)>> uiPartDepth; //CU高  
  UInt  uiCuWidth2  = uiCuWidth<<1;//  uiCuWidth*2
  UInt  uiCuHeight2 = uiCuHeight<<1;  
  UInt  uiWidth;  
  UInt  uiHeight;  
  Int   iPicStride = pcCU->getPic()->getStride(); //图像跨度(原图像宽度 + 两边扩充的参考像素点) 
  
  Int   iUnitSize = 0;    
  Int   iNumUnitsInCu = 0;    
  Int   iTotalUnits = 0;  
  
  Bool  bNeighborFlags[4 * MAX_NUM_SPU_W + 1]; //!< 用于存放4个方向上的相邻样点值的【可用性】,4*32+1  
  Int   iNumIntraNeighbor = 0;                 !< 给可用邻块进行计数    
    
  UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;  
  
  ! 获取当前PU左上角LT,右上角RT以及左下角LB 以4x4块为单位的Z-order(Zscan)  
  pcCU->deriveLeftRightTopIdxAdi( uiPartIdxLT, uiPartIdxRT, uiZorderIdxInPart, uiPartDepth );  
  
  pcCU->deriveLeftBottomIdxAdi  ( uiPartIdxLB,              uiZorderIdxInPart, uiPartDepth );  
    
  iUnitSize      = g_uiMaxCUWidth >> g_uiMaxCUDepth;  // 4   
  iNumUnitsInCu  = uiCuWidth / iUnitSize;    // 当前CU的宽/4  = 宽方向上,iUnitSize的个数  
  iTotalUnits    = (iNumUnitsInCu << 2) + 1; //(iNumUnitsInCu*4) + 1    
     
  // (扫描顺序是从左下到左上,再从左上到右上)   
  bNeighborFlags[iNumUnitsInCu*2] = isAboveLeftAvailable( pcCU, uiPartIdxLT );  
  iNumIntraNeighbor  += (Int)(bNeighborFlags[iNumUnitsInCu*2]);  
  iNumIntraNeighbor  += isAboveAvailable     ( pcCU, uiPartIdxLT, uiPartIdxRT, bNeighborFlags+(iNumUnitsInCu*2)+1 );  
  iNumIntraNeighbor  += isAboveRightAvailable( pcCU, uiPartIdxLT, uiPartIdxRT, bNeighborFlags+(iNumUnitsInCu*3)+1 );  
  iNumIntraNeighbor  += isLeftAvailable      ( pcCU, uiPartIdxLT, uiPartIdxLB, bNeighborFlags+(iNumUnitsInCu*2)-1 );  
  iNumIntraNeighbor  += isBelowLeftAvailable ( pcCU, uiPartIdxLT, uiPartIdxLB, bNeighborFlags+ iNumUnitsInCu   -1 );  
    
  bAbove = true;  //之前定义为FALSE
  bLeft  = true;  //同上
  
  uiWidth=uiCuWidth2+1;  
  uiHeight=uiCuHeight2+1;  
    
  if (((uiWidth<<2)>iOrgBufStride)||((uiHeight<<2)>iOrgBufHeight))  //判定范围
  {  
    return;  
  }  
   //! piRoiOrigin指向当前PU左上角  
  piRoiOrigin = pcCU->getPic()->getPicYuvRec()->getLumaAddr( pcCU->getAddr(), pcCU->getZorderIdxInCU()+uiZorderIdxInPart );  
  piAdiTemp   = piAdiBuf;  
    
  // 参考样点的替换(填补)过程  
  fillReferenceSamples (g_bitDepthY, piRoiOrigin, piAdiTemp, bNeighborFlags, iNumIntraNeighbor, iUnitSize, iNumUnitsInCu, iTotalUnits, uiCuWidth, uiCuHeight, uiWidth, uiHeight, iPicStride, bLMmode);
// ****************************************************  
  //! 下面所进行的工作主要是对参考样点进行3抽头的滤波。  
  //    piAdiBuf指向滤波前的参考样点的首地址,在滤波前,先将所有参考样点拷贝到piFilterBuf指向的区域,  
  //! 经滤波后的样点值保存在piFilterBufN指向的区域,最终将滤波后的样点值拷贝到piFilterBuf1。  
  
  //  值得一提的是,最终的结果是,piAdiBuf指向的区域是未经滤波的样点值,而piFilterBuf1指向的区域是经过  
  //! 滤波的样点值,两者的地址相差uiWH = uiWidth * uiHeight = (uiCuWidth2 + 1) * (uiCuHeight2 + 1),这就解释了在进行   
  //! 真正的帧内预测时,在需要滤波时,指向piAdiBuf的指针需要加上uiWH的偏移量。  
  Int   i;  
  // generate filtered intra prediction samples  
  Int iBufSize = uiCuHeight2 + uiCuWidth2 + 1;  //结合图中信息比较
  
  UInt uiWH = uiWidth * uiHeight;               // number of elements in one buffer  
  
  Int* piFilteredBuf1 = piAdiBuf + uiWH;        // 1. filter buffer  
  Int* piFilteredBuf2 = piFilteredBuf1 + uiWH;  // 2. filter buffer  
  Int* piFilterBuf = piFilteredBuf2 + uiWH;     // buffer for 2. filtering (sequential)  
  
  //piFilterBufN 存放的是参考样点经3抽头滤波后的值  
  Int* piFilterBufN = piFilterBuf + iBufSize;   // buffer for 1. filtering (sequential)  
  
  
  
  // ----- 先进行样点值拷贝  
  Int l = 0;  
  // left border from bottom to top【左下->左上,滤波前参考样点值拷贝】  
  for (i = 0; i < uiCuHeight2; i++)  
  {  
    piFilterBuf[l++] = piAdiTemp[uiWidth * (uiCuHeight2 - i)];  
  }  
  // top left corner  
  piFilterBuf[l++] = piAdiTemp[0]; //【左上角点, 拷贝】  
  // above border from left to right  
  for (i=0; i < uiCuWidth2; i++)  // 【上->右上, 拷贝】  
  {  
    piFilterBuf[l++] = piAdiTemp[1 + i];  
  }  
  
  
 //对32*32的块进行 StrongIntraSmoothing
 if (pcCU->getSlice()->getSPS()->getUseStrongIntraSmoothing()) //cfg里面设置  
  {  
    Int blkSize = 32;  
    Int bottomLeft = piFilterBuf[0];  
    Int topLeft = piFilterBuf[uiCuHeight2];  
    Int topRight = piFilterBuf[iBufSize-1];  
    Int threshold = 1 << (g_bitDepthY - 5);//8  
    Bool bilinearLeft = abs(bottomLeft+topLeft-2*piFilterBuf[uiCuHeight]) < threshold;  
    Bool bilinearAbove  = abs(topLeft+topRight-2*piFilterBuf[uiCuHeight2+uiCuHeight]) < threshold;  
    
    if (uiCuWidth>=blkSize && (bilinearLeft && bilinearAbove))  
    {  
      Int shift = g_aucConvertToBit[uiCuWidth] + 3;  // log2(uiCuHeight2) =7 
      piFilterBufN[0] = piFilterBuf[0];  
      piFilterBufN[uiCuHeight2] = piFilterBuf[uiCuHeight2];  
      piFilterBufN[iBufSize - 1] = piFilterBuf[iBufSize - 1];  
      for (i = 1; i < uiCuHeight2; i++)  
      {  
        piFilterBufN[i] = ((uiCuHeight2-i)*bottomLeft + i*topLeft + uiCuHeight) >> shift;  
      }  
    
      for (i = 1; i < uiCuWidth2; i++)  
      {  
        piFilterBufN[uiCuHeight2 + i] = ((uiCuWidth2-i)*topLeft + i*topRight + uiCuWidth) >> shift;  
      }  
    }  
    else   
    {  
      // 1. filtering with [1 2 1]  
      piFilterBufN[0] = piFilterBuf[0];  
      piFilterBufN[iBufSize - 1] = piFilterBuf[iBufSize - 1];  
      for (i = 1; i < iBufSize - 1; i++)  
      {  
        piFilterBufN[i] = (piFilterBuf[i - 1] + 2 * piFilterBuf[i]+piFilterBuf[i + 1] + 2) >> 2; // 最后 +2是为了四舍五入取整  
      }  
    }  
  }  
  else   
  {  
    // 1. filtering with [1 2 1]   
    piFilterBufN[0] = piFilterBuf[0];  
    piFilterBufN[iBufSize - 1] = piFilterBuf[iBufSize - 1];  
  
    for (i = 1; i < iBufSize - 1; i++)  
    {  
      piFilterBufN[i] = (piFilterBuf[i - 1] + 2 * piFilterBuf[i]+piFilterBuf[i + 1] + 2) >> 2;  
    }  
  }  
  
  // fill 1. filter buffer with filtered values  
  l=0;  
  for (i = 0; i < uiCuHeight2; i++)  
  {  
    piFilteredBuf1[uiWidth * (uiCuHeight2 - i)] = piFilterBufN[l++];  
  }  
  piFilteredBuf1[0] = piFilterBufN[l++];  
  for (i = 0; i < uiCuWidth2; i++)  
  {  
    piFilteredBuf1[1 + i] = piFilterBufN[l++];  
  }  
}



 
 





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值