帧间预测的原理
AMVP的原理
帧间预测的实质就是为当前的PU在参考帧中寻找一块最相似块(相似度的判断准则有SAD等方法)。但是参考图像通常都比较大,我们直接去搜索的话就太费时了,应该使用某种方法在参考图像中确定一个搜索起始点,然后再该搜索起始点的周围进行搜索,那么就能降低搜索的时间了。AMVP模式就提供了这样一种方法,在开始搜索之前,先为当前PU预测出一个MV,这个预测的MV就被称为MVP,预测的MV可以直接从空域或者时域上的相邻块直接得到,因为相邻块有多个,因此MVP也会有多个,这些MVP组成了MVP候选列表,我们需要从中选择最优的一个来作为实际的MVP,得到MVP之后,我们根MVP(MVP实际也是一个MV)来确定搜索的起始点,然后在搜索起始点的附近按照某种方法做搜索,最后得到一个最优的MV,这个MV就是实际MV,MV确定了参考块的位置,参考块与当前PU相减得到残差,达到了数据压缩的目的;
同时MV与MVP相减得到MV残差也就是MVD,也能够达到数据压缩的目的。
它的大致工作流程是:
1、根据某种方法获取MVP候选列表
2、从候选列表中选出最优的一个MVP
3、根据MVP确定运动估计的起始点
4、在起始点附近,按照某种方法进行搜索
5、搜索完毕之后得到最优的MV
6、由MV确定参考块在参考图像中的位置
7、参考块减去当前块(PU)得到残差块
8、MV减去MVP得到MVD
9、通过7和8两个步骤就能达到数据压缩的目的
merge模式的原理
帧间预测的目的就是要得到一个MV(运动向量),然后根据该MV确定参考块在参考图像中的位置,但是由于临近块的相似性(比如当前块和临近块都属于同一个物体,在镜头移动的时候,它们移动的距离和方向当然是相同的),因此很多时候我们并不需要去计算MV,我们把相邻块的MV直接当作当前块的MV。和AMVP相似,我们通过相邻块得到一个MVP候选列表,从中选出最优的一个MVP作为当前块的MV,然后根据该MV直接确定参考块的位置,确定了参考块之后就能计算残差了。因为MVP和MV相同,因此不存在MVD,因此编码的时候只需要编码MV(MVP)在候选列表中索引即可,不再需要编码MVD,解码可以按照类似的方法构造MVP候选列表,然后依据传送过来的索引就能得到MV了。
工作流程是:
1、根据某种方法获取MVP候选列表
2、从候选列表中选出最优的一个MVP,同时得到该MVP在候选列表中的索引
3、把该MVP作为当前块的MV
4、根据MV确定参考块在参考图像中的位置
5、参考块减去当前块得到残差块
6、因为MVP和MV相同,因此没有MVD,只需把残差系数和MVP的索引传给解码器就行了
skip模式的原理
skip模式是merge模式的一种特例。按照merge模式得到MV之后,如果编码器根据某种方法判断了当前块和参考块基本一样,那么不需要传输残差数据,只需要传送MV的索引和一个标志,来表明当前块可以直接从参考块得到。AMVP模式的入口函数xCheckRDCostInter
主要流程如下:
(1)得到当前的深度。
(2)调用predInterSearch,进行ME(运动估计)和MC(运动补偿)。
(3)调用encodeResAndCalcRdInterCU,根据预测值,求出残差,然后进行TU的划分,然后进行变换、量化等操作以及RD代价的计算。
(4)调用xCheckBestMode选择最好的模式。
(2)调用predInterSearch,进行ME(运动估计)和MC(运动补偿)。
(3)调用encodeResAndCalcRdInterCU,根据预测值,求出残差,然后进行TU的划分,然后进行变换、量化等操作以及RD代价的计算。
(4)调用xCheckBestMode选择最好的模式。
#if AMP_MRG
Void TEncCu::xCheckRDCostInter( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize, Bool bUseMRG)
#else
Void TEncCu::xCheckRDCostInter( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize )
#endif
{
// 深度
UChar uhDepth = rpcTempCU->getDepth( 0 );
rpcTempCU->setDepthSubParts( uhDepth, 0 );
rpcTempCU->setSkipFlagSubParts( false, 0, uhDepth );
rpcTempCU->setPartSizeSubParts ( ePartSize, 0, uhDepth );
rpcTempCU->setPredModeSubParts ( MODE_INTER, 0, uhDepth );
// 对于帧间预测,需要在参考帧选择一个最合适的位置给它,进行预测编码
// 并计算出了残差以及其他信息
#if AMP_MRG
rpcTempCU->setMergeAMP (true);
m_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth], false, bUseMRG );
#else
m_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth] );
#endif
#if AMP_MRG
if ( !rpcTempCU->getMergeAMP() )
{
return;
}
#endif
// 下一步的计算
m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcResiYuvBest[uhDepth], m_ppcRecoYuvTemp[uhDepth], false );
rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
xCheckDQP( rpcTempCU );
xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth);
}