ALF原理介绍见博文:https://blog.csdn.net/baidu_28446365/article/details/89511554
ALF在解码过程中分为以下几个部分
为了便于理解,本文主要从解码端操作过程进行详解
首先解析亮度分量和色度分量的ALF Flag、滤波器个数以及每个class对应的FilterIdx,主体函数void HLSyntaxReader::parseAPS(APS* aps)
//解析Slice Header中的参数
void HLSyntaxReader::parseAPS(APS* aps)
{
#if ENABLE_TRACING
xTraceAPSHeader();
#endif
uint32_t code;
READ_CODE(5, code, "adaptation_parameter_set_id");
aps->setAPSId(code);
//获取ALF相关的参数
AlfSliceParam param = aps->getAlfAPSParam();
param.enabledFlag[COMPONENT_Y] = true;//亮度分量是否ALF的标志
//获取色度分量Cb和Cr是否使用ALF的标志位
int alfChromaIdc = truncatedUnaryEqProb(3); //alf_chroma_idc
param.enabledFlag[COMPONENT_Cb] = alfChromaIdc >> 1;
param.enabledFlag[COMPONENT_Cr] = alfChromaIdc & 1;
//解析滤波器种类数numLumaFilters ,最多MAX_NUM_ALF_CLASSES=25种,此处为何存在滤波器种类少于25的情况,原因在于Filter Merge技术,之后再进行介绍
xReadTruncBinCode(code, MAX_NUM_ALF_CLASSES); //number_of_filters_minus1
param.numLumaFilters = code + 1;
if (param.numLumaFilters > 1)
{
for (int i = 0; i < MAX_NUM_ALF_CLASSES; i++)
{
//解析每个种类(根据梯度和activity将4x4小块分为25个class)所对应的滤波器索引FilterIdx
xReadTruncBinCode(code, param.numLumaFilters);
//filterCoeffDeltaIdx[25]:25种class对应的FilterIdx
param.filterCoeffDeltaIdx[i] = code;
}
}
else
{
//如果只有一种滤波器,则所有4x4小块使用同一种滤波器,直接将filterCoeffDeltaIdx全部置为0,无需解析每个class对应的FilterIdx
memset(param.filterCoeffDeltaIdx, 0, sizeof(param.filterCoeffDeltaIdx));
}
alfFilter(param, false);//解析滤波器参数的主体函数,解析亮度分量的滤波器参数
if (alfChromaIdc)
{
//解析滤波器参数的主体函数,解析色度分量的滤波器参数
alfFilter(param, true);
}
aps->setAlfAPSParam(param);
xReadRbspTrailingBits();
}
25个ALF滤波器的参数存储在Slice级别,所以,先解析Slice级别的滤波器参数(filter coeff),解析滤波器参数的主体函数为void HLSyntaxReader::alfFilter()
关键点包括
void HLSyntaxReader::alfFilter( AlfSliceParam& alfSliceParam, const bool isChroma )
{
uint32_t code;
if( !isChroma )
{
//alfLumaCoeffDeltaFlag :numLumaFilters 个是否都传输了Filter Coeff(意思是有些滤波器没有传输参数)
READ_FLAG( code, "alf_luma_coeff_delta_flag" );
alfSliceParam.alfLumaCoeffDeltaFlag = code;
if( !alfSliceParam.alfLumaCoeffDeltaFlag )
{
std::memset( alfSliceParam.alfLumaCoeffFlag, true, sizeof( alfSliceParam.alfLumaCoeffFlag ) );
if( alfSliceParam.numLumaFilters > 1 )
{
//alfLumaCoeffDeltaPredictionFlag :Filter Coeff之间是否采用DPCM的方式编码(差分编码)
READ_FLAG( code, "alf_luma_coeff_delta_prediction_flag" );
alfSliceParam.alfLumaCoeffDeltaPredictionFlag = code;
}
else
{
//若滤波器种类数只有1个,那么也不存在DPCM编码方式这一做法
alfSliceParam.alfLumaCoeffDeltaPredictionFlag = 0;
}
}
else
{
alfSliceParam.alfLumaCoeffDeltaPredictionFlag = 0;
}
}
// derive maxGolombIdx,根据颜色分量获取滤波器形状,色度5x5或亮度7x7
AlfFilterShape alfShape( isChroma ? 5 : 7 );
const int maxGolombIdx = AdaptiveLoopFilter::getMaxGolombIdx( alfShape.filterType );
READ_UVLC( code, isChroma ? "alf_chroma_min_eg_order_minus1" : "alf_luma_min_eg_order_minus1" );
int kMin = code + 1;
static int kMinTab[MAX_NUM_ALF_COEFF];
//滤波器种类数numFilters ,色度统一使用一个滤波器,亮度分量根据解析的参数赋值
const int numFilters = isChroma ? 1 : alfSliceParam.numLumaFilters;
short* coeff = isChroma ? alfSliceParam.chromaCoeff : alfSliceParam.lumaCoeff;
for( int idx = 0; idx < maxGolombIdx; idx++ )
{
READ_FLAG( code, isChroma ? "alf_chroma_eg_order_increase_flag" : "alf_luma_eg_order_increase_flag" );
CHECK( code > 1, "Wrong golomb_order_increase_flag" );
kMinTab[idx] = kMin + code;
kMin = kMinTab[idx];
}
if( !isChroma )
{
if( alfSliceParam.alfLumaCoeffDeltaFlag )
//如果numLumaFilters个滤波器均传输了Filter Coeff,获取某个滤波器是否传输Filter Coeff
{
for( int ind = 0; ind < alfSliceParam.numLumaFilters; ++ind )
{
READ_FLAG( code, "alf_luma_coeff_flag[i]" );
alfSliceParam.alfLumaCoeffFlag[ind] = code;//第ind个滤波器是否传输了Filter Coeff
}
}
}
// Filter coefficients
for( int ind = 0; ind < numFilters; ++ind )//逐个解析滤波器参数
{
if( !isChroma && !alfSliceParam.alfLumaCoeffFlag[ind] && alfSliceParam.alfLumaCoeffDeltaFlag )
//若亮度分量情况下,不是numLumaFilters个都传输了Filter Coeff,且第ind个滤波器未传输Filter Coeff,则直接将当前Filter Coeff置0
{
memset( coeff + ind * MAX_NUM_ALF_LUMA_COEFF, 0, sizeof( *coeff ) * alfShape.numCoeff );
continue;
}
for( int i = 0; i < alfShape.numCoeff - 1; i++ )
//否则,解析Filter Coeff
{
//熵解码滤波器参数
coeff[ind * MAX_NUM_ALF_LUMA_COEFF + i] = alfGolombDecode( kMinTab[alfShape.golombIdx[i]] );
}
}
}
函数调用流程如下图所示,decode()
函数会调用DecLib::executeLoopFilters()
函数,其中又调用所有进行滤波操作的函数:loopFilterPic()
进行DF去除方块效应、LMCS、SAOProcess()
进行SAO操作减小图像的失真、ALFProcess()
进行ALF操作。
void DecLib::executeLoopFilters()
{
if( !m_pcPic )
{
return; // nothing to deblock
}
CodingStructure& cs = *m_pcPic->cs;
//LMCS相关操作
if (cs.sps->getUseReshaper() && m_cReshaper.getSliceReshaperInfo().getUseSliceReshaper())
{
CHECK((m_cReshaper.getRecReshaped() == false), "Rec picture is not reshaped!");
m_pcPic->getRecoBuf(COMPONENT_Y).rspSignal(m_cReshaper.getInvLUT());
m_cReshaper.setRecReshaped(false);
m_cSAO.setReshaper(&m_cReshaper);
}
// deblocking filter
m_cLoopFilter.loopFilterPic( cs );//DF
CS::setRefinedMotionField(cs);
if( cs.sps->getSAOEnabledFlag() )
{ //SAO过程
m_cSAO.SAOProcess( cs, cs.picture->getSAO() );
}
if( cs.sps->getALFEnabledFlag() )
{
if (cs.slice->getTileGroupAlfEnabledFlag())
{
// ALF decodes the differentially coded coefficients and stores them in the parameters structure.
// Code could be restructured to do directly after parsing. So far we just pass a fresh non-const
// copy in case the APS gets used more than once.
//ALF过程
AlfSliceParam alfParamCopy = cs.aps->getAlfAPSParam();
m_cALF.ALFProcess(cs, alfParamCopy);
}
}
}
ALF滤波主体函数是m_cALF.ALFProcess()
void AdaptiveLoopFilter::ALFProcess( CodingStructure& cs, AlfSliceParam& alfSliceParam )
{
if( !alfSliceParam.enabledFlag[COMPONENT_Y] && !alfSliceParam.enabledFlag[COMPONENT_Cb] && !alfSliceParam.enabledFlag[COMPONENT_Cr] )
{
return;
}
// set available filter shapes
alfSliceParam.filterShapes = m_filterShapes;
// set clipping range
m_clpRngs = cs.slice->getClpRngs();
// set CTU enable flags,CTU级别的Flag
for( int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++ )
{
m_ctuEnableFlag[compIdx] = cs.picture->getAlfCtuEnableFlag( compIdx );
}
//根据Slice级别解析的滤波器参数重建Filter Coefficient
reconstructCoeff( alfSliceParam, CHANNEL_TYPE_LUMA );
reconstructCoeff( alfSliceParam, CHANNEL_TYPE_CHROMA );
PelUnitBuf recYuv = cs.getRecoBuf();
m_tempBuf.copyFrom( recYuv );
PelUnitBuf tmpYuv = m_tempBuf.getBuf( cs.area );
//为了对边缘像素进行滤波,需要将边缘扩展(例如:滤波器形状为7x7,则需要每一边扩展7/2=3个像素点)
tmpYuv.extendBorderPel( MAX_ALF_FILTER_LENGTH >> 1 );
const PreCalcValues& pcv = *cs.pcv;
int ctuIdx = 0;
for( int yPos = 0; yPos < pcv.lumaHeight; yPos += pcv.maxCUHeight )
{
for( int xPos = 0; xPos < pcv.lumaWidth; xPos += pcv.maxCUWidth )
{
const int width = ( xPos + pcv.maxCUWidth > pcv.lumaWidth ) ? ( pcv.lumaWidth - xPos ) : pcv.maxCUWidth;
const int height = ( yPos + pcv.maxCUHeight > pcv.lumaHeight ) ? ( pcv.lumaHeight - yPos ) : pcv.maxCUHeight;
const UnitArea area( cs.area.chromaFormat, Area( xPos, yPos, width, height ) );
if( m_ctuEnableFlag[COMPONENT_Y][ctuIdx] )
{
Area blk( xPos, yPos, width, height );
//获取4x4小块的类别(class)
deriveClassification( m_classifier, tmpYuv.get( COMPONENT_Y ), blk );
Area blkPCM(xPos, yPos, width, height);
resetPCMBlkClassInfo(cs, m_classifier, tmpYuv.get(COMPONENT_Y), blkPCM);
//对亮度分量进行滤波
m_filter7x7Blk(m_classifier, recYuv, tmpYuv, blk, COMPONENT_Y, m_coeffFinal, m_clpRngs.comp[COMPONENT_Y], cs );
}
for( int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ )
{
ComponentID compID = ComponentID( compIdx );
const int chromaScaleX = getComponentScaleX( compID, tmpYuv.chromaFormat );
const int chromaScaleY = getComponentScaleY( compID, tmpYuv.chromaFormat );
if( m_ctuEnableFlag[compIdx][ctuIdx] )
{
Area blk( xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY );
//对色度分量进行滤波
m_filter5x5Blk( m_classifier, recYuv, tmpYuv, blk, compID, alfSliceParam.chromaCoeff, m_clpRngs.comp[compIdx], cs );
}
}
ctuIdx++;
}
}
}
重建滤波器系数主体函数void AdaptiveLoopFilter::reconstructCoeff( )
void AdaptiveLoopFilter::reconstructCoeff( AlfSliceParam& alfSliceParam, ChannelType channel, const bool bRedo )
{
int factor = ( 1 << ( m_NUM_BITS - 1 ) );
AlfFilterType filterType = isLuma( channel ) ? ALF_FILTER_7 : ALF_FILTER_5;
int numClasses = isLuma( channel ) ? MAX_NUM_ALF_CLASSES : 1;
int numCoeff = filterType == ALF_FILTER_5 ? 7 : 13;
int numCoeffMinus1 = numCoeff - 1;
int numFilters = isLuma( channel ) ? alfSliceParam.numLumaFilters : 1;
short* coeff = isLuma( channel ) ? alfSliceParam.lumaCoeff : alfSliceParam.chromaCoeff;
if( alfSliceParam.alfLumaCoeffDeltaPredictionFlag && isLuma( channel ) )
{
for( int i = 1; i < numFilters; i++ )
{
for( int j = 0; j < numCoeffMinus1; j++ )
{
//Filter Coefficient采用DPCM编码方式
coeff[i * MAX_NUM_ALF_LUMA_COEFF + j] += coeff[( i - 1 ) * MAX_NUM_ALF_LUMA_COEFF + j];
}
}
}
for( int filterIdx = 0; filterIdx < numFilters; filterIdx++ )
{
int sum = 0;
for( int i = 0; i < numCoeffMinus1; i++ )
{
sum += ( coeff[filterIdx* MAX_NUM_ALF_LUMA_COEFF + i] << 1 );
}
coeff[filterIdx* MAX_NUM_ALF_LUMA_COEFF + numCoeffMinus1] = factor - sum;
}
if( isChroma( channel ) )
{
return;
}
//为各个种类(共25种)的像素分配滤波器系数
for( int classIdx = 0; classIdx < numClasses; classIdx++ )
{
int filterIdx = alfSliceParam.filterCoeffDeltaIdx[classIdx];
memcpy( m_coeffFinal + classIdx * MAX_NUM_ALF_LUMA_COEFF, coeff + filterIdx * MAX_NUM_ALF_LUMA_COEFF, sizeof( short ) * numCoeff );
}
if( bRedo && alfSliceParam.alfLumaCoeffDeltaPredictionFlag )
{
for( int i = numFilters - 1; i > 0; i-- )
{
for( int j = 0; j < numCoeffMinus1; j++ )
{
coeff[i * MAX_NUM_ALF_LUMA_COEFF + j] = coeff[i * MAX_NUM_ALF_LUMA_COEFF + j] - coeff[( i - 1 ) * MAX_NUM_ALF_LUMA_COEFF + j];
}
}
}
}
注:本文代码为VTM4.0版本