HEVC帧内预测参考像素检测获取和滤波

12 篇文章 4 订阅
3 篇文章 4 订阅

作者:66

(转载请注明出处)

还是参考HEVC_CJL的博客,理论都清楚,跟着他的进度看代码,感谢前辈的分享,他的代码里没有强滤波过程,在此我稍加补充。

原文链接:http://blog.csdn.net/hevc_cjl/article/category/1283611

分析initAdiPattern函数,其中调用了之前的fillReferenceSample函数。

initAdiPattern实现的功能如下,1.先按4x4块从左下到右上检测每个块是否可用。2.调用fillReferenceSample填充参考样点。3.参考样点的滤波,分了常规滤波和强滤波。另外,HEVC_CJL博客中最后uiWidthuiHeigth标识错误了,经几次确认后,应该是uiWidth=2*uiCuWidthuiHeith=2*uiCuHeigth

具体过程见代码注释,肯定也有表述不完备的地方,请不吝赐教:

Void TComPattern::initAdiPattern( TComDataCU* pcCU, UInt uiZorderIdxInPart, UInt uiPartDepth, Int* piAdiBuf, Int iOrgBufStride, Int iOrgBufHeight, Bool& bAbove, Bool& bLeft, Bool bLMmode )
{
  Pel*  piRoiOrigin;//当前cu首地址
  Int*  piAdiTemp;
  UInt  uiCuWidth   = pcCU->getWidth(0) >> uiPartDepth;//cu宽度,uiPartDepth为四叉树深度
  UInt  uiCuHeight  = pcCU->getHeight(0)>> uiPartDepth;//cu高度
  UInt  uiCuWidth2  = uiCuWidth<<1;
  UInt  uiCuHeight2 = uiCuHeight<<1;
  UInt  uiWidth;//cu宽度
  UInt  uiHeight;//cu高度
  Int   iPicStride = pcCU->getPic()->getStride();//每次步进的距离
  Int   iUnitSize = 0;//4*4块
  Int   iNumUnitsInCu = 0;
  Int   iTotalUnits = 0;//总共包含的4*4块数量
  Bool  bNeighborFlags[4 * MAX_NUM_SPU_W + 1];//标记参考像素是否可用,4*16+1
  Int   iNumIntraNeighbor = 0;//可用的相邻块数
  
  UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;//获取当前PU左上、右上、左下以4x4为单位的Zorder

  
  pcCU->deriveLeftRightTopIdxAdi( uiPartIdxLT, uiPartIdxRT, uiZorderIdxInPart, uiPartDepth );
  pcCU->deriveLeftBottomIdxAdi  ( uiPartIdxLB,              uiZorderIdxInPart, uiPartDepth );
  
  iUnitSize      = g_uiMaxCUWidth >> g_uiMaxCUDepth;//4x4
  iNumUnitsInCu  = uiCuWidth / iUnitSize;
  iTotalUnits    = (iNumUnitsInCu << 2) + 1;//Top + RightTop\
   + Left + LeftBottom + LeftTop = iNumUnitsInCu + iNumUnitsInCu + iNumUnitsInCu + iNumUnitsInCu + 1

  //统计可用总数量,扫描顺序从左下到左上,再到右上
  bNeighborFlags[iNumUnitsInCu*2] = isAboveLeftAvailable( pcCU, uiPartIdxLT );//统计左上
  iNumIntraNeighbor  += (Int)(bNeighborFlags[iNumUnitsInCu*2]);
  iNumIntraNeighbor  += isAboveAvailable     ( pcCU, uiPartIdxLT, uiPartIdxRT, bNeighborFlags+(iNumUnitsInCu*2)+1 );//上,这个函数的\
    四个参数解释分别为当前pu编号,开始参考像素块号,结束块号,标志数组当前的位置指针
  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;
  bLeft  = true;

  //uiWidth、uiHeight与uiCuWidth,uiCuHeight不一样
  uiWidth=uiCuWidth2+1;//lefttop+above+rightabove
  uiHeight=uiCuHeight2+1;//lefttop+left+leftbelow
  
  //超出buf的长 
  if (((uiWidth<<2)>iOrgBufStride)||((uiHeight<<2)>iOrgBufHeight))
  {
    return;
  }
  
  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);
  
  Int   i;
  // generate filtered intra prediction samples参考像素滤波
  Int iBufSize = uiCuHeight2 + uiCuWidth2 + 1;  // left and left above border + above and above right border + top left corner = length of 3. filter buffer

  UInt uiWH = uiWidth * uiHeight;               // number of elements in one bufferbuf的大小

  //piFilteredBuf1最终参考像素放置的buf
  Int* piFilteredBuf1 = piAdiBuf + uiWH;        // 1. filter buffer
  Int* piFilteredBuf2 = piFilteredBuf1 + uiWH;  // 2. filter buffer
  //piFilterBuf中进行滤波计算
  Int* piFilterBuf = piFilteredBuf2 + uiWH;     // buffer for 2. filtering (sequential)
  //此处存放经滤波后的值
  Int* piFilterBufN = piFilterBuf + iBufSize;   // buffer for 1. filtering (sequential)
  

  //draft8.4.2.3Filtering process of neighbouring sample
  Int l = 0;
  //左下到右上
  // left border from bottom to top
  for (i = 0; i < uiCuHeight2; i++)//将处理后的参考样点值放到piFilterBuf中
  {
    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];
  }

  //判断是否进行强滤波
  if (pcCU->getSlice()->getSPS()->getUseStrongIntraSmoothing())
  {
    Int blkSize = 32;//强滤波块大小限定值,需要大于32的块
    Int bottomLeft = piFilterBuf[0];//左下角一个像素
    Int topLeft = piFilterBuf[uiCuHeight2];//左上角像素
    Int topRight = piFilterBuf[iBufSize-1];//右上角像素
    Int threshold = 1 << (g_bitDepthY - 5);//强滤波判断阈值
    //左下+左上-2*左中间<阈值
    Bool bilinearLeft = abs(bottomLeft+topLeft-2*piFilterBuf[uiCuHeight]) < threshold;
    //左上+右上-2*上中间<阈值
    Bool bilinearAbove  = abs(topLeft+topRight-2*piFilterBuf[uiCuHeight2+uiCuHeight]) < threshold;
  
    //强滤波
    if (uiCuWidth>=blkSize && (bilinearLeft && bilinearAbove))
    {
      Int shift = g_aucConvertToBit[uiCuWidth] + 3;  // log2(uiCuHeight2)=log2(64)=6
      piFilterBufN[0] = piFilterBuf[0];//复制左下
      piFilterBufN[uiCuHeight2] = piFilterBuf[uiCuHeight2];//左上
      piFilterBufN[iBufSize - 1] = piFilterBuf[iBufSize - 1];//右上
      //滤波的权值与据本边界两顶点的距离有关
      for (i = 1; i < uiCuHeight2; i++)//垂直方向滤波
      {
          //uiCuHeitht2 = (64-纵坐标)*左上+纵坐标*右上+32
        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;
      }
    }
  }
  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;
    }
  }

  //滤波后的参考像素复制到piFilteredBuf1中
  // 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++];
  }
}
其实这个代码有些细节很有意思,应该设计到可移植性和以后的更新维护,有时间了研究一下。

(转载请务必注明出处)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值