昨天VVC新的参考软件VTM5.0正式发布啦,其中对于CCLM部分的改动还是挺大的。接下来我来详细讲讲改动的地方,并且讲一下具体的代码实现细节,希望对大家理解有所帮助~
首先,VTM4.0中的CCLM是通过对所有的相邻参考像素去搜寻一个亮度最小点和一个亮度最大点,通过这两个点去拟合线性模型。
如今的VTM5.0中的CCLM现在只从相邻参考像素中总共找四个点或者两个点,如果是四个点的情况,则先进行排序,找出其中亮度较小的两个点或者亮度较大的两个点,然后分别对两个亮度最小点和两个亮度最大点再求一次平均得到一个最小点和一个最大点,再去通过这两个点拟合一条线性模型。

相比VTM4.0,5.0中的CCLM复杂度得到了大幅的降低,并且性能还有所提升。下面是具体的代码,我都有详细的注释,供大家参考
#if JVET_N0271_SIMPLFIED_CCLM
int startPos[2]; //0:Above, 1: Left
int pickStep[2];
int aboveIs4 = leftAvailable ? 0 : 1;
int leftIs4 = aboveAvailable ? 0 : 1;
startPos[0] = actualTopTemplateSampNum >> (2 + aboveIs4);//上一行选点的起始点
pickStep[0] = std::max(1, actualTopTemplateSampNum >> (1 + aboveIs4));//上一行选点的跳跃步长
startPos[1] = actualLeftTemplateSampNum >> (2 + leftIs4);//左一列选点的起始点
pickStep[1] = std::max(1, actualLeftTemplateSampNum >> (1 + leftIs4));//左一列选点的跳跃步长
Pel selectLumaPix[4];//保存选好的点的亮度值
Pel selectChromaPix[4];//保存选好的点的色度值
int minLuma[2] = { MAX_INT,0 };//保存最后计算出的最小点
int maxLuma[2] = { -MAX_INT,0 };//保存最后计算出的最大点
int cntT, cntL;//分别保存上一行和左一列中选出的样本点数
cntT = cntL = 0;//初始化为0
int cnt = 0;
if (aboveAvailable)//如果上一行是有效行
{
cntT = std::min(actualTopTemplateSampNum, (1 + aboveIs4) << 1);
src = srcColor0 - srcStride;//重建亮度指针指向上相邻行的首地址
cur = curChroma0 - curStride;//重建色度指针指向上相邻行的首地址
for (int pos = startPos[0]; cnt < cntT; pos += pickStep[0], cnt++)//循环选点,分别保存选好的参考像素的色度亮度值
{
selectLumaPix[cnt] = src[pos];
selectChromaPix[cnt] = cur[pos];
}
}
if (leftAvailable)//如果左一列是有效行,进行同样的操作
{
cntL = std::min(actualLeftTemplateSampNum, ( 1 + leftIs4 ) << 1 );
src = srcColor0 - 1;
cur = curChroma0 - 1;
for (int pos = startPos[1], cnt = 0; cnt < cntL; pos += pickStep[1], cnt++)
{
selectLumaPix[cnt + cntT] = src[pos * srcStride];
selectChromaPix[cnt+ cntT] = cur[pos * curStride];
}
}
cnt = cntL + cntT;//最后将上和左的选点的总数求和得到所有的选点个数,要么是4,2或者0。
if (cnt == 2)//如果总共选到了两个点,则将两个点扩充成四个点,其实这里的操作就是复制出来两个完全一样的点,目的就是为了后面的统一计算和比较
{
selectLumaPix[3] = selectLumaPix[0]; selectChromaPix[3] = selectChromaPix[0];
selectLumaPix[2] = selectLumaPix[1]; selectChromaPix[2] = selectChromaPix[1];
selectLumaPix[0] = selectLumaPix[1]; selectChromaPix[0] = selectChromaPix[1];
selectLumaPix[1] = selectLumaPix[3]; selectChromaPix[1] = selectChromaPix[3];
}
int minGrpIdx[2] = { 0, 2 };
int maxGrpIdx[2] = { 1, 3 };
int *tmpMinGrp = minGrpIdx;//保存两个亮度较小的点
int *tmpMaxGrp = maxGrpIdx;//保存两个亮度较大的点
if (selectLumaPix[tmpMinGrp[0]] > selectLumaPix[tmpMinGrp[1]]) std::swap(tmpMinGrp[0], tmpMinGrp[1]);//这里进行四次比较,找出四个点中的两个亮度较小的值和两个亮度较大的值
if (selectLumaPix[tmpMaxGrp[0]] > selectLumaPix[tmpMaxGrp[1]]) std::swap(tmpMaxGrp[0], tmpMaxGrp[1]);
if (selectLumaPix[tmpMinGrp[0]] > selectLumaPix[tmpMaxGrp[1]]) std::swap(tmpMinGrp, tmpMaxGrp);
if (selectLumaPix[tmpMinGrp[1]] > selectLumaPix[tmpMaxGrp[0]]) std::swap(tmpMinGrp[1], tmpMaxGrp[0]);
minLuma[0] = (selectLumaPix[tmpMinGrp[0]] + selectLumaPix[tmpMinGrp[1]] + 1 )>>1;//对两个较小的点求平均得到一个最小点
minLuma[1] = (selectChromaPix[tmpMinGrp[0]] + selectChromaPix[tmpMinGrp[1]] + 1) >> 1;
maxLuma[0] = (selectLumaPix[tmpMaxGrp[0]] + selectLumaPix[tmpMaxGrp[1]] + 1 )>>1;//对两个较大的点求平均得到一个最大点
maxLuma[1] = (selectChromaPix[tmpMaxGrp[0]] + selectChromaPix[tmpMaxGrp[1]] + 1) >> 1;
#endif
if (leftAvailable || aboveAvailable)
{
int diff = maxLuma[0] - minLuma[0];//这里就是开始求参数a和b了,具体很复杂就不详细介绍,想了解的可以私信我
if (diff > 0)
{
int diffC = maxLuma[1] - minLuma[1];
int x = floorLog2( diff );
static const uint8_t DivSigTable[1 << 4] = {
// 4bit significands - 8 ( MSB is omitted )
0, 7, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 1, 1, 0
};
int normDiff = (diff << 4 >> x) & 15;
int v = DivSigTable[normDiff] | 8;
x += normDiff != 0;
int y = floorLog2( abs( diffC ) ) + 1;
int add = 1 << y >> 1;
a = (diffC * v + add) >> y;
iShift = 3 + x - y;
if ( iShift < 1 ) {
iShift = 1;
a = ( (a == 0)? 0: (a < 0)? -15 : 15 ); // a=Sign(a)*15
}
b = minLuma[1] - ((a * minLuma[0]) >> iShift);
}
else
{
a = 0;
b = minLuma[1];
iShift = 0;
}
}
else
{
a = 0;
b = 1 << (internalBitDepth - 1);
iShift = 0;
}
性能增益如下:


2262

被折叠的 条评论
为什么被折叠?



