本文共 5329 字,大约阅读时间需要 17 分钟。
下表定义了各个预测模式与方向角度差之间的一一对应关系。角度差用参数A表示,在生成参考像素时会作为获取参考数据的依据。
对于负角度,左侧和上方的参考像素都会被使用到,此时参考数组中的非负索引的元素依旧如前文所述,负索引值所表示的像素通过映射获得,公式如下:
其中B与角度参数A的对应关系如下表:
这部分该如何理解呢?以下两张图分别是正向角度的垂直模式/水平模式的方向示意图:
对于不同的预测方向,预测块所使用的预测数据时不同的。由于预测像素的组织形式是一个一维数组,以顶点像素为中心向两边扩展。在正向角度预测时,只需要或正方向或负方向的预测数据级就可以为预测块进行赋值。而对于负向角度,情况将有所不同。下图表示负向角度下的预测方向示意图:
举例,当mode为2时,预测方向为右上方对角线。处理代码如下:
Void TComPrediction::xPredIntraAng(Int bitDepth, Int* pSrc, Int srcStride, Pel*& rpDst, Int dstStride, UInt width, UInt height, UInt dirMode, Bool blkAboveAvailable, Bool blkLeftAvailable, Bool bFilter ){ //...... // Map the mode index to main prediction direction and angle assert( dirMode > 0 ); //no planar Bool modeDC = dirMode < 2;//对于mode2,显然不是DC模式 Bool modeHor = !modeDC && (dirMode < 18);//mode2小于18,因此属于水平类 Bool modeVer = !modeDC && !modeHor;//mode11不属于垂直类 Int intraPredAngle = modeVer ? (Int)dirMode - VER_IDX/*26*/ : modeHor ? -((Int)dirMode - HOR_IDX/*10*/) : 0;//计算索引差值,值为8 Int absAng = abs(intraPredAngle);//绝对值为8 Int signAng = intraPredAngle < 0 ? -1 : 1;//符号位正 //......}而后,模式的索引差将转换为角度偏移差:
// Set bitshifts and scale the angle parameter to block size Int angTable[9] = {0, 2, 5, 9, 13, 17, 21, 26, 32}; Int invAngTable[9] = {0, 4096, 1638, 910, 630, 482, 390, 315, 256}; // (256 * 32) / Angle Int invAngle = invAngTable[absAng]; absAng = angTable[absAng];//将模式索引差值转换为角度偏移差 intraPredAngle = signAng * absAng;intraPredAngle这个变量中就保存了当前模式同水平/垂直模式映射到边界上的偏移值,精度为1/32像素。如果该参数为正,那么将当前预测块的上方和左方预测像素复制到两个数组中,并依据当前模式的方向分类确定哪一个作为主要参考哪一个作为辅助参考:
// Initialise the Main and Left reference array. if (intraPredAngle < 0) { // 角度差为负 //...... } else { // 角度差为正 for (k=0;k<2*blkSize+1;k++) { refAbove[k] = pSrc[k-srcStride-1];//复制上方参考像素 } for (k=0;k<2*blkSize+1;k++) { refLeft[k] = pSrc[(k-1)*srcStride-1];//复制左侧参考像素 } refMain = modeVer ? refAbove : refLeft;//mode2属于水平类,因此refMain为refLeft,refSide为refAbove。 refSide = modeVer ? refLeft : refAbove; }当对于mode11时,情况将有所不同。
Bool modeDC = dirMode < 2;//mode11非DC模式 Bool modeHor = !modeDC && (dirMode < 18);//mode11属于水平类 Bool modeVer = !modeDC && !modeHor; Int intraPredAngle = modeVer ? (Int)dirMode - VER_IDX/*26*/ : modeHor ? -((Int)dirMode - HOR_IDX/*10*/) : 0;//模式索引差为-1 Int absAng = abs(intraPredAngle); Int signAng = intraPredAngle < 0 ? -1 : 1; // Set bitshifts and scale the angle parameter to block size Int angTable[9] = {0, 2, 5, 9, 13, 17, 21, 26, 32}; Int invAngTable[9] = {0, 4096, 1638, 910, 630, 482, 390, 315, 256}; // (256 * 32) / Angle Int invAngle = invAngTable[absAng]; absAng = angTable[absAng];//将模式索引差值转换为角度偏移差 intraPredAngle = signAng * absAng;//最终计算得到的角度差为-2mode11的预测方向为水平向右,并略带向右下方倾斜,其参考的像素大部分为左侧像素,同时也会用到几个上方的像素。具体所需的像素个数为块尺寸×角度差参数A的绝对值÷32,对于64×64的mode11就是64×2÷32=4。这几个值从refSide中每隔M个像素取一个,M的取值为invAngle的取值除以256。实现方法如下:
if (intraPredAngle < 0) { for (k=0;kblkSize*intraPredAngle>>5; k--) { invAngleSum += invAngle; refMain[k] = refSide[invAngleSum>>8];//挑选某几个参考像素进行拷贝 } }
if (intraPredAngle == 0) {//水平或者垂直模式 for (k=0;k> 5; deltaFract = deltaPos & (32 - 1); if (deltaFract) { // Do linear filtering for (l=0;l > 5 );//亚像素预测,从两个相邻像素中获取加权均值 } } else { // Just copy the integer samples for (l=0;l
水平方向的预测结果Ph[x][y]和垂直方向上的预测结果Pv[x][y]按照以下方法生成:
对于水平模式,操作类似。 对于DC模式,需要根据原预测像素的位置分为三种情况: