帧内预测——fillReferenceSamples

此函数`TComPattern::fillReferenceSamples`用于填充帧内预测时的参考样本。根据邻接块的数量,它会用DC值填充边框,或者使用重建样本填充边界。在部分可用邻接块的情况下,会进行特定的填充策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

	fillReferenceSamples函数主要的作用就是在真正进行帧内预测之前,使用重建后的Yuv图像对当前PU的相邻样点进行值,为接下来进行的角度预测提供参考样点值。我引用了http://blog.youkuaiyun.com/hevc_cjl/article/details/8175721的文章对这段代码的注解同时加上了一些自己学习的体会。
 
/*
(1)如果所有相邻点均不可用,则参考样点值均被赋值为DC值;
(2)如果所有相邻点均可用,则参考样点值都会被赋值为重建Yuv图像中与其位置相同的样点值;
(3)如果不满足上述两个条件,则按照从左下往左上,从左上往右上的扫描顺序进行遍历,
如果第一个点不可用,则使用下一个可用点对应的重建Yuv样点值对其进行赋值;对于除第一个点外的其它邻点,
如果该点不可用,则使用它的前一个样点值进行赋值(前一个步骤保证了前一个样点值一定是存在的),直到遍历完毕。*/
 

Void TComPattern::fillReferenceSamples(Int bitDepth, Pel* piRoiOrigin, Int* piAdiTemp, Bool* bNeighborFlags, Int iNumIntraNeighbor, Int iUnitSize, Int iNumUnitsInCu, Int iTotalUnits, UInt uiCuWidth, UInt uiCuHeight, UInt uiWidth, UInt uiHeight, Int iPicStride, Bool bLMmode )

{   Pel* piRoiTemp; //!< piRoiOrgin指向重建Yuv图像对应于当前PU所在位置的首地址,piRoiTemp用于指向所感兴趣的重建Yuv的位置,piAdiTemp   Int  i, j;   Int  iDCValue = 1 << (bitDepth - 1);//用于DC赋值     if (iNumIntraNeighbor == 0)//可用邻块数为0   {     // Fill border with DC value     for (i=0; i<uiWidth; i++)//上边界赋值     {       piAdiTemp[i] = iDCValue;     }     for (i=1; i<uiHeight; i++)//左边     {       piAdiTemp[i*uiWidth] = iDCValue;     }   }   else if (iNumIntraNeighbor == iTotalUnits)   {     // Fill top-left border with rec. samples     piRoiTemp = piRoiOrigin - iPicStride - 1;////!< 左上,iPicStride图像跨度相当于- iPicStride为换一行     piAdiTemp[0] = piRoiTemp[0];//指针指向左上

    // Fill left border with rec. samples piRoiTemp = piRoiOrigin - 1;//!< 左 if (bLMmode)//bLMmode 默认值为false { piRoiTemp --; // move to the second left column } for (i=0; i<uiCuHeight; i++)//对左上赋值 { piAdiTemp[(1+i)*uiWidth] = piRoiTemp[0];//!< 每个参考样点赋值为对应位置重建Yuv样点值 piRoiTemp += iPicStride;//!< 指向重建Yuv下一行 } // Fill below left border with rec. samples for (i=0; i<uiCuHeight; i++)//!< 对左下赋值 { piAdiTemp[(1+uiCuHeight+i)*uiWidth] = piRoiTemp[0]; piRoiTemp += iPicStride; } // Fill top border with rec. samples piRoiTemp = piRoiOrigin - iPicStride;//!< 重新指向重建Yuv的上方 for (i=0; i<uiCuWidth; i++) { piAdiTemp[1+i] = piRoiTemp[i];//!< 每个参考样点赋值为对应位置重建Yuv样点值 } // Fill top right border with rec. samples piRoiTemp = piRoiOrigin - iPicStride + uiCuWidth;//!< 指向右上 for (i=0; i<uiCuWidth; i++) { piAdiTemp[1+uiCuWidth+i] = piRoiTemp[i];//!< 每个参考样点赋值为对应位置重建Yuv样点值 } } else // reference samples are partially available { Int iNumUnits2 = iNumUnitsInCu<<1;//乘以2 Int iTotalSamples = iTotalUnits*iUnitSize;//!< neighboring samples的总数iTotalUnits以4x4块为单位iUnitSize为块的大小 Pel piAdiLine[5 * MAX_CU_SIZE]; Pel *piAdiLineTemp; //!<临时存储用于填充neighboring samples的样点值 Bool *pbNeighborFlags; Int iNext, iCurr; Pel piRef = 0;//!< 存储临时样点值 // Initialize for (i=0; i<iTotalSamples; i++) //!< 先将所有样点值赋值为DC值 { piAdiLine[i] = iDCValue; } // Fill top-left sample piRoiTemp = piRoiOrigin - iPicStride - 1;//!< 指向重建Yuv左上角

piAdiLineTemp = piAdiLine + (iNumUnits2*iUnitSize);//初始指针设定,piAdiLine的扫描顺序为左下到左上再从左到右上 pbNeighborFlags = bNeighborFlags + iNumUnits2;

if (*pbNeighborFlags)//!< 如果左上角可用,则左上角4个像素点均赋值为重建Yuv左上角的样点值 { piAdiLineTemp[0] = piRoiTemp[0]; for (i=1; i<iUnitSize; i++) { piAdiLineTemp[i] = piAdiLineTemp[0];

//把左上角一个参考点拓宽成了四个点而这四个点的值均为piAdiLineTemp[0] } } // Fill left & below-left samples piRoiTemp += iPicStride;//!< piRoiTemp指向重建Yuv的左边界 if (bLMmode) { piRoiTemp --; // move the second left column } piAdiLineTemp--;//!< 从开始的piAdiLineTemp = piAdiLine + (iNumUnits2*iUnitSize),-1移动指针置左边界 pbNeighborFlags--;//!< 移动指针置左边界 for (j=0; j<iNumUnits2; j++) //!< 从左往左下扫描 { if (*pbNeighborFlags) { for (i=0; i<iUnitSize; i++) { piAdiLineTemp[-i] = piRoiTemp[i*iPicStride]; //!< 每个4x4块里的4个样点分别被赋值为对应位置的重建Yuv的样点值 } } piRoiTemp += iUnitSize*iPicStride; //!< 指针挪到下一个行(以4x4块为单位,即实际上下移了4行) piAdiLineTemp -= iUnitSize;//!< 指针下移 pbNeighborFlags--; } // Fill above & above-right samples piRoiTemp = piRoiOrigin - iPicStride;//!< piRoiTemp 指向重建Yuv的上边界 piAdiLineTemp = piAdiLine + ((iNumUnits2+1)*iUnitSize);//!< piAdiLine + (iNumUnits2*iUnitSize)为初始指针,现指向上边界 pbNeighborFlags = bNeighborFlags + iNumUnits2 + 1;//!< 指向上边界 for (j=0; j<iNumUnits2; j++)//!< 从左扫描至右上 { if (*pbNeighborFlags) { for (i=0; i<iUnitSize; i++) { piAdiLineTemp[i] = piRoiTemp[i];//!< 每个4x4块里的4个样点分别被赋值为对应位置的重建Yuv的样点值 } } piRoiTemp += iUnitSize;//!< 指针右移 piAdiLineTemp += iUnitSize;//!< 指针右移 pbNeighborFlags++;//!< 指针右移 } // Pad reference samples when necessary iCurr = 0; iNext = 1; piAdiLineTemp = piAdiLine;//!< 指向左下角(纵坐标最大的那个位置,即扫描起点) while (iCurr < iTotalUnits)//!< 遍历所有neighboring samples { if (!bNeighborFlags[iCurr]) { if(iCurr == 0)//!< 第一个点就不可用 { while (iNext < iTotalUnits && !bNeighborFlags[iNext])//!< 找到第1个可用点 { iNext++; } piRef = piAdiLine[iNext*iUnitSize];//!< 保存该可用点的样点值 // Pad unavailable samples with new value while (iCurr < iNext)//!< 使用保存下来的第一个可用点的样点值赋值给在其之前被标记为不可用的点 { for (i=0; i<iUnitSize; i++) { piAdiLineTemp[i] = piRef; } piAdiLineTemp += iUnitSize; iCurr++; } } else//!< 当前点不可用且其不是第一个点,则使用该点的前一个可用点的样点值进行赋值 { piRef = piAdiLine[iCurr*iUnitSize-1]; for (i=0; i<iUnitSize; i++) { piAdiLineTemp[i] = piRef; } piAdiLineTemp += iUnitSize; iCurr++; } } else//!< 当前点可用,继续检查下一点 { piAdiLineTemp += iUnitSize; iCurr++; } } // Copy processed samples piAdiLineTemp = piAdiLine + uiHeight + iUnitSize - 2; //!< piAdiLineTemp = (piAdiLine + 128) + 3,跳过之前对左上角扩充的3个像素点 for (i=0; i<uiWidth; i++)//!< 将最终结果拷贝到左上、上、右上边界 { piAdiTemp[i] = piAdiLineTemp[i]; } piAdiLineTemp = piAdiLine + uiHeight - 1;//!< uiHeight = uiCUHeight2 + 1 for (i=1; i<uiHeight; i++) //!< 将最终结果拷贝到左和左下边界 { piAdiTemp[i*uiWidth] = piAdiLineTemp[-i];//!< piAdiLineTemp下标为-i是因为赋值方向与实际存储方向是相反的 搜索是从左下开始,赋值是左开始 } } }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值