H.266/VVC代码学习笔记3:带你解析VTM5.0中CCLM的代码实现细节

昨天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;
  }

性能增益如下:
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值