作者:66
1. 理论部分--快速率失真计算方法:
在后面的代码中用到了,在此说明一下方便后面的理解:
率失真(J) = 像素误差(D)+语法编码代价(λR),R是编码所需bit,λ是系数。
其中像素误差可以有MSE(最小均方误差)、MAD(最小平均绝对误差)等。这里用的MSE,即原始像素与重构像素的差值平方和。
以org代表原始像素,rec代表重构像素,offset为补偿值,则有:
补偿前:
补偿后:
补偿前后的误差:
上式中N为像素个数,因此率失真差值为:
可以看出计算差值J比计算J少了约N次对差值进行平方的计算,因此选最优时只需要对比差值J即可。
2.补充:
昨天剩下的两个函数,saoCOmponentParamDist中,计算过EO、BO模式后的merge与mergeup是计算取邻块SAO模式的率失真,也就是说,函数saoComponentParamDist计算并记录了EO、BO模式下最优模式,但并未在此函数中与融合模式进行对比,具体的对比在调用saoCOmponentParamDist的函数rdoSaoUnitAll的后半部分。
图一、本文涉及的代码结构(标红部分)
saoCOmponentParamDist中计算merge率失真的代码:
// merge left or merge up
for (Int idxNeighbor=0;idxNeighbor<2;idxNeighbor++)
{
saoLcuParamNeighbor = NULL;
if (allowMergeLeft && addrLeft>=0 && idxNeighbor ==0)//!< 左邻块可用
{
saoLcuParamNeighbor = &(saoParam->saoLcuParam[yCbCr][addrLeft]);//!< 取左邻块的SAO参数
}
else if (allowMergeUp && addrUp>=0 && idxNeighbor ==1)//!< 上邻块可用
{
saoLcuParamNeighbor = &(saoParam->saoLcuParam[yCbCr][addrUp]);//!< 取上邻块的SAO参数
}
if (saoLcuParamNeighbor!=NULL)
{
estDist = 0;
typeIdx = saoLcuParamNeighbor->typeIdx;//取邻块的SAO模式
if (typeIdx>=0)
{
Int mergeBandPosition = (typeIdx == SAO_BO)?saoLcuParamNeighbor->subTypeIdx:0;
Int merge_iOffset;
for(classIdx = 0; classIdx < m_iNumClass[typeIdx]; classIdx++)
{
merge_iOffset = saoLcuParamNeighbor->offset[classIdx];
estDist += estSaoDist(m_iCount [yCbCr][typeIdx][classIdx+mergeBandPosition+1], merge_iOffset, m_iOffsetOrg[yCbCr][typeIdx][classIdx+mergeBandPosition+1], shift);
}
}
else
{
estDist = 0;
}
copySaoUnit(&compSaoParam[idxNeighbor], saoLcuParamNeighbor );
compSaoParam[idxNeighbor].mergeUpFlag = idxNeighbor;
compSaoParam[idxNeighbor].mergeLeftFlag = !idxNeighbor;
compDistortion[idxNeighbor+1] += ((Double)estDist/lambda);
}
}
}
其中调用了计算率失真的函数estSaoDist,函数定义为:
inline Int64 TEncSampleAdaptiveOffset::estSaoDist(Int64 count, Int64 offset, Int64 offsetOrg, Int shift)
{
return (( count*offset*offset-offsetOrg*offset*2 ) >> shift);
}
这个函数用的是SAO率失真的快速计算方法,其中return (( count*offset*offset-offsetOrg*offset*2 ) >> shift);对应于公式
具体解析看前理论部分。
前面说过,merge模式参与率失真的比较在rdoSaoUnitAll函数后半部分,下面贴后半部分代码:
//计算亮度和色度模式下的参数融合率失真
if( saoParam->bSaoFlag[0] || saoParam->bSaoFlag[1] )
{
// Cost of new SAO_params初始化参数
m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[0][CI_CURR_BEST]);
m_pcRDGoOnSbacCoder->resetBits();
if (allowMergeLeft)
{
m_pcEntropyCoder->m_pcEntropyCoderIf->codeSaoMerge(0);
}
if (allowMergeUp)
{
m_pcEntropyCoder->m_pcEntropyCoderIf->codeSaoMerge(0);
}
for ( compIdx=0;compIdx<3;compIdx++)
{
if( (compIdx ==0 && saoParam->bSaoFlag[0]) || (compIdx >0 && saoParam->bSaoFlag[1]))
{
m_pcEntropyCoder->encodeSaoOffset(&saoParam->saoLcuParam[compIdx][addr], compIdx);
//cost of merge
}
}
rate = m_pcEntropyCoder->getNumberOfWrittenBits();
bestCost = compDistortion[0] + (Double)rate;
m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[0][CI_TEMP_BEST]);
//计算参数融合模式下的率失真
for(Int mergeUp=0; mergeUp<2; ++mergeUp)
{
if ( (allowMergeLeft && (mergeUp==0)) || (allowMergeUp && (mergeUp==1)) )
{
m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[0][CI_CURR_BEST]);
m_pcRDGoOnSbacCoder->resetBits();
if (allowMergeLeft)
{
m_pcEntropyCoder->m_pcEntropyCoderIf->codeSaoMerge(1-mergeUp);
}
if ( allowMergeUp && (mergeUp==1) )
{
m_pcEntropyCoder->m_pcEntropyCoderIf->codeSaoMerge(1);
}
rate = m_pcEntropyCoder->getNumberOfWrittenBits();//码率
mergeCost = compDistortion[mergeUp+1] + (Double)rate;//率失真
if (mergeCost < bestCost)//更新最佳滤波模式
{
bestCost = mergeCost;
m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[0][CI_TEMP_BEST]);
for ( compIdx=0;compIdx<3;compIdx++)
{
mergeSaoParam[compIdx][mergeUp].mergeLeftFlag = 1-mergeUp;
mergeSaoParam[compIdx][mergeUp].mergeUpFlag = mergeUp;
if( (compIdx==0 && saoParam->bSaoFlag[0]) || (compIdx>0 && saoParam->bSaoFlag[1]))
{
copySaoUnit(&saoParam->saoLcuParam[compIdx][addr], &mergeSaoParam[compIdx][mergeUp] );
}
}
}
}
}
#if SAO_ENCODING_CHOICE
#if SAO_ENCODING_CHOICE_CHROMA
if( saoParam->saoLcuParam[0][addr].typeIdx == -1)//Y分量不存在SAO参数
{
numNoSao[0]++;
}
if( saoParam->saoLcuParam[1][addr].typeIdx == -1)//CbCr分量不存在SAO参数
{
numNoSao[1]+=2;
}
#else
for ( compIdx=0;compIdx<3;compIdx++)
{
if( depth == 0 && saoParam->saoLcuParam[compIdx][addr].typeIdx == -1)
{
numNoSao++;
}
}
#endif
#endif
m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[0][CI_TEMP_BEST]);
m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[0][CI_CURR_BEST]);
}//!< if( saoParam->bSaoFlag[0] || saoParam->bSaoFlag[1] )
}//!< for (idxX = 0; idxX< frameWidthInCU; idxX++)
}//!< for (idxY = 0; idxY< frameHeightInCU; idxY++)
#if SAO_ENCODING_CHOICE
#if SAO_ENCODING_CHOICE_CHROMA
if( !saoParam->bSaoFlag[0])
{
m_depthSaoRate[0][depth] = 1.0;
}
else
{
m_depthSaoRate[0][depth] = numNoSao[0]/((Double) frameHeightInCU*frameWidthInCU);
}
if( !saoParam->bSaoFlag[1])
{
m_depthSaoRate[1][depth] = 1.0;
}
else
{
m_depthSaoRate[1][depth] = numNoSao[1]/((Double) frameHeightInCU*frameWidthInCU*2);
}
#else
if( depth == 0)
{
// update SAO Rate
m_depth0SaoRate = numNoSao/((Double) frameHeightInCU*frameWidthInCU*3);
}
#endif
#endif
}
(转载请注明出处)