热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

H.266/VVC帧间预测技术学习:基于子块的时间运动矢量预测(Subblockbasedtemporalmotionvectorprediction)

基于子块的时间运动矢量预测VVC支持基于子块的时间运动矢量预测(SbTMVP)方法。类似于HEVC中的时间运动矢量预测(temporal

基于子块的时间运动矢量预测

VVC支持基于子块的时间运动矢量预测(SbTMVP)方法。 类似于HEVC中的时间运动矢量预测(temporal motion vector prediction, TMVP),SbTMVP使用同位图片中的运动场来改善当前图片中CU的运动矢量预测和Merge模式。 SbTVMP和TMVP使用的相同的同位图片。 (同位块:相邻已编码图像中对应位置的块)

SbTMVP在以下两个主要方面与TMVP不同:

  1. TMVP预测CU级别的运动,但SbTMVP预测子CU级别的运动;
  2. TMVP直接从同位图片的同位块获取时间运动矢量(同位块是相对于当前CU的右下或中心块),而SbTMVP在从同位图片中获取时间运动信息之前应用了运动偏移 ,其中运动偏移来自当前CU的空间相邻块的运动矢量。

SbTMVP中使用的子CU大小固定为8x8,SbTMVP模式仅适用于宽度和高度都大于或等于8的CU。另外,SbTMVP Merge候选的编码逻辑与其他Merge候选的编码逻辑相同,即,对于P或B片中的每个CU,执行附加RD检查以决定是否使用SbTMVP候选。

SbTMVP分两步预测当前CU内子CU的运动矢量:

Step1:检查下图中的空域相邻块A1。 如果A1具有将同位图片用作其参考图片的运动矢量(A1可用且其参考图像就是当前图像的同位图像),则将该运动矢量选择为要应用的运动偏移。 如果未识别到此类运动,则将运动偏移设置为(0,0)。

Step2:利用①中A1块的运动偏移,定位当前CU的参考同位块的位置。然后将当前CU以及其对应的同位图像中的同位块分割为8*8的子块,对于每个子块,获取对应同位子块的运动信息( 8*8 子块中心位置处)。在确定同位子CU的运动信息之后,以与HEVC的TMVP过程类似的方式,将其转换为当前子CU的运动矢量和参考帧索引,其中应用时间运动缩放以将时间运动矢量的参考图片与当前CU的参考图片对齐。

SbtMVP和Affine Merge的关系

在VVC中,SbTMVP和Affine Merge的候选是共存的,将SbTVMP得到的候选和仿射Merge候选共同组成基于子块的Merge候选列表。 通过序列参数集(SPS)标志启用/禁用SbTVMP模式。 如果启用了SbTMVP模式,则将SbTMVP预测变量添加为基于子块的Merge候选列表的第一项,然后是仿射Merge候选项。 基于子块的Merge列表的大小在SPS中用信号通知,并且基于子块的Merge列表的最大允许大小为5。

SbTMVP的相关代码及注释如下所示:(基于VTM10.0)

// 基于子块的TMVP技术if (sbTmvpEnableFlag && slice.getPicHeader()->getEnableTMVPFlag()){MergeCtx mrgCtx &#61; *affMrgCtx.mrgCtx;bool tmpLICFlag &#61; false;CHECK( mrgCtx.subPuMvpMiBuf.area() &#61;&#61; 0 || !mrgCtx.subPuMvpMiBuf.buf, "Buffer not initialized" );mrgCtx.subPuMvpMiBuf.fill( MotionInfo() );int pos &#61; 0;// Get spatial MVconst Position posCurLB &#61; pu.Y().bottomLeft();MotionInfo miLeft;//leftconst PredictionUnit* puLeft &#61; cs.getPURestricted( posCurLB.offset( -1, 0 ), pu, pu.chType );const bool isAvailableA1 &#61; puLeft && isDiffMER(pu.lumaPos(), posCurLB.offset(-1, 0), plevel) && pu.cu !&#61; puLeft->cu && CU::isInter( *puLeft->cu );if ( isAvailableA1 ){ //A1块可用miLeft &#61; puLeft->getMotionInfo( posCurLB.offset( -1, 0 ) );// get Inter DirmrgCtx.interDirNeighbours[pos] &#61; miLeft.interDir;// get Mv from Left 获得A1块的MVmrgCtx.mvFieldNeighbours[pos <<1].setMvField( miLeft.mv[0], miLeft.refIdx[0] );if ( slice.isInterB() ){mrgCtx.mvFieldNeighbours[(pos <<1) &#43; 1].setMvField( miLeft.mv[1], miLeft.refIdx[1] );}pos&#43;&#43;;}mrgCtx.numValidMergeCand &#61; pos;// 获得子PU的时域MV预测isAvailableSubPu &#61; getInterMergeSubPuMvpCand(pu, mrgCtx, tmpLICFlag, pos, 0);if ( isAvailableSubPu ){// 将子块的时域MV添加到Affine Merge列表中for ( int mvNum &#61; 0; mvNum <3; mvNum&#43;&#43; ){affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand <<1) &#43; 0][mvNum].setMvField( mrgCtx.mvFieldNeighbours[(pos <<1) &#43; 0].mv, mrgCtx.mvFieldNeighbours[(pos <<1) &#43; 0].refIdx );affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand <<1) &#43; 1][mvNum].setMvField( mrgCtx.mvFieldNeighbours[(pos <<1) &#43; 1].mv, mrgCtx.mvFieldNeighbours[(pos <<1) &#43; 1].refIdx );}affMrgCtx.interDirNeighbours[affMrgCtx.numValidMergeCand] &#61; mrgCtx.interDirNeighbours[pos];affMrgCtx.affineType[affMrgCtx.numValidMergeCand] &#61; AFFINE_MODEL_NUM;affMrgCtx.mergeType[affMrgCtx.numValidMergeCand] &#61; MRG_TYPE_SUBPU_ATMVP;if ( affMrgCtx.numValidMergeCand &#61;&#61; mrgCandIdx ){return;}affMrgCtx.numValidMergeCand&#43;&#43;;// early terminationif ( affMrgCtx.numValidMergeCand &#61;&#61; maxNumAffineMergeCand ){return;}}}

其中&#xff0c;在getInterMergeSubPuMvpCand函数中获得子PU的MVP候选项

bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, bool& LICFlag, const int count, int mmvdList
)
{const Slice &slice &#61; *pu.cs->slice;const unsigned scale &#61; 4 * std::max(1, 4 * AMVP_DECIMATION_FACTOR / 4);const unsigned mask &#61; ~(scale - 1);// 获得同位图片const Picture *pColPic &#61; slice.getRefPic(RefPicList(slice.isInterB() ? 1 - slice.getColFromL0Flag() : 0), slice.getColRefIdx());Mv cTMv;if ( count ){if ( (mrgCtx.interDirNeighbours[0] & (1 <> ATMVP_SUB_BLOCK_SIZE, 1u);int numPartCol &#61; std::max(puSize.height >> ATMVP_SUB_BLOCK_SIZE, 1u);int puHeight &#61; numPartCol &#61;&#61; 1 ? puSize.height : 1 <> 1) &#43; tempX; centerPos.y &#61; puPos.y &#43; (puSize.height >> 1) &#43; tempY;clipColPos(centerPos.x, centerPos.y, pu);centerPos &#61; Position{ PosType(centerPos.x & mask), PosType(centerPos.y & mask) };// derivation of center motion parameters from the collocated CU// 从同位CU得出中心运动参数const MotionInfo &mi &#61; pColPic->cs->getMotionInfo(centerPos);if (mi.isInter && mi.isIBCmot &#61;&#61; false){mrgCtx.interDirNeighbours[count] &#61; 0;for (unsigned currRefListId &#61; 0; currRefListId <(bBSlice ? 2 : 1); currRefListId&#43;&#43;){RefPicList currRefPicList &#61; RefPicList(currRefListId); //参考帧列表索引if (getColocatedMVP(pu, currRefPicList, centerPos, cColMv, refIdx, true)) //从同位CU中获得MVP{// set as default, for further motion vector field spanningmrgCtx.mvFieldNeighbours[(count <<1) &#43; currRefListId].setMvField(cColMv, 0);mrgCtx.interDirNeighbours[count] |&#61; (1 <> 1) &#43; tempX;int yOff &#61; (puHeight >> 1) &#43; tempY;MotionBuf &mb &#61; mrgCtx.subPuMvpMiBuf;const bool isBiPred &#61; isBipredRestriction(pu);for (int y &#61; puPos.y; y cs->getMotionInfo(colPos);MotionInfo mi;found &#61; false;mi.isInter &#61; true;mi.sliceIdx &#61; slice.getIndependentSliceIdx();mi.isIBCmot &#61; false;if (colMi.isInter && colMi.isIBCmot &#61;&#61; false){for (unsigned currRefListId &#61; 0; currRefListId <(bBSlice ? 2 : 1); currRefListId&#43;&#43;){RefPicList currRefPicList &#61; RefPicList(currRefListId);if (getColocatedMVP(pu, currRefPicList, colPos, cColMv, refIdx, true)){mi.refIdx[currRefListId] &#61; 0;mi.mv[currRefListId] &#61; cColMv;found &#61; true;}}}if (!found){mi.mv[0] &#61; mrgCtx.mvFieldNeighbours[(count <<1) &#43; 0].mv;mi.mv[1] &#61; mrgCtx.mvFieldNeighbours[(count <<1) &#43; 1].mv;mi.refIdx[0] &#61; mrgCtx.mvFieldNeighbours[(count <<1) &#43; 0].refIdx;mi.refIdx[1] &#61; mrgCtx.mvFieldNeighbours[(count <<1) &#43; 1].refIdx;}mi.interDir &#61; (mi.refIdx[0] !&#61; -1 ? 1 : 0) &#43; (mi.refIdx[1] !&#61; -1 ? 2 : 0);if (isBiPred && mi.interDir &#61;&#61; 3){mi.interDir &#61; 1;mi.mv[1] &#61; Mv();mi.refIdx[1] &#61; NOT_VALID;}mb.subBuf(g_miScaling.scale(Position{ x, y } - pu.lumaPos()), g_miScaling.scale(Size(puWidth, puHeight))).fill(mi);}}}return true;
}

 sbtMVP对应的mergetype是MRG_TYPE_SUBPU_ATMVP&#xff0c;相应的运动补偿函数为&#xff1a;

void InterPrediction::xSubPuMC( PredictionUnit& pu, PelUnitBuf& predBuf, const RefPicList &eRefPicList /*&#61; REF_PIC_LIST_X*/, const bool luma /*&#61; true*/, const bool chroma /*&#61; true*/)
{// compute the location of the current PU// 当前PU的位置和尺寸Position puPos &#61; pu.lumaPos();Size puSize &#61; pu.lumaSize();int numPartLine, numPartCol, puHeight, puWidth;{numPartLine &#61; std::max(puSize.width >> ATMVP_SUB_BLOCK_SIZE, 1u); // 行存在多少个子PUnumPartCol &#61; std::max(puSize.height >> ATMVP_SUB_BLOCK_SIZE, 1u); // 列存在多少个子PU//subPu 的宽度/高度&#xff0c;如果当前PU的宽度/高度大于8&#xff0c;则subPU的宽度/高度为8&#xff0c;否则subPU的宽度/高度和PU的宽度/高度相等puHeight &#61; numPartCol &#61;&#61; 1 ? puSize.height : 1 <affine;subPu.cu->affine &#61; false;// join sub-pus containing the same motionbool verMC &#61; puSize.height > puSize.width;int fstStart &#61; (!verMC ? puPos.y : puPos.x);int secStart &#61; (!verMC ? puPos.x : puPos.y);int fstEnd &#61; (!verMC ? puPos.y &#43; puSize.height : puPos.x &#43; puSize.width);int secEnd &#61; (!verMC ? puPos.x &#43; puSize.width : puPos.y &#43; puSize.height);int fstStep &#61; (!verMC ? puHeight : puWidth);int secStep &#61; (!verMC ? puWidth : puHeight);bool scaled &#61; pu.cu->slice->getRefPic( REF_PIC_LIST_0, 0 )->isRefScaled( pu.cs->pps ) || ( pu.cs->slice->getSliceType() &#61;&#61; B_SLICE ? pu.cu->slice->getRefPic( REF_PIC_LIST_1, 0 )->isRefScaled( pu.cs->pps ) : false );m_subPuMC &#61; true;for (int fstDim &#61; fstStart; fstDim affine &#61; isAffine;
}


推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • OpenMap教程4 – 图层概述
    本文介绍了OpenMap教程4中关于地图图层的内容,包括将ShapeLayer添加到MapBean中的方法,OpenMap支持的图层类型以及使用BufferedLayer创建图像的MapBean。此外,还介绍了Layer背景标志的作用和OMGraphicHandlerLayer的基础层类。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
author-avatar
无心之无心
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有