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

155 篇文章 138 订阅
66 篇文章 24 订阅

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。

双线性滤波如下所示:

相关参数由下表给出:

当下面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中滤波开关决策和强滤波决策一样。

色度强滤波操作如下:

相关代码实现如下:

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

 

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
去块滤波(Deblock)是视频编码中的一种技术,用于减少压缩后图像的块状伪影和边界伪影。在VVC编码标准中,去块滤波是以CU(Coding Unit)为单元进行的。具体的去块滤波过程如下: 1. 首先,通过设置边界是否可用去块滤波,确定需要进行滤波的边界。这些边界包括内部子块边界、左侧边界和上侧边界。 2. 然后,遍历CU中的全部子TU(Transform Unit),设置子TU的垂直和水平边界,并根据边界长度确定需要进行滤波的像素数。 3. 接下来,遍历CU中的全部子PU(Prediction Unit),进行类似的边界设置过程。 4. 针对每个需要进行滤波的边界,先对边界进行排序,然后调用相应的滤波函数进行滤波滤波过程包括对亮度分量和色度分量的滤波。 总的来说,去块滤波通过对CU、TU和PU进行边界设置,并调用相应的滤波函数对边界进行滤波,以减少压缩后图像的块状伪影和边界伪影。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *3* [H.266/VVC技术学习之环路滤波:去块滤波(Deblock)技术](https://blog.csdn.net/BigDream123/article/details/115016745)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [H.266/VVC代码学习:去块滤波Deblock代码一](https://blog.csdn.net/BigDream123/article/details/115974424)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值