小小柴的博客

日常学习笔记

H.266中的各类滤波器总结

      一直搞不清楚各种滤波器之间的区别,今天好好看看记录下来(持续更新)。

一.参考采样中的平滑滤波

在函数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 * iDstStride] = ( filter[0] * pDst[y * iDstStride] 
      + filter[1] * pSrc[(y + offset[0] ) * iSrcStride -1 ] 
      + filter[2] * pSrc[(y + offset[1] ) * iSrcStride -1 ] + 8) >> 4; //对当前块的第一列进行3抽头滤波;      
    }

总结:BoundaryFilter只用于对角和斜对角模式(左下和右上各8个),对预测值进行滤波。

四.4抽头滤波器

该滤波器在xPredIntraAng函数里面使用。

条件:只用于角度模式2--66

过程:在计算分像素位置的预测值时,使用该滤波器来得到预测值;

         对于小于等于8*8的块,使用三次插值滤波(滤波后需要进行clipping);

         对于大于8*8的块,使用高斯插值滤波(滤波后不需要进行clipping);

pDst[y*dstStride+x] =  (Pel)( ( f[0]*p[0] + f[1]*p[1] + f[2]*p[2] + f[3]*p[3] + 128 ) >> 8 );

(f0,f1,f2,f3就表示插值系数)

总结:只用于角度模式 ,生成预测值;

五.filteringIntraReferenceSamples函数

       在predIntraAng函数进行前先要求bUseFilter,该函数不是指示是否进行滤波的标志,而是指示是否使用滤波过的参考像素用于预测。

bUseFilter=TComPrediction::filteringIntraReferenceSamples(COMPONENT_Y, uiMode, puRect.width, puRect.height, chFmt, sps.getSpsRangeExtension().getIntraSmoothingDisabledFlag()

然后将bUseFilter作为参数传入predIntraAng函数里使用;

 if( isLuma( compID ) )
    {
      if( pcCU->getROTIdx( CHANNEL_TYPE_LUMA, uiAbsPartIdx ) )
      {
        ptrSrc = getPredictorPtr( compID, bUseFilteredPredSamples );//bUseFilteredPredSamples为false,指针指向未滤波参考像素,否则指向滤波的参考像素;
      }
    }
 Pel*  getPredictorPtr           ( const ComponentID compID, const Bool bUseFilteredPredictions )
  {
    return m_piYuvExt[compID][bUseFilteredPredictions?PRED_BUF_FILTERED:PRED_BUF_UNFILTERED];//m_piYuvExt在initIntraPatternChType里完成赋值;

  }

六.残差信号的平滑

在得到残差后进行变换量化之前,先对残差信号进行平滑;

 smoothResidual(compID,piOrg,piResi,uiHeight,uiWidth,uiStride,uiStride);
void smoothResidual(const ComponentID compID,const Pel *piOrg,Pel *piResi,UInt uiHeight,UInt uiWidth,UInt uiStrideOrg,UInt uiStrideRes) {

    Bound prm;//是一个结构体,里面有两个数据成员,m,M;
    switch(compID) {
    case COMPONENT_Y:    prm=g_ClipParam.Y(); break;
    case COMPONENT_Cb:   prm=g_ClipParam.U(); break;
    case COMPONENT_Cr:   prm=g_ClipParam.V(); break;
    default: assert(false);
    }

    static std::vector<Pel> org; // avoid realloc
    org.resize(uiHeight*uiWidth);

    Bool activate=false;
    for(Int i=0,k=0;i<uiHeight;++i)
        for(Int j=0;j<uiWidth;++j,++k) {
            org[k]=piOrg[i*uiStrideOrg+j];//把原始值赋给org;
            if (org[k]<=prm.m||org[k]>=prm.M) activate=true;//如果有某个原始值小于m,或者大于M,则active=true;
        }


    if (activate) {
        static std::vector<Pel> r; // avoid realloc
        r.resize(uiHeight*uiWidth);
        for(Int i=0,k=0;i<uiHeight;++i)
            for(Int j=0;j<uiWidth;++j,++k) {
                r[k]=piResi[i*uiStrideRes+j];//把残差数据赋值给r
            }
        smoothResidual(prm,org,r,uiHeight,uiWidth);//根据prm和原始数据对残差信号进行平滑
        // copy back
        for(Int i=0,k=0;i<uiHeight;++i)
            for(Int j=0;j<uiWidth;++j,++k) {
                piResi[i*uiStrideRes+j]=r[k];//又将r重新赋值给残差信号数组;
            }
    }
}

void smoothResidual(const Bound prm,const std::vector<Pel> &org,std::vector<Pel> &res,UInt uiHeight,UInt uiWidth) {
    // find boundaries of the res
    static std::vector<char> bmM;
    static std::vector<Pel> r;
    r=res;
    bmM.resize(uiHeight*uiWidth); // avoir realloc

    for(int k=0;k<(int)org.size();++k) {
        if (org[k]<=prm.m)      bmM[k]=-1;//如果原始值小于等于m,则bmM等于-1;
        else if (org[k]>=prm.M) bmM[k]=+1;//如果原始值大于等于M,则bmM等于+1;
        else                    bmM[k]=0;//如果原始值小于M且大于m,则bmM=0;
    }

    const int cptmax=4;
    int cpt=0;
    bool cont=true;
    while(cpt<cptmax&&cont) {
        cont=false;
        for(int i=0;i<(int)uiHeight;++i)
            for(int j=0;j<(int)uiWidth;++j) {
                if (bmM[i*uiWidth+j]==-1) { // we can lower the res,如果原始值小于prm.m,则计算一个s,如果残差大于s,把残差改为s;
                    Int s=average<3>(res,i,j,uiHeight,uiWidth);//s的计算为以(i,j)为中心的3*3正方形的9个采样的均值;
                    if (s<res[i*uiWidth+j]) r[i*uiWidth+j]=s;//即相当于减小残差
                    cont=true;
                } else if (bmM[i*uiWidth+j]==1) { // we can inc the res,如果原始值大于prm.M,则计算一个s,如果残差小于s,把残差改为s;
                    Int s=average<3>(res,i,j,uiHeight,uiWidth);
                    if (s>res[i*uiWidth+j]) r[i*uiWidth+j]=s;//即相当于增大残差
                    cont=true;
                }
            }
        ++cpt;
        std::copy(r.begin(),r.end(),res.begin());
    }
}

七.双边滤波器

双边滤波器是H.266中新加的技术,用在重建环节后,权重不仅和距离有关,还和强度有关,所以双边滤波器的设计是为了减少对帧间预测块的滤波;

条件:只用于亮度分量,如果QP小于18或者块是帧间预测且块大于等于16*16时,则不进行双边滤波;

 if(pcCU->getSlice()->getSPS()->getUseBilateralFilter()) //重建完使用双边滤波,只对亮度分量使用?    
  {
    Pel* piReco = pcRecoYuv->getAddr( compID, uiAbsPartIdx );
    Pel* piRecIPred = pcCU->getPic()->getPicYuvRec()->getAddr( compID, pcCU->getCtuRsAddr(), pcCU->getZorderIdxInCtu() + uiAbsPartIdx );

    if (isLuma(compID))//双边滤波器只用于亮度分量
    {
      if ((pcCU->getCbf(uiAbsPartIdx, compID, rTu.GetTransformDepthRel()) != 0) && (pcCU->getQP(COMPONENT_Y) > 17))
      {//双边滤波器,即重建CU中的每一个亮度采样都用其自身及其邻近采样的加权平均替代
        TComBilateralFilter::instance()->bilateralFilterIntra(pcCU, uiWidth, uiHeight, piReco, uiStride, pcCU->getQP(COMPONENT_Y));
        for( UInt uiY = 0; uiY < uiHeight; uiY++ )
        {
          memcpy(piRecIPred + uiY * uiRecIPredStride, piReco + uiY * uiStride , uiWidth * sizeof(Short));
          uiY++;
          memcpy(piRecIPred + uiY * uiRecIPredStride, piReco + uiY * uiStride , uiWidth * sizeof(Short));
        }
      }
    }
  }
Void TComBilateralFilter::bilateralFilterIntra(TComDataCU *pcCU, UInt uiWidth, UInt uiHeight, Pel *piReco, UInt uiStride, Int qp)
{
  UInt uiMinSize = std::min(uiWidth, uiHeight);
  Short *tempblock = new Short[ uiWidth * uiHeight ];
  
  for (UInt j = 0; j < uiHeight; j++)   
  {
    memcpy(tempblock + j * uiWidth, piReco + j * uiStride, uiWidth * sizeof(Short));
  }
  smoothBlockBilateralFilter(pcCU, uiWidth, uiHeight, tempblock, uiMinSize, 0, qp);//双边滤波的主函数
  for (UInt j = 0; j < uiHeight; j++)
  {
    memcpy(piReco + j * uiStride, tempblock + j * uiWidth, uiWidth * sizeof(Short));
  }
  delete[] tempblock;
}
Void TComBilateralFilter::smoothBlockBilateralFilter(TComDataCU* pcCU, UInt uiWidth, UInt uiHeight, Short block[], Int length, Int isInterBlock, Int qp)
{
  Int rightPixel, centerPixel;
  Int rightWeight, bottomWeight, centerWeight;
  Int sumWeights[MAX_CU_SIZE];
  Int sumDelta[MAX_CU_SIZE];
  Int blockLengthIndex;
  
  Int dIB, dIR;
    
  switch (length)
  {
    case 4:
      blockLengthIndex = 0;
      break;
    case 8:
      blockLengthIndex = 1;
      break;
    default:
      blockLengthIndex = 2;
      break;
  }
  
  UShort *lookupTablePtr;
  //isInterBlock默认等于0,所以这里的取值只是[0],[1],[2];
  centerWeight = m_bilateralCenterWeightTable[blockLengthIndex + 3 * isInterBlock];//中间像素的权重,查表法
  //QP小于18则不进行双边滤波
  Int theMaxPos = maxPosList[qp-18];
  lookupTablePtr = m_bilateralFilterTable[qp-18];//邻近样本权重的查找表,每个QP对应一个表

  // for each pixel in block,依次为块中的像素执行双边滤波器
  
  // These are the types of pixels,像素类型:
  //
  // A BB C
  //
  // D EE F
  // D EE F
  //
  // G HH I
  //
  // If the block is larger than 4x4, the E-part is larger.
  //
  // Filter types,滤波类型:
  //
  // AA  BBB   CC
  // A    B     C
  //
  // D    E     F
  // DD  EEE   FF
  // D    E     F
  //
  // G    H     I
  // GG  HHH   II
  // C uses a filter of type x
  Int currentPixelDeltaSum;
  Int currentPixelSumWeights;
  Int rightPixelDeltaSum;
  Int rightPixelSumWeights;
  Int rightWeightTimesdIR;
  Int bottomWeightTimesdIB;
  
  Int mySignIfNeg;
  Int mySign;
  
  Short *blockCurrentPixelPtr = block;//当前像素
  Short *blockRightPixelPtr = blockCurrentPixelPtr+1;//当前像素的右边像素
  Short *blockNextLinePixelPtr = blockCurrentPixelPtr + uiWidth;//当前像素的下边像素
  Int *sumWeightsPtr = sumWeights;
  Int *sumDeltaPtr = sumDelta;
  
  // A pixel. uses filter type xx,第一行第一个像素,只有两个相邻像素
  //                           x
  //
  // No information from previous row,前一行没有信息
  // No information from previous pixel,前一个像素没有信息
  // Storing information to next row,为下一行存储信息
  // Storing information to next pixel,为下一个像素存储信息
  
  // top left pixel; i = 0, j = 0;
  
  centerPixel = *(blockCurrentPixelPtr);//中心像素
  rightPixel = *(blockRightPixelPtr++);//右边的像素
  dIR = rightPixel - centerPixel;
  dIB = *(blockNextLinePixelPtr++) - centerPixel;
  
  rightWeight = lookupTablePtr[std::min(theMaxPos, abs(dIR))];//右边像素的权重
  bottomWeight = lookupTablePtr[std::min(theMaxPos, abs(dIB))];//下边像素的权重
  
  rightWeightTimesdIR = rightWeight*dIR;//Wr*(Ir-Ic)
  bottomWeightTimesdIB = bottomWeight*dIB;//Wb*(Ib-Ic)
  
  currentPixelSumWeights = centerWeight + rightWeight + bottomWeight;//Wc+Wr+Wb
  currentPixelDeltaSum = rightWeightTimesdIR + bottomWeightTimesdIB;//Wr*(Ir-Ic)+Wb*(Ib-Ic)
  //为下一个像素存储信息
  rightPixelSumWeights = rightWeight; //next pixel to the right
  rightPixelDeltaSum = rightWeightTimesdIR;//Wr*(Ir-Ic)
  //为下一行像素存储信息
  *(sumWeightsPtr++) = bottomWeight; //next pixel to the bottom
  *(sumDeltaPtr++) = bottomWeightTimesdIB; //next pixel to the bottom
  
  mySignIfNeg = SIGN_IF_NEG(currentPixelDeltaSum);
  mySign = 1 | mySignIfNeg;
  //G1001里的式45;
  *(blockCurrentPixelPtr++) = centerPixel + mySign*((((mySign*currentPixelDeltaSum + ((currentPixelSumWeights+mySignIfNeg) >> 1))*divToMulOneOverN[currentPixelSumWeights]) >> (BITS_PER_DIV_LUT_ENTRY + divToMulShift[currentPixelSumWeights])));
  
  for (Int i = 1; i < (uiWidth-1); i++)//遍历第一行中间的像素(除去头尾的像素)
  {
    // B pixel. uses filter type xxx,有3个相邻像素,左,右,下
    //                            x
    //
    // No information from previous row,前一行没有信息
    // Information reused from previous pixel,前一个像素有信息
    // Storing information to next row,为下一行存储信息
    // Storing information to next pixel,为下一个像素存储信息
    
    centerPixel = rightPixel;
    rightPixel = *(blockRightPixelPtr++);
    dIR = rightPixel - centerPixel;//Ir-Ic
    dIB = *(blockNextLinePixelPtr++) - centerPixel;//Ib-Ic
    
    rightWeight = lookupTablePtr[std::min(theMaxPos, abs(dIR))];//Wr;
    bottomWeight = lookupTablePtr[std::min(theMaxPos, abs(dIB))];//Wb
    
    rightWeightTimesdIR = rightWeight*dIR;////Wr*(Ir-Ic)
    bottomWeightTimesdIB = bottomWeight*dIB;//Wb*(Ib-Ic)
    
    currentPixelSumWeights = centerWeight + rightPixelSumWeights + rightWeight + bottomWeight;
    currentPixelDeltaSum = rightWeightTimesdIR + bottomWeightTimesdIB - rightPixelDeltaSum;
	//为下一个像素存储信息
    rightPixelSumWeights = rightWeight; //next pixel to the right
    rightPixelDeltaSum = rightWeightTimesdIR; //next pixel to the right
    //为下一行像素存储信息
    *(sumWeightsPtr++) = bottomWeight; //next pixel to the bottom
    *(sumDeltaPtr++) = bottomWeightTimesdIB; //next pixel to the bottom
    
    mySignIfNeg = SIGN_IF_NEG(currentPixelDeltaSum);
    mySign = 1 | mySignIfNeg;

    *(blockCurrentPixelPtr++) = centerPixel + mySign*((((mySign*currentPixelDeltaSum + ((currentPixelSumWeights+mySignIfNeg) >> 1))*divToMulOneOverN[currentPixelSumWeights]) >> (BITS_PER_DIV_LUT_ENTRY + divToMulShift[currentPixelSumWeights])));
    
  }
  
  // C pixel. uses filter type xx,第一行的最后一个像素,有两个相邻像素,左和下
  //                            x
  //
  // No information from previous row,前一行没有信息
  // Information reused from previous pixel,前面像素有信息
  // Storing information to next row,为下一行存储信息
  // No information to store to next pixel,不需要为下一个像素存储信息
  
  centerPixel = rightPixel;
  blockRightPixelPtr++;
  dIB = *(blockNextLinePixelPtr++) - centerPixel;
  
  bottomWeight = lookupTablePtr[std::min(theMaxPos, abs(dIB))];
  bottomWeightTimesdIB = bottomWeight*dIB;
  
  currentPixelSumWeights = centerWeight + rightPixelSumWeights + bottomWeight;
  currentPixelDeltaSum = bottomWeightTimesdIB - rightPixelDeltaSum;
  //为下一行存储信息
  *(sumWeightsPtr) = bottomWeight; //next pixel to the bottom
  *(sumDeltaPtr++) = bottomWeightTimesdIB; //next pixel to the bottom
  
  mySignIfNeg = SIGN_IF_NEG(currentPixelDeltaSum);
  mySign = 1 | mySignIfNeg;

  *(blockCurrentPixelPtr++) = centerPixel + mySign*((((mySign*currentPixelDeltaSum + ((currentPixelSumWeights+mySignIfNeg) >> 1))*divToMulOneOverN[currentPixelSumWeights]) >> (BITS_PER_DIV_LUT_ENTRY + divToMulShift[currentPixelSumWeights])));
  
  for (Int j = 1; j < (uiHeight-1); j++)//遍历除了第一行和最后一行的每行
  {
    sumWeightsPtr = sumWeights;
    sumDeltaPtr = sumDelta;
    
    //                           x
    // D pixel. uses filter type xx,中间行的第一个像素,右三个相邻像素,上,下,右
    //                           x
    //
    // Uses information from previous row,前一行有信息
    // No information from previous pixel,前一个像素没有信息
    // Storing information to next row,为下一行存储信息
    // Storing information to next pixel,为下一个像素存储信息
    
    centerPixel = *(blockCurrentPixelPtr);
    rightPixel = *(blockRightPixelPtr++);
    dIR = rightPixel - centerPixel;
    dIB = *(blockNextLinePixelPtr++) - centerPixel;
    
    rightWeight = lookupTablePtr[std::min(theMaxPos, abs(dIR))];
    bottomWeight = lookupTablePtr[std::min(theMaxPos, abs(dIB))];
    
    rightWeightTimesdIR = rightWeight*dIR;
    bottomWeightTimesdIB = bottomWeight*dIB;
    
    currentPixelSumWeights = centerWeight + *(sumWeightsPtr) + rightWeight + bottomWeight;
    currentPixelDeltaSum = rightWeightTimesdIR + bottomWeightTimesdIB - *(sumDeltaPtr);
	//为下一个像素存储信息
    rightPixelSumWeights = rightWeight; //next pixel to the right
    rightPixelDeltaSum = rightWeightTimesdIR;
	//为下一行像素存储信息
    *(sumWeightsPtr++) = bottomWeight; //next pixel to the bottom
    *(sumDeltaPtr++) = bottomWeightTimesdIB; //next pixel to the bottom
    
    mySignIfNeg = SIGN_IF_NEG(currentPixelDeltaSum);
    mySign = 1 | mySignIfNeg;

    *(blockCurrentPixelPtr++) = centerPixel + mySign*((((mySign*currentPixelDeltaSum + ((currentPixelSumWeights+mySignIfNeg) >> 1))*divToMulOneOverN[currentPixelSumWeights]) >> (BITS_PER_DIV_LUT_ENTRY + divToMulShift[currentPixelSumWeights])));
    
    for (Int i = 1; i < (uiWidth-1); i++)//遍历中间行的每个中间像素
    {
      //                            x
      // E pixel. uses filter type xxx,中间行的中间像素,有上下左右四个像素
      //                            x
      //
      // Uses information from previous row前一行有信息
      // Uses information from previous pixel前一个像素有信息
      // Storing information to next row为下一行存储信息
      // Storing information to next pixel为下一个像素存储信息
      
      centerPixel = rightPixel;
      rightPixel = *(blockRightPixelPtr++);
      dIR = rightPixel - centerPixel;
      dIB = *(blockNextLinePixelPtr++) - centerPixel;
      
      rightWeight = lookupTablePtr[std::min(theMaxPos, abs(dIR))];
      bottomWeight = lookupTablePtr[std::min(theMaxPos, abs(dIB))];
      
      rightWeightTimesdIR = rightWeight*dIR;
      bottomWeightTimesdIB = bottomWeight*dIB;
      
      currentPixelSumWeights = centerWeight + *(sumWeightsPtr) + rightPixelSumWeights + rightWeight + bottomWeight;
      currentPixelDeltaSum = rightWeightTimesdIR + bottomWeightTimesdIB - rightPixelDeltaSum - *(sumDeltaPtr);
	  //为下一个像素存储信息
      rightPixelSumWeights = rightWeight; //next pixel to the right
      rightPixelDeltaSum = rightWeightTimesdIR;
	  //为下一行像素存储信息
      *(sumWeightsPtr++) = bottomWeight; //next pixel to the bottom
      *(sumDeltaPtr++) = bottomWeightTimesdIB; //next pixel to the bottom
      
      mySignIfNeg = SIGN_IF_NEG(currentPixelDeltaSum);
      mySign = 1 | mySignIfNeg;

      *(blockCurrentPixelPtr++) = centerPixel + mySign*((((mySign*currentPixelDeltaSum + ((currentPixelSumWeights+mySignIfNeg) >> 1))*divToMulOneOverN[currentPixelSumWeights]) >> (BITS_PER_DIV_LUT_ENTRY + divToMulShift[currentPixelSumWeights])));
    }
    
    //                            x
    // F pixel. uses filter type xx,中间行的最后一个像素,有左,上,下三个相邻像素
    //                            x
    //
    // Uses information from previous row,使用前一行的信息
    // Uses information from previous pixel,使用前一个像素的信息
    // Storing information to next row,为下一行存储信息
    // No  information to store to next pixel,不需要为下一个像素存储信息
    
    centerPixel = rightPixel;
    blockRightPixelPtr++;
    dIB = *(blockNextLinePixelPtr++) - centerPixel;
    
    bottomWeight = lookupTablePtr[std::min(theMaxPos, abs(dIB))];
    bottomWeightTimesdIB = bottomWeight*dIB;
    
    currentPixelSumWeights = centerWeight + *(sumWeightsPtr) + rightPixelSumWeights + bottomWeight;
    currentPixelDeltaSum = bottomWeightTimesdIB - rightPixelDeltaSum - *(sumDeltaPtr);
	//为下一行像素存储信息
    *(sumWeightsPtr) = bottomWeight; //next pixel to the bottom
    *(sumDeltaPtr++) = bottomWeightTimesdIB; //next pixel to the bottom
    
    mySignIfNeg = SIGN_IF_NEG(currentPixelDeltaSum);
    mySign = 1 | mySignIfNeg;

    *(blockCurrentPixelPtr++) = centerPixel + mySign*((((mySign*currentPixelDeltaSum + ((currentPixelSumWeights+mySignIfNeg) >> 1))*divToMulOneOverN[currentPixelSumWeights]) >> (BITS_PER_DIV_LUT_ENTRY + divToMulShift[currentPixelSumWeights])));
    
  }
  
  sumWeightsPtr = sumWeights;
  sumDeltaPtr = sumDelta;
  
  //                           x
  // G pixel. uses filter type xx最后一行的第一个像素,有上,右两个信息
  //
  // Uses information from previous row,前一行有信息
  // No information from previous pixel,前一个像素没有信息
  // No information to store to next row,不需要为下一行存储信息
  // Storing information to next pixel,为下一个像素存储信息
  
  
  centerPixel = *(blockCurrentPixelPtr);
  rightPixel = *(blockRightPixelPtr++);
  dIR = rightPixel - centerPixel;
  
  rightWeight = lookupTablePtr[std::min(theMaxPos, abs(dIR))];
  rightWeightTimesdIR = rightWeight*dIR;
  
  currentPixelSumWeights = centerWeight + *(sumWeightsPtr++) + rightWeight;
  currentPixelDeltaSum = rightWeightTimesdIR - *(sumDeltaPtr++);
  //为下一个像素存储信息
  rightPixelSumWeights = rightWeight; //next pixel to the right
  rightPixelDeltaSum = rightWeightTimesdIR;
  
  mySignIfNeg = SIGN_IF_NEG(currentPixelDeltaSum);
  mySign = 1 | mySignIfNeg;

  *(blockCurrentPixelPtr++) = centerPixel + mySign*((((mySign*currentPixelDeltaSum + ((currentPixelSumWeights+mySignIfNeg) >> 1))*divToMulOneOverN[currentPixelSumWeights]) >> (BITS_PER_DIV_LUT_ENTRY + divToMulShift[currentPixelSumWeights])));
  
  for (Int i = 1; i < (uiWidth-1); i++)//遍历最后一行的中间像素
  {
    //                            x
    // H pixel. uses filter type xxx,有上,左,右三个像素
    //
    // Uses information from previous row前一行有信息
    // Uses information from previous pixel前一个像素有信息
    // No information to store to next row不需要为下一行存储信息
    // Storing information to next pixel为下一个像素存储信息
    
    centerPixel = rightPixel;
    rightPixel = *(blockRightPixelPtr++);
    dIR = rightPixel - centerPixel;
    
    rightWeight = lookupTablePtr[std::min(theMaxPos, abs(dIR))];
    rightWeightTimesdIR = rightWeight*dIR;
    
    currentPixelSumWeights = centerWeight + *(sumWeightsPtr++) + rightWeight + rightPixelSumWeights;
    currentPixelDeltaSum = rightWeightTimesdIR - rightPixelDeltaSum - *(sumDeltaPtr++);
	//为下一个像素存储信息
    rightPixelSumWeights = rightWeight; //next pixel to the right
    rightPixelDeltaSum = rightWeightTimesdIR;
    
    mySignIfNeg = SIGN_IF_NEG(currentPixelDeltaSum);
    mySign = 1 | mySignIfNeg;

    *(blockCurrentPixelPtr++) = centerPixel + mySign*((((mySign*currentPixelDeltaSum + ((currentPixelSumWeights+mySignIfNeg) >> 1))*divToMulOneOverN[currentPixelSumWeights]) >> (BITS_PER_DIV_LUT_ENTRY + divToMulShift[currentPixelSumWeights])));
    
  }
  
  //                            x
  // I pixel. uses filter type xx,最后一行的最后一个像素,有左和上两个像素
  //
  // Uses information from previous row,使用前一行的信息
  // Uses information from previous pixel,使用前一个像素的信息
  // No information to store to next row,不需要为下一行存储信息
  // No information to store to nex pixel,不需要为下一个像素存储信息
  
  centerPixel = rightPixel;
  
  currentPixelSumWeights = centerWeight + *(sumWeightsPtr) + rightPixelSumWeights;
  currentPixelDeltaSum = - rightPixelDeltaSum - *(sumDeltaPtr);
  
  mySignIfNeg = SIGN_IF_NEG(currentPixelDeltaSum);
  mySign = 1 | mySignIfNeg;

  *(blockCurrentPixelPtr) = centerPixel + mySign*((((mySign*currentPixelDeltaSum + ((currentPixelSumWeights+mySignIfNeg) >> 1))*divToMulOneOverN[currentPixelSumWeights]) >> (BITS_PER_DIV_LUT_ENTRY + divToMulShift[currentPixelSumWeights])));
  
}

八.DC模式的边界滤波

如果预测模式是DC模式,则需要对预测后的块边界值做平滑滤波,具体为:

1.对于P[0,0],将其与左相邻与上相邻的两个参考像素之间做三抽头滤波,比例系数为1:2:1;

2.对于P[x,0],即第一行,将其与上相邻的参考像素之间做二抽头滤波,比例系数为3:1;

3.对于P[0,y],即第一行,将其与左相邻的参考像素之间做二抽头滤波,比例系数为3:1;




阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cxy19931018/article/details/79950597
个人分类: H.266/VVC JEM
上一篇H.266中的熵编码
下一篇VVC/JEM代码学习23:xRecurIntraCodingLumaQT()
想对作者说点什么? 我来说一句

IIR滤波器设计实验报告

2011年07月01日 323KB 下载

各种滤波器程序 matlab

2012年12月13日 2KB 下载

HM-16.6-JEM-6.0

2017年05月11日 5.78MB 下载

H.266变换编码ppt

2018年01月22日 475KB 下载

KEILC51的应用,各类问题的总结

2011年07月08日 32KB 下载

ios各种翻页效果总结

2012年12月02日 36KB 下载

ios各种动画效果

2012年12月02日 118KB 下载

公司年会报告PPT素材

2017年12月27日 26.33MB 下载

数据采集系统中滤波器的选择

2011年05月22日 210KB 下载

没有更多推荐了,返回首页

关闭
关闭