HM代码阅读3:AMVP候选填充函数Void TComDataCU::fillMvpCand ()
AMVP候选理论回顾
根据图像中块与块的相关性计算,针对当前块,空域上与其相关性最强的块的位置如下图所示:
时域上相关性的最强的块如下图所示:
HM中该MVP填充流程如下:
- 计算得到当前PU左上、左下、右上的4x4块的索引值.将ZScan转换成Raster来找更好计算位置
- 预先判断当前PU左方的CU能不能获取,不能获取的话 isScaledFlagLX=false
- 依次找无需缩放的A0、A1。根据当前参考帧以及所选块参考帧来确定,若两个参考帧相同,则就无需缩放。如果无需缩放的MVP找不到,则寻找可以缩放的MVP。
- 依次找上方的CU:B0、B1、B2(此步只找无需缩放的MVP)
- 如果左方的CU不能用,再依次找可以缩放的 B0 B1 B2填入AMVP候选
- 判断当前MVP候选个数,同时去冗余
- 去完冗余后,若还不满足AMVP候选个数最大值,则寻找时域同位块的MV。
- 先找右下方的CU、右下方CU不可用或者是当前PU右下角的4x4块在当前CTU角落、在最后一行不在最后一列时也不可用。就开始寻找中心块
- 若还填不满 则填充0矢量.
代码如下:
/** Constructs a list of candidates for AMVP (See specification, section "Derivation process for motion vector predictor candidates")* \param uiPartIdx -当前处理PU的索引* \param uiPartAddr - 当前处理PU的起始地址(后续需要根据当前CU的地址来判断)* \param eRefPicList - 当前参考图像列表* \param iRefIdx - 当前参考帧* \param pInfo - 要存入的MVP信息*/
Void TComDataCU::fillMvpCand ( const UInt partIdx, const UInt partAddr, const RefPicList eRefPicList, const Int refIdx, AMVPInfo* pInfo ) const
{pInfo->iN = 0;if (refIdx < 0){return;}//-- Get Spatial MV// 得到当前PU左上,右上,左下4x4CU块的索引(4x4为默认最小CU)// Zscan为Z扫, Raster为逐行扫描UInt partIdxLT, partIdxRT, partIdxLB;deriveLeftRightTopIdx( partIdx, partIdxLT, partIdxRT ); //要以当前CU起始位置开始找deriveLeftBottomIdx( partIdx, partIdxLB );Bool isScaledFlagLX = false; /// variable name from specification; true when the PUs below left or left are available (availableA0 || availableA1).//判断左方的CTU,左下方CU能不能获取{UInt idx;const TComDataCU* tmpCU = getPUBelowLeft(idx, partIdxLB);isScaledFlagLX = (tmpCU != NULL) && (tmpCU->isInter(idx));if (!isScaledFlagLX){tmpCU = getPULeft(idx, partIdxLB);isScaledFlagLX = (tmpCU != NULL) && (tmpCU->isInter(idx));}}// Left predictor search// 先按照左下,左方的顺序搜索可用的CU,先找不用缩放的,再找需要缩放的// 不用缩放:邻居块与当前PU参考同一帧if (isScaledFlagLX){Bool bAdded = xAddMVPCandUnscaled( *pInfo, eRefPicList, refIdx, partIdxLB, MD_BELOW_LEFT);if (!bAdded){bAdded = xAddMVPCandUnscaled( *pInfo, eRefPicList, refIdx, partIdxLB, MD_LEFT );if(!bAdded){bAdded = xAddMVPCandWithScaling( *pInfo, eRefPicList, refIdx, partIdxLB, MD_BELOW_LEFT);if (!bAdded){xAddMVPCandWithScaling( *pInfo, eRefPicList, refIdx, partIdxLB, MD_LEFT );}}}}// Above predictor search{Bool bAdded = xAddMVPCandUnscaled( *pInfo, eRefPicList, refIdx, partIdxRT, MD_ABOVE_RIGHT);if (!bAdded){bAdded = xAddMVPCandUnscaled( *pInfo, eRefPicList, refIdx, partIdxRT, MD_ABOVE);if(!bAdded){xAddMVPCandUnscaled( *pInfo, eRefPicList, refIdx, partIdxLT, MD_ABOVE_LEFT);}}}if(!isScaledFlagLX){Bool bAdded = xAddMVPCandWithScaling( *pInfo, eRefPicList, refIdx, partIdxRT, MD_ABOVE_RIGHT);if (!bAdded){bAdded = xAddMVPCandWithScaling( *pInfo, eRefPicList, refIdx, partIdxRT, MD_ABOVE);if(!bAdded){xAddMVPCandWithScaling( *pInfo, eRefPicList, refIdx, partIdxLT, MD_ABOVE_LEFT);}}}// 判断空域候选是否填满了AMVP候选列表// 去除冗余MVP,如两个MV相同,则去除掉一个if ( pInfo->iN == 2 ){if ( pInfo->m_acMvCand[ 0 ] == pInfo->m_acMvCand[ 1 ] ){pInfo->iN = 1;}}// 若未填满,则开启时域候选if (pInfo->iN < AMVP_MAX_NUM_CANDS && getSlice()->getEnableTMVPFlag() ){// Get Temporal Motion Predictorconst UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth(); //一个CTU的宽中可以有多少个4x4的块const UInt numPartInCtuHeight = m_pcPic->getNumPartInCtuHeight();const Int refIdx_Col = refIdx;TComMv cColMv;UInt partIdxRB;UInt absPartIdx;deriveRightBottomIdx( partIdx, partIdxRB ); //找到右下方的4x4块UInt absPartAddr = m_absZIdxInCtu + partAddr; //当前PU起始位置//---- co-located RightBottom Temporal Predictor (H) ---//absPartIdx = g_auiZscanToRaster[partIdxRB]; //Zscan to RasterInt ctuRsAddr = -1;//找右下角的CU块起始位置,由于CTU的划分每一帧都相同,所以若右下角的块是下一个CTU了,那么还要获取下一个CTU的地址if ( ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelX() + g_auiRasterToPelX[absPartIdx] + m_pcPic->getMinCUWidth () ) < m_pcSlice->getSPS()->getPicWidthInLumaSamples () ) // image boundary check&& ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelY() + g_auiRasterToPelY[absPartIdx] + m_pcPic->getMinCUHeight() ) < m_pcSlice->getSPS()->getPicHeightInLumaSamples() ) ){if ( ( absPartIdx % numPartInCtuWidth < numPartInCtuWidth - 1 ) && // is not at the last column of CTU( absPartIdx / numPartInCtuWidth < numPartInCtuHeight - 1 ) ) // is not at the last row of CTU{absPartAddr = g_auiRasterToZscan[ absPartIdx + numPartInCtuWidth + 1 ]; //用逐行扫描的索引更容易计算相对位置ctuRsAddr = getCtuRsAddr();}else if ( absPartIdx % numPartInCtuWidth < numPartInCtuWidth - 1 ) // is not at the last column of CTU But is last row of CTU{absPartAddr = g_auiRasterToZscan[ (absPartIdx + numPartInCtuWidth + 1) % m_pcPic->getNumPartitionsInCtu() ];}else if ( absPartIdx / numPartInCtuWidth < numPartInCtuHeight - 1 ) // is not at the last row of CTU But is last column of CTU{absPartAddr = g_auiRasterToZscan[ absPartIdx + 1 ];ctuRsAddr = getCtuRsAddr() + 1;}else //is the right bottom corner of CTU{absPartAddr = 0;}}//若当前PU右下角的位置在当前CTU内且不是最后一行也不是角落位置if ( ctuRsAddr >= 0 && xGetColMVP( eRefPicList, ctuRsAddr, absPartAddr, cColMv, refIdx_Col ) ){pInfo->m_acMvCand[pInfo->iN++] = cColMv;}//中心同位帧else{UInt uiPartIdxCenter;xDeriveCenterIdx( partIdx, uiPartIdxCenter );if (xGetColMVP( eRefPicList, getCtuRsAddr(), uiPartIdxCenter, cColMv, refIdx_Col )){pInfo->m_acMvCand[pInfo->iN++] = cColMv;}}//---- co-located RightBottom Temporal Predictor ---//}while (pInfo->iN < AMVP_MAX_NUM_CANDS){pInfo->m_acMvCand[pInfo->iN].set(0,0);pInfo->iN++;}return ;
}
HM代码阅读3:AMVP候选填充函数Void TComDataCU::fillMvpCand ()相关推荐
- HM代码阅读1: 帧间预测函数Void TEncSearch::predInterSearch()
AMVP理论知识简单回顾(含GPB) MVP主要是为了给当前PU提供一个运动矢量的预测,可加快ME的计算速度以及提升准确性.并且在后续编码中也只用编码MVD,减少了传输bit数. HM中获取每个参考图 ...
- HM代码阅读2:AMVP预测函数Void TEncSearch::xEstimateMvPredAMVP()
AMVP预测函数:根据AMVP候选准则为该帧建立MVP候选列表,调用pcCU->fillMvpCand( uiPartIdx, uiPartAddr, eRefPicList, iRefIdx, ...
- HM代码阅读0:Win10下安装HM16.23,编码一个视频,main函数阅读
HEVC理论知识的学习告了一段落了,说实话脑子里还是嗡嗡的,剩下的部分就一边阅读代码一边掌握吧. 1. HM16.23安装 首先需要安装Cmake,参考以下博客,照步骤安装即可 https://blo ...
- VTM1.0代码阅读:CodingStructure类主要函数
CodingStructure类中的各个函数对于cu.pu和tu的函数处理,其实大致流程都是差不多一样的,所以这里只对cu的相应函数进行分析. 对于下面CodingStructure类中的各个函数的阅 ...
- VVC代码阅读(2)compressGOP函数(2)
注意:本次代码运用的是encoder_intra_vtm的设置,所以GOP_size 只有一帧 // store sub-picture numbers, sizes, and locations ...
- HM编码器代码阅读(16)——帧间预测之AMVP模式(四)预测MV的获取
帧间预测的原理 AMVP的原理 帧间预测的实质就是为当前的PU在参考帧中寻找一块最相似块(相似度的判断准则有SAD等方法).但是参考图像通常都比较大,我们直接去搜索的话就太费时了,应该使用某种方法在参 ...
- 【二十一】 H.266/VVC | 仿射运动估计AMVP候选列表的构建 | fillAffineMvpCand函数
/* 函数的作用: 构建Affine AMVP list候选列表 函数的参数说明: 1.PredictionUnit &pu 当前编码的PU 2.const RefPicList &e ...
- 【二十二】 H.266/VVC | 选择最优的仿射AMVP候选项 | xEstimateAffineAMVP函数
/* 函数的所用:从构建的仿射AMVP候选列表中选择最优的候选项 函数的参数说明: 1.PredictionUnit& pu, 当前编码的PU 2.AffineAMVPInfo& af ...
- VTM3.0代码阅读:xEstimateMvPredAMVP函数
AMVP运用于inter_ME模式的时候. xEstimateMvPredAMVP进行AMVP,获得当前pu的相邻运动信息,构建AMVP列表,最终选择出最优的MVP.AMVP最终获得的MVP作为ME的 ...
最新文章
- 关于运算符重载的问题
- java并发排序_Java并发(三):重排序
- 如何使用 SQL Server FILESTREAM 存储非结构化数据?这篇文章告诉你!
- 开源数据库再创里程碑,PingCAP 获 2.7 亿美元融资
- linux NFS共享
- 自旋锁,偏向锁,轻量级锁 和 重量级锁
- 爬虫mm131明星照片
- Url重写——伪静态实现
- mnist数据集python导入_Python读取MNIST数据集
- VB2010的串口能正常接收数据,但无法发送数值大于127的数据
- 使用vld查看OPCode
- UE5——材质学习笔记(4):溶解材质
- 使用Python及SMTP协议发送邮件(以163邮箱为例)
- 《程序员》走近创新工场 解密李开复如何寻找创业之星
- VTK读取序列DCM格式医学图像
- Android系统定制开机logo和开机动画
- Linux·工作队列
- Tensorflow2 图像分类-Flowers数据及分类代码详解
- linux raid 找回文件,linux – 恢复已经在降级模式下运行的RAID-5(丢失了第二个磁盘)...
- logback根据业务分开打印日志