帧内预测
原理
帧内预测,利用当前图像内已经编码的像素生成预测值,生成预测值之后,和原始的值相减,得到残差,后续的变换量化等操作就是基于残差进行处理的。具体细节参考
HEVC/H.265理论知识(3)——帧内预测
流程
帧内预测的大致流程是这样的
(1)遍历所有的预测模式,得到每种模式下的残差信号,再对残差信号进行Hadamard变换计算SATD值
(2)利用SATD值计算每种预测模式的率失真代价,选取率失真代价最小的几种模式(与PU大小相关)为预测模式集
(3)将已编码相邻块的预测模式补充到预测模式集中
(4)遍历模式集合中的所有模式,并对残差信号进行正常编码(熵编码),计算率失真代价
(5)选取最优的预测模式作为该PU的最优模式
(6)当亮度块的模式确定之后,把该模式以及DC、planar、水平方向模式、垂直方向模式作为色度块的候选模式,选取最优的模式即可
(1)遍历所有的预测模式,得到每种模式下的残差信号,再对残差信号进行Hadamard变换计算SATD值
(2)利用SATD值计算每种预测模式的率失真代价,选取率失真代价最小的几种模式(与PU大小相关)为预测模式集
(3)将已编码相邻块的预测模式补充到预测模式集中
(4)遍历模式集合中的所有模式,并对残差信号进行正常编码(熵编码),计算率失真代价
(5)选取最优的预测模式作为该PU的最优模式
(6)当亮度块的模式确定之后,把该模式以及DC、planar、水平方向模式、垂直方向模式作为色度块的候选模式,选取最优的模式即可
帧内预测的入口函数
入口函数是TEncCu::xCheckRDCostIntra,流程如下:
1、对亮度块进行帧内预测、变换量化,选取出最优的预测模式、并且计算出变换系数
2、对色度块(U、V分量)进行帧内预测、变换量化,选出最优的预测模式,并且计算出量化变换系数
3、对步骤1、2得到的模式和变换系数进行熵编码,得到比特代价
4、最后更新最优模式信息和数据
2、对色度块(U、V分量)进行帧内预测、变换量化,选出最优的预测模式,并且计算出量化变换系数
3、对步骤1、2得到的模式和变换系数进行熵编码,得到比特代价
4、最后更新最优模式信息和数据
/*
** 帧内预测入口函数
*/
Void TEncCu::xCheckRDCostIntra( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize eSize )
{
// 获取当前CU所处的深度
UInt uiDepth = rpcTempCU->getDepth( 0 );
// 跳过模式,设置为false
rpcTempCU->setSkipFlagSubParts( false, 0, uiDepth );
// 设置尺寸
rpcTempCU->setPartSizeSubParts( eSize, 0, uiDepth );
// 设置预测模式(帧内)
rpcTempCU->setPredModeSubParts( MODE_INTRA, 0, uiDepth );
// 是否区分亮度和色度
Bool bSeparateLumaChroma = true; // choose estimation mode
UInt uiPreCalcDistC = 0;
// !bSeparateLumaChroma总是false,所以不会进到该条件判断
if( !bSeparateLumaChroma )
{
m_pcPredSearch->preestChromaPredMode( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth] );
}
// 这里进行实际的帧内预测(亮度)
m_pcPredSearch ->estIntraPredQT ( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth], m_ppcResiYuvTemp[uiDepth], m_ppcRecoYuvTemp[uiDepth], uiPreCalcDistC, bSeparateLumaChroma );
m_ppcRecoYuvTemp[uiDepth]->copyToPicLuma(rpcTempCU->getPic()->getPicYuvRec(), rpcTempCU->getAddr(), rpcTempCU->getZorderIdxInCU() );
// 这里进行实际的帧内预测(色度)
m_pcPredSearch ->estIntraPredChromaQT( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth], m_ppcResiYuvTemp[uiDepth], m_ppcRecoYuvTemp[uiDepth], uiPreCalcDistC );
// 重置熵编码器的比特数量
m_pcEntropyCoder->resetBits();
if ( rpcTempCU->getSlice()->getPPS()->getTransquantBypassEnableFlag())
{
m_pcEntropyCoder->encodeCUTransquantBypassFlag( rpcTempCU, 0, true );
}
// 进行熵编码,得到最优模式下的比特代价等信息
m_pcEntropyCoder->encodeSkipFlag ( rpcTempCU, 0, true );
m_pcEntropyCoder->encodePredMode( rpcTempCU, 0, true );
m_pcEntropyCoder->encodePartSize( rpcTempCU, 0, uiDepth, true );
m_pcEntropyCoder->encodePredInfo( rpcTempCU, 0, true );
// 编码IPCM信息
m_pcEntropyCoder->encodeIPCMInfo(rpcTempCU, 0, true );
// Encode Coefficients
Bool bCodeDQP = getdQPFlag();
// 对系数进编码
m_pcEntropyCoder->encodeCoeff( rpcTempCU, 0, uiDepth, rpcTempCU->getWidth (0), rpcTempCU->getHeight(0), bCodeDQP );
setdQPFlag( bCodeDQP );
m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]);
rpcTempCU->getTotalBits() = m_pcEntropyCoder->getNumberOfWrittenBits();
rpcTempCU->getTotalBins() = ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
xCheckDQP( rpcTempCU );
// 更新最优模式信息和数据
xCheckBestMode(rpcBestCU, rpcTempCU, uiDepth);
}