关于图像级别和单元级别的lambda和qp预测计算
这两个级别各两个参数的计算主要考虑的是计算和计算后的平滑参数的设置。都有现成的公式可以参考。同样用到的是HEVC提案JCTVC-K0103(码率控制提案)
(一)Double TEncRCPic::estimatePicLambda
Double TEncRCPic::estimatePicLambda( list<TEncRCPic*>& listPreviousPictures, SliceType eSliceType)//估计图片级别的lambda
{
Double alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha;
Double beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta;
Double bpp = (Double)m_targetBits/(Double)m_numberOfPixel;//前面求得的bpp用于这里来获得lambda
Double estLambda;
if (eSliceType == I_SLICE)//I片有自己的lambda算法
{
estLambda = calculateLambdaIntra(alpha, beta, pow(m_totalCostIntra/(Double)m_numberOfPixel, BETA1), bpp);
}
else
{
estLambda = alpha * pow( bpp, beta );//非I帧的计算公式,提案中常用的公式
}
/*到这里当前帧的lambda已经求得,但是还需要对数据进行处理才能正式用于编码当中,用约束条件进行约束,使其值有限定范围*/
//下面这段程序是对Lambda的平滑,保证前后帧之间的参数不变化太大。
Double lastLevelLambda = -1.0;//上一个级别???
Double lastPicLambda = -1.0;//上一帧的lambda
Double lastValidLambda = -1.0;
list<TEncRCPic*>::iterator it;
for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ )
{
if ( (*it)->getFrameLevel() == m_frameLevel )
{
lastLevelLambda = (*it)->getPicActualLambda();
}
lastPicLambda = (*it)->getPicActualLambda();
if ( lastPicLambda > 0.0 )
{
lastValidLambda = lastPicLambda;
}
}
if ( lastLevelLambda > 0.0 )
{
lastLevelLambda = Clip3( 0.1, 10000.0, lastLevelLambda );
estLambda = Clip3( lastLevelLambda * pow( 2.0, -3.0/3.0 ), lastLevelLambda * pow( 2.0, 3.0/3.0 ), estLambda );
}
if ( lastPicLambda > 0.0 )
{
lastPicLambda = Clip3( 0.1, 2000.0, lastPicLambda );
estLambda = Clip3( lastPicLambda * pow( 2.0, -10.0/3.0 ), lastPicLambda * pow( 2.0, 10.0/3.0 ), estLambda );
}
else if ( lastValidLambda > 0.0 )
{
lastValidLambda = Clip3( 0.1, 2000.0, lastValidLambda );
estLambda = Clip3( lastValidLambda * pow(2.0, -10.0/3.0), lastValidLambda * pow(2.0, 10.0/3.0), estLambda );
}
else
{
estLambda = Clip3( 0.1, 10000.0, estLambda );
}
if ( estLambda < 0.1 )//最终的预测lambda不能小于0.1
{
estLambda = 0.1;
}
m_estPicLambda = estLambda;
Double totalWeight = 0.0;
// initial BU bit allocation weight 初始化BU比特分配比重
for ( Int i=0; i<m_numberOfLCU; i++ )//遍历整个LCU的数目
{
Double alphaLCU, betaLCU;
if ( m_encRCSeq->getUseLCUSeparateModel() )//启用LCU的分层模式,同一个图片层的不同LCU的参数是不同的,所以要遍历整个图像层的所有LCU ,分配不同的参数。。
{
alphaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_alpha;
betaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_beta;
}
else//如果没有启用LCU的层的不同模式,则整个picture使用个相同的参数,就不需要分各个不同的LCU考虑了
{
alphaLCU = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha;
betaLCU = m_encRCSeq->getPicPara( m_frameLevel ).m_beta;
}
m_LCUs[i].m_bitWeight = m_LCUs[i].m_numberOfPixel * pow( estLambda/alphaLCU, 1.0/betaLCU );
if ( m_LCUs[i].m_bitWeight < 0.01 )
{
m_LCUs[i].m_bitWeight = 0.01;
}
totalWeight += m_LCUs[i].m_bitWeight;
}
for ( Int i=0; i<m_numberOfLCU; i++ )
{
Double BUTargetBits = m_targetBits * m_LCUs[i].m_bitWeight / totalWeight;
m_LCUs[i].m_bitWeight = BUTargetBits;
}
return estLambda;
}
(二)TEncRCPic::estimatePicQP
Int TEncRCPic::estimatePicQP( Double lambda, list<TEncRCPic*>& listPreviousPictures )
{
Int QP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 );//加0.5为了四舍五入(上面一个函数已经给出了lambda的计算,所以由公式可以知道,直接计算出QP的值)
/*将下面三个参数都赋值相同,什么意思?*/
Int lastLevelQP = g_RCInvalidQPValue;//上一层?
Int lastPicQP = g_RCInvalidQPValue;
Int lastValidQP = g_RCInvalidQPValue;//前一帧的有效的合法的QP,也就是经过平滑之后的QP
list<TEncRCPic*>::iterator it;
for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ )
{
if ( (*it)->getFrameLevel() == m_frameLevel )
{
lastLevelQP = (*it)->getPicActualQP();
}
lastPicQP = (*it)->getPicActualQP();
if ( lastPicQP > g_RCInvalidQPValue )
{
lastValidQP = lastPicQP;
}
}
if ( lastLevelQP > g_RCInvalidQPValue )
{
QP = Clip3( lastLevelQP - 3, lastLevelQP + 3, QP );
}
if( lastPicQP > g_RCInvalidQPValue )
{
QP = Clip3( lastPicQP - 10, lastPicQP + 10, QP );
}
else if( lastValidQP > g_RCInvalidQPValue )
{
QP = Clip3(lastValidQP - 10, lastValidQP + 10, QP);//当前的QP受限于前一帧的合法QP值
}
return QP;
}
上面两个函数完成了图片级的lambda和QP的求解。下面将对单元层的参数进行分析
(一)
Double TEncRCPic::getLCUEstLambda( Double bpp )//LCU层的λ预测
{
Int LCUIdx = getLCUCoded();
Double alpha;
Double beta;
if ( m_encRCSeq->getUseLCUSeparateModel() )//每个LCU使用的不同的alpha和beta
{
alpha = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_alpha;//这些值由LCU的编号决定
beta = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_beta;
}
else//使用相同的
{
alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha;//这些值直接由帧号决定
beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta;
}
Double estLambda = alpha * pow( bpp, beta );
//for Lambda clip, picture level clip
Double clipPicLambda = m_estPicLambda;
//for Lambda clip, LCU level clip
Double clipNeighbourLambda = -1.0;
for ( Int i=LCUIdx - 1; i>=0; i-- )
{
if ( m_LCUs[i].m_lambda > 0 )
{
clipNeighbourLambda = m_LCUs[i].m_lambda;
break;
}
}
if ( clipNeighbourLambda > 0.0 )
{
estLambda = Clip3( clipNeighbourLambda * pow( 2.0, -1.0/3.0 ), clipNeighbourLambda * pow( 2.0, 1.0/3.0 ), estLambda );
}
if ( clipPicLambda > 0.0 )
{
estLambda = Clip3( clipPicLambda * pow( 2.0, -2.0/3.0 ), clipPicLambda * pow( 2.0, 2.0/3.0 ), estLambda );
}
else
{
estLambda = Clip3( 10.0, 1000.0, estLambda );
}
if ( estLambda < 0.1 )
{
estLambda = 0.1;
}
return estLambda;
}
(二)
Int TEncRCPic::getLCUEstQP( Double lambda, Int clipPicQP )//LCU层的QP估计
{
Int LCUIdx = getLCUCoded();
Int estQP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 );//0.5的作用是四舍五入
//for Lambda clip, LCU level clip
Int clipNeighbourQP = g_RCInvalidQPValue;
for ( Int i=LCUIdx - 1; i>=0; i-- )
{
if ( (getLCU(i)).m_QP > g_RCInvalidQPValue )
{
clipNeighbourQP = getLCU(i).m_QP;
break;
}
}
if ( clipNeighbourQP > g_RCInvalidQPValue )
{
estQP = Clip3( clipNeighbourQP - 1, clipNeighbourQP + 1, estQP );
}
estQP = Clip3( clipPicQP - 2, clipPicQP + 2, estQP );
return estQP;
}
在求这两个参数的时候,前面有一个函数(TEncRCPic::getLCUTargetBpp)是用来求出单元层的bpp的。由bpp求出lambda,lambda求出QP。
原文地址:http://blog.csdn.net/cpp12341234/article/details/45867631