【HEVC学习与研究】36、对帧内预测参考数据进行滤波处理

在帧内预测的过程中,获取临近的Prediction Unit的边缘数据作为当前PU的参考数据。数据获取完成后,并不一定会直接使用这些数据进行预测,而可能会先将这些预测数据进行一次滤波操作。帧内参考像素的滤波在标准文档的8.4.4.2.3节详述。

帧内参考像素的滤波使能标记由一个标志位filterFlag标识。该标志位的判定方法为:

1、如果当前预测模式为DC模式,或者帧内预测的PU为4×4大小时,filterFlag一律为0;

2、计算当前的Intra预测模式同“水平”和“垂直”预测模式的index之间的差值;将这个差值同针对不同大小PU所分别设定的阈值(对于8×8PU为7,对于16×16PU为1,对于32×32PU为0)进行比较,如果大于阈值则filterFlag为1,否则为0。

思想:对于角度预测而言,该算法的目的是对不同的PU大小和预测方向进行区分,越小的PU越不需要滤波,越接近于“水平”和“垂直”的预测模式越不需要滤波。也就是说,4×4PU全不需要滤波,8×8PU只有接近于对角线的部分模式需要滤波,16×16PU除了水平和垂直模式其他都需要滤波,而32×32PU全部必须进行滤波处理。

当设定为需要滤波时,滤波操作根据一个开关变量bInitFlag又有所区分。bInitFlag的判定方法如下:

1、SPS中指定的一个设置位strong_intra_smoothing_enabled_flag设置为1,并且PU大小为32×32,并且指定参考点数据之间的差值不是很大(具体的判定方法见标准文档)的时候,该标志位设为1;

2、其他情况下,该标志位设为0。

设定bInitFlag完成后,根据该标识取值,滤波过程分为两种不同情况:

1、当bInitFlag取1时,缓存区中两个端点和中心店不进行滤波,其他值根据距离这三个点的距离不同进行加权平均滤波;

2、当bInitFlag取0时,缓存区中的相邻数据进行[1,2,1]平滑滤波。

代码中的实现方法如下,很容易看出代码的实现和标准文档是匹配的:

Void TComPattern::initAdiPattern( TComDataCU* pcCU, UInt uiZorderIdxInPart, UInt uiPartDepth, Int* piAdiBuf, Int iOrgBufStride, Int iOrgBufHeight, Bool& bAbove, Bool& bLeft, Bool bLMmode )
{
//......
if (pcCU->getSlice()->getSPS()->getUseStrongIntraSmoothing())
  {
    Int blkSize = 32;
    Int bottomLeft = piFilterBuf[0];
    Int topLeft = piFilterBuf[uiCuHeight2];
    Int topRight = piFilterBuf[iBufSize-1];
    Int threshold = 1 << (g_bitDepthY - 5);
    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)
      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;
      }
    }
  }
  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;
    }
  }
//......
}


上一篇:python访问oracle时的问题总结


下一篇:Python编程:getattribute和getattr访问对象属性顺序