一直搞不清楚各种滤波器之间的区别,今天好好看看记录下来(持续更新)。
一.参考采样中的平滑滤波
在函数initIntraPatternChType里面,完成对相邻参考采样的填充后,要对参考采样进行平滑滤波;
平滑滤波又分为强平滑滤波和常规平滑滤波。
强平滑滤波的条件:只用于亮度分量且块的宽大于32且相邻采样间的差大于某个阈值
Bool useStrongIntraSmoothing = isLuma(chType) && sps.getUseStrongIntraSmoothing();
const Pel bottomLeft = piIntraTemp[stride * uiTuHeight2];//左下
const Pel topLeft = piIntraTemp[0];//左上
const Pel topRight = piIntraTemp[uiTuWidth2];//右上
if (useStrongIntraSmoothing)
{
#if O0043_BEST_EFFORT_DECODING
const Int threshold = 1 << (bitDepthForChannelInStream - 5);//32;
#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
if ((uiTuWidth < 32) || (!bilinearLeft) || (!bilinearAbove))//如果满足三个条件的其中之一,就不执行强平滑滤波
{
useStrongIntraSmoothing = false;
}
}
过程(以左列参考像素为例):
强平滑滤波:
if (useStrongIntraSmoothing)
{
#if JVET_C0024_QTBT
const Int shift = g_aucConvertToBit[uiTuHeight] + MIN_CU_LOG2 + 1; //log2(uiTuHeight2) //it is a bug for non-square PU for strong filter, JCA
#endif
//滤波系数与距离有关
for(UInt i=1; i<uiTuHeight2; i++, piDestPtr-=stride)
{
*piDestPtr = (((uiTuHeight2 - i) * bottomLeft) + (i * topLeft) + uiTuHeight) >> shift;
}
piSrcPtr -= stride * (uiTuHeight2 - 1);
}
常规滤波:
for(UInt i=1; i<uiTuHeight2; i++, piDestPtr-=stride, piSrcPtr-=stride)
{
*piDestPtr = ( piSrcPtr[stride] + 2*piSrcPtr[0] + piSrcPtr[-stride] + 2 ) >> 2;//即是[1 2 1]/4的3抽头滤波
}
二.EdgeFilter
该滤波器在xPredIntraAng函数里面使用。
enableEdgeFilters = !(pcCU->isRDPCMEnabled(uiAbsPartIdx) && pcCU->getCUTransquantBypass(uiAbsPartIdx));
条件:只对亮度分量且块的宽和高都小于16的块应用。
过程:当模式是纯水平或者是纯垂直模式,则对预测块(即已经得到预测值的当前块)的第一行/第一列进行滤波;
pDst[y*dstStride] = ClipA (pDst[y*dstStride] + (( refSide[y+1] - refSide[0] ) >> 1) ,compID);
当模式是纯水平模式左右的模式(即17,19)和纯垂直模式左右的模式(即49,51),则对预测块的第一行/第一列进行滤波;
pDst[y*dstStride] = ClipA(pDst[y*dstStride] + (( refSide[y+1] - refSide[0] ) >> 2) ,compID);
总结:EdgeFilter模式只用于纯水平垂直和类水平垂直(各两个)模式,对预测值进行滤波。
三.BoundaryFilter
该滤波器在xPredIntraAng函数后面使用。
enableBoundaryFilter = pcCU->getSlice()->getSPS()->getUseIntraBoundaryFilter();
条件:只对亮度分量且块的宽和高都大于2的块应用,且只应用于角度模式;
过程:当模式是2时,对预测块的上面四行(JEM中扩展到了4行)进行2抽头滤波;
for ( Int x = 0; x < iWidth; x++ )
{
pDst[x ] = ( 8 * pDst[x ] + 8 * pSrc[x - iSrcStride + 1] + 8 ) >> 4;
#if VCEG_AZ07_INTRA_BOUNDARY_FILTER_MULTI_LINE
pDst[x+iDstStride ] = ( 12 * pDst[x+iDstStride ] + 4 * pSrc[x - iSrcStride + 2] + 8 ) >> 4;
#if JVET_C0024_QTBT
if (iHeight>2)
{
#endif
pDst[x+iDstStride*2] = ( 14 * pDst[x+iDstStride*2] + 2 * pSrc[x - iSrcStride + 3] + 8 ) >> 4;
pDst[x+iDstStride*3] = ( 15 * pDst[x+iDstStride*3] + pSrc[x - iSrcStride + 4] + 8 ) >> 4;
#if JVET_C0024_QTBT
}
#endif
#endif
}
当模式是66时,对预测块的最左边四列(JEM中扩展到了4列)进行2抽头滤波;
for ( Int y = 0, iDstStride2 = 0, iSrcStride2 = -1; y < iHeight; y++, iDstStride2+=iDstStride, iSrcStride2+=iSrcStride )
{
pDst[iDstStride2 ] = ( 8 * pDst[iDstStride2 ] + 8 * pSrc[iSrcStride2+iSrcStride ] + 8 ) >> 4;
#if VCEG_AZ07_INTRA_BOUNDARY_FILTER_MULTI_LINE
pDst[iDstStride2+1] = ( 12 * pDst[iDstStride2+1] + 4 * pSrc[iSrcStride2+iSrcStride*2] + 8 ) >> 4;
#if JVET_C0024_QTBT
if (iWidth>2)
{
#endif
pDst[iDstStride2+2] = ( 14 * pDst[iDstStride2+2] + 2 * pSrc[iSrcStride2+iSrcStride*3] + 8 ) >> 4;
pDst[iDstStride2+3] = ( 15 * pDst[iDstStride2+3] + pSrc[iSrcStride2+iSrcStride*4] + 8 ) >> 4;
#if JVET_C0024_QTBT
}
#endif
#endif
}
当模式是3--10或者是58--66模式,则
如果是水平模式,则对当前块的第一行边界进行3抽头滤波;
for ( Int x = 0; x < iWidth; x++ )
{
pDst[x] = ( filter[0] * pDst[x]
+ filter[1] * pSrc[x - iSrcStride + offset[0]]
+ filter[2] * pSrc[x - iSrcStride + offset[1]] + 8) >> 4;//对第一行边界进行3抽头滤波
}
如果是垂直模式,则对当前块的第一列边界进行3抽头滤波;
for ( Int y = 0; y < iHeight; y++ )
{
pDst[y * iDstStrid