环路滤波(三):VVC去方块滤波改进

H.266/VVC中去方块滤波改进

VVC中,去方块滤波和HEVC过程类似,主要有以下几个方面改进:

  1. 滤波强度依赖于重建像素的平均亮度级。

  2. tc表有了扩展。

  3. 亮度强滤波有了改进。

  4. 增加了色度强滤波。

依赖重建像素平均亮度级的滤波强度

在HEVC中滤波强度由beta和tc决定,而beta和tc是由平均量化参数QP_L生成。在VVC中为QP_L增加一个偏移值,偏移量由重建像素的平均亮度级LL决定。

QP_L计算中比HEVC增加了一个偏移值如下:

qpOffset是偏移值,由LL决定。

下面是通过平均亮度级LL计算偏移值的方法:

void LoopFilter::deriveLADFShift( const Pel* src, const int stride, int& shift, const DeblockEdgeDir edgeDir, const SPS sps )
{
  uint32_t lumaLevel = 0;
  shift = sps.getLadfQpOffset(0);
  //!<计算平均亮度级
  if (edgeDir == EDGE_VER)
  {
    lumaLevel = (src[0] + src[3*stride] + src[-1] + src[3*stride - 1]) >> 2;
  }
  else // (edgeDir == EDGE_HOR)
  {
    lumaLevel = (src[0] + src[3] + src[-stride] + src[-stride + 3]) >> 2;
  }

  for ( int k = 1; k < sps.getLadfNumIntervals(); k++ )
  {
    const int th = sps.getLadfIntervalLowerBound( k );
    if ( lumaLevel > th )
    {
      shift = sps.getLadfQpOffset( k );
    }
    else
    {
      break;
    }
  }
}
#endif
#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET
      if ( sps.getLadfEnabled() )
      {
        int iShift = 0;
        deriveLADFShift( piTmpSrc + iSrcStep * (iIdx*pelsInPart), iStride, iShift, edgeDir, sps );
        iQP += iShift; //!<根据重建像素的平均亮度级LL增加偏移值
      }
#endif

tc表扩展

在VVC中最大QP变为63,与之对应tc表要进行相应扩展。

tC = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8,  9,10,11,13,14,16, 18,20,22,25,28,31,35,39,44,50,56,63,70,79,88,99 ]

const uint8_t LoopFilter::sm_tcTable[MAX_QP + 1 + DEFAULT_INTRA_TC_OFFSET] =
{
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,5,5,6,6,7,8,9,10,11,13,14,16,18,20,22,25, 28, 31, 35, 39, 44, 50, 56, 63, 70,79, 88, 99
};

const uint8_t LoopFilter::sm_betaTable[MAX_QP + 1] =
{
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88
};

亮度强滤波

当边界任一侧像素属于一个“大块”时使用双线性滤波器。像素属于大块的定义是边界长度大于等于32。

双线性滤波如下所示:

环路滤波(三):VVC去方块滤波改进_第1张图片

相关参数由下表给出:

环路滤波(三):VVC去方块滤波改进_第2张图片

环路滤波(三):VVC去方块滤波改进_第3张图片

当下面3个条件都满足时可以使用双线性滤波:

条件1:边界任一侧像素属于一个“大块”。

条件2:

条件3:

是否使用双线性滤波判断条件实现如下:

inline bool LoopFilter::xUseStrongFiltering( Pel* piSrc, const int iOffset, const int d, const int beta, const int tc, bool sidePisLarge, bool sideQisLarge, int maxFilterLengthP, int maxFilterLengthQ ) const
{
  const Pel m4 = piSrc[ 0          ];
  const Pel m3 = piSrc[-iOffset    ];
  const Pel m7 = piSrc[ iOffset * 3];
  const Pel m0 = piSrc[-iOffset * 4];
  int       sp3      = abs(m0 - m3);
  int       sq3      = abs(m7 - m4);
  const int d_strong = sp3 + sq3;

  if (sidePisLarge || sideQisLarge)
  {
    Pel mP4;
    Pel m11;
    if (maxFilterLengthP == 5)
    {
      mP4 = piSrc[-iOffset * 6];
    }
    else
    {
      mP4 = piSrc[-iOffset * 8];
    }
    if (maxFilterLengthQ == 5)
    {
      m11 = piSrc[iOffset * 5];
    }
    else
    {
      m11 = piSrc[iOffset * 7];
    }

    if (sidePisLarge)
    {
      sp3 = (sp3 + abs(m0 - mP4) + 1) >> 1;
    }
    if (sideQisLarge)
    {
      sq3 = (sq3 + abs(m11 - m7) + 1) >> 1;
    }
    return ((sp3 + sq3) < (beta*3 >> 5)) && (d < (beta >> 2)) && (abs(m3 - m4) < ((tc * 5 + 1) >> 1));
  }
  else
  return ( ( d_strong < ( beta >> 3 ) ) && ( d < ( beta >> 2 ) ) && ( abs( m3 - m4 ) < ( ( tc * 5 + 1 ) >> 1 ) ) );
}

双线性滤波代码实现如下:

/**
 - Deblocking for the luminance component with strong or weak filter
 .
 \param piSrc           pointer to picture data
 \param iOffset         offset value for picture data
 \param tc              tc value
 \param sw              decision strong/weak filter
 \param bPartPNoFilter  indicator to disable filtering on partP
 \param bPartQNoFilter  indicator to disable filtering on partQ
 \param iThrCut         threshold value for weak filter decision
 \param bFilterSecondP  decision weak filter/no filter for partP
 \param bFilterSecondQ  decision weak filter/no filter for partQ
 \param bitDepthLuma    luma bit depth
*/
inline void LoopFilter::xBilinearFilter(Pel* srcP, Pel* srcQ, int offset, int refMiddle, int refP, int refQ, int numberPSide, int numberQSide, const int* dbCoeffsP, const int* dbCoeffsQ, int tc) const
{
    int src;
    const char tc7[7] = { 6, 5, 4, 3, 2, 1, 1};
    const char tc3[3] = { 6, 4, 2 };
    const char *tcP  = (numberPSide == 3) ? tc3 : tc7;
    const char *tcQ  = (numberQSide == 3) ? tc3 : tc7;
    for (int pos = 0; pos < numberPSide; pos++)
    {
      src = srcP[-offset*pos];
      int cvalue = (tc * tcP[pos]) >>1;
      srcP[-offset * pos] = Clip3(src - cvalue, src + cvalue, ((refMiddle*dbCoeffsP[pos] + refP * (64 - dbCoeffsP[pos]) + 32) >> 6));
    }
    for (int pos = 0; pos < numberQSide; pos++)
    {
      src = srcQ[offset*pos];
      int cvalue = (tc * tcQ[pos]) >> 1;
      srcQ[offset*pos] = Clip3(src - cvalue, src + cvalue, ((refMiddle*dbCoeffsQ[pos] + refQ * (64 - dbCoeffsQ[pos]) + 32) >> 6));
    }
}

色度强滤波

当色度边界长度大于等于8,且满足下面3个条件时,色度边界使用强滤波。(1)边界强度和大块条件。VVC中色度边界强度计算如下表,当高优先级条件满足时不再检查低优先级条件。当BS=2或BS=1且边界属于一个大块时才进行滤波。条件(2)(3)分别和HEVC中滤波开关决策和强滤波决策一样。

环路滤波(三):VVC去方块滤波改进_第4张图片

色度强滤波操作如下:

相关代码实现如下:

inline void LoopFilter::xPelFilterChroma( Pel* piSrc, const int iOffset, const int tc, const bool sw, const bool bPartPNoFilter, const bool bPartQNoFilter, const ClpRng& clpRng, const bool largeBoundary ) const
{
  int delta;

  const Pel m0 = piSrc[-iOffset * 4];
  const Pel m1 = piSrc[-iOffset * 3];
  const Pel m2 = piSrc[-iOffset * 2];
  const Pel m3 = piSrc[-iOffset];
  const Pel m4 = piSrc[0];
  const Pel m5 = piSrc[iOffset];
  const Pel m6 = piSrc[iOffset * 2];
  const Pel m7 = piSrc[iOffset * 3];

  if (sw)
  {//!<色度强滤波
      piSrc[-iOffset * 3] = Clip3(m1 - tc, m1 + tc, ((3 * m0 + 2 * m1 + m2 + m3 + m4 + 4) >> 3));       // p2
      piSrc[-iOffset * 2] = Clip3(m2 - tc, m2 + tc, ((2 * m0 + m1 + 2 * m2 + m3 + m4 + m5 + 4) >> 3));  // p1
      piSrc[-iOffset * 1] = Clip3(m3 - tc, m3 + tc, ((m0 + m1 + m2 + 2 * m3 + m4 + m5 + m6 + 4) >> 3)); // p0
      piSrc[0]            = Clip3(m4 - tc, m4 + tc, ((m1 + m2 + m3 + 2 * m4 + m5 + m6 + m7 + 4) >> 3)); // q0
      piSrc[iOffset * 1]  = Clip3(m5 - tc, m5 + tc, ((m2 + m3 + m4 + 2 * m5 + m6 + 2 * m7 + 4) >> 3));  // q1
      piSrc[iOffset * 2]  = Clip3(m6 - tc, m6 + tc, ((m3 + m4 + m5 + 2 * m6 + 3 * m7 + 4) >> 3));       // q2
  }
  else
  {
      delta = Clip3(-tc, tc, ((((m4 - m3) << 2) + m2 - m5 + 4) >> 3));
      piSrc[-iOffset] = ClipPel(m3 + delta, clpRng);
      piSrc[0] = ClipPel(m4 - delta, clpRng);
  }


  if( bPartPNoFilter )
  {
    if (largeBoundary)
    {
      piSrc[-iOffset * 3] = m1; // p2
      piSrc[-iOffset * 2] = m2; // p1
    }
    piSrc[-iOffset] = m3;
  }
  if( bPartQNoFilter )
  {
    if (largeBoundary)
    {
      piSrc[iOffset * 1] = m5; // q1
      piSrc[iOffset * 2] = m6; // q2
    }
    piSrc[ 0      ] = m4;
  }
}

感兴趣的请关注微信公众号Video Coding

环路滤波(三):VVC去方块滤波改进_第5张图片

 

你可能感兴趣的:(H.266/VVC,h.265/hevc,视频编码)