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

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

 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抽头滤波
}

enableEdgeFilters = !(pcCU->isRDPCMEnabled(uiAbsPartIdx) && pcCU->getCUTransquantBypass(uiAbsPartIdx));

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);

enableBoundaryFilter = pcCU->getSlice()->getSPS()->getUseIntraBoundaryFilter();

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抽头滤波；
}

对于小于等于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就表示插值系数）

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

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

 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());
}
}

 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])));

}

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

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

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