VVC帧间预测(八)DMVR

解码端运动向量修正(Decoder side motion vector refinement ,DMVR)是为了提高merge模式下双向预测MV的准确性而提出的技术。双向预测是在list0和list1中分别找一个运动向量MV0和MV1,然后将MV0和MV1所指向的预测块进行加权得到最终的预测块。而DMVR不是直接使用MV0和MV1,而是在MV0和MV1附近搜索更准确的MV0‘和MV1’。

如上图所示,在初始MV附件搜索MV‘,计算MV’指向的块(红色块)间的SAD,选择SAD值最小的MV‘作为最终修正的MV。

在VTM5中满足以下条件的CU才可以使用DMVR模式:

  • CU使用merge模式,且是双向预测。

  • 两个参考帧分别位于当前帧之前和之后。

  • 即两个参考帧离当前帧一样远(即两个参考帧的POC与当前帧POC的差值相等)。

  • CU至少有64个亮度像素。

  • CU的宽和高都大于等于8。

  • BCW使用相等权值。

  • 当前块不使用WP模式。

DMVR生成的修正MV用于生成帧间预测值和后续图像编码的时域运动向量预测值(TMVP)。原始MV用于去方块效应过程和后续CU编码的空域运动向量预测值(SMVP)。

VTM5中DMVR的具体过程如下:

搜索

DMVR中要搜索初始MV周围的点以找到最优的修正MV。待搜索的MV满足以下方程:

MV_offset表示修正MV相对初始MV的偏移量。VTM5规定搜索范围是初始MV附近2个整数亮度像素点内,搜索过程包括两个阶段,第一阶段搜索整像素第二阶段搜索分像素。

整像素搜索:

由于搜索范围是初始MV附近2个整数亮度像素点,所以一共有25个整像素点。

  Mv m_pSearchOffset[25] = { Mv(-2,-2), Mv(-1,-2), Mv(0,-2), Mv(1,-2), Mv(2,-2),Mv(-2,-1), Mv(-1,-1), Mv(0,-1), Mv(1,-1), Mv(2,-1),Mv(-2, 0), Mv(-1, 0), Mv(0, 0), Mv(1, 0), Mv(2, 0),Mv(-2, 1), Mv(-1, 1), Mv(0, 1), Mv(1, 1), Mv(2, 1),Mv(-2, 2), Mv(-1, 2), Mv(0, 2), Mv(1, 2), Mv(2, 2) };uint64_t m_SADsArray[((2 * DMVR_NUM_ITERATION) + 1) * ((2 * DMVR_NUM_ITERATION) + 1)];

首先计算初始MV0和MV1对应的块的SAD,如果该SAD小于阈值则终止整像素搜索过程。否则按扫描顺序计算剩下24个点的SAD,选择SAD最小的作为整数像素搜索阶段的输出。

分像素搜索:

为了减少计算复杂性,进行分像素搜索时用参数误差曲面方程(parametric error surface equation)代替SAD。只有当第一轮或第二轮整像素搜索阶段中心像素SAD最小时,才需要进行分像素搜索。

在计算分像素参数误差曲面时,需要使用中心位置和其周围四个位置的cost来拟合一共二维抛物线误差曲面方程:

通过使用5个点的cost值可以求解上面的方程:

x_min和y_min的值会被自动限制在-8~8间,因为所有的cost都为正且最小的cost是E(0,0)。计算得到的分像素(x_min,y_min)加上整像素MV得到最终修正MV。

双线性插值和像素填充

VVC中MV是1/16亮度像素精度。这些分像素是通过8抽头插值滤波器生成的。在DMVR中,为了减少计算复杂性在分像素搜索阶段使用双线性插值滤波器生成分像素。另外,使用双线性插值只需要访问周围2像素范围,而不用像普通运动补偿一样要参考更多像素。当获得修正MV后,在生成最终预测值时需要使用8抽头插值滤波器。

DMVR最大能处理16x16的块,如果块的宽和/或高大于16,需要将其分为宽和/或高等于16的子块。

VTM5中相关代码如下:

 for (int y = puPos.y; y < (puPos.y + pu.lumaSize().height); y = y + dy, yStart = yStart + dy){for (int x = puPos.x, xStart = 0; x < (puPos.x + pu.lumaSize().width); x = x + dx, xStart = xStart + dx){uint64_t minCost = MAX_UINT64;bool notZeroCost = true;int16_t totalDeltaMV[2] = { 0,0 };int16_t deltaMV[2] = { 0, 0 };uint64_t  *pSADsArray;for (int i = 0; i < (((2 * DMVR_NUM_ITERATION) + 1) * ((2 * DMVR_NUM_ITERATION) + 1)); i++){//!<25个整像素点SAD初始化m_SADsArray[i] = MAX_UINT64;}pSADsArray = &m_SADsArray[(((2 * DMVR_NUM_ITERATION) + 1) * ((2 * DMVR_NUM_ITERATION) + 1)) >> 1];Pel *addrL0Centre = biLinearPredL0 + yStart * m_biLinearBufStride + xStart;Pel *addrL1Centre = biLinearPredL1 + yStart * m_biLinearBufStride + xStart;for (int i = 0; i < iterationCount; i++){deltaMV[0] = 0;deltaMV[1] = 0;Pel *addrL0 = addrL0Centre + totalDeltaMV[0] + (totalDeltaMV[1] * m_biLinearBufStride);Pel *addrL1 = addrL1Centre - totalDeltaMV[0] - (totalDeltaMV[1] * m_biLinearBufStride);if (i == 0){//!<计算初始MV对应的costminCost = xDMVRCost(clpRngs.comp[COMPONENT_Y].bd, addrL0, m_biLinearBufStride, addrL1, m_biLinearBufStride, dx, dy);if (minCost < ((4 * dx * (dy >> 1/*for alternate line*/)))){//!<判断是否小于阈值notZeroCost = false;break;}pSADsArray[0] = minCost;}if (!minCost){notZeroCost = false;break;}//!<计算25个整像素点对应的costxBIPMVRefine(bd, addrL0, addrL1, minCost, deltaMV, pSADsArray, dx, dy);if (deltaMV[0] == 0 && deltaMV[1] == 0){break;}totalDeltaMV[0] += deltaMV[0];totalDeltaMV[1] += deltaMV[1];pSADsArray += ((deltaMV[1] * (((2 * DMVR_NUM_ITERATION) + 1))) + deltaMV[0]);}totalDeltaMV[0] = (totalDeltaMV[0] << mvShift);totalDeltaMV[1] = (totalDeltaMV[1] << mvShift);//!<计算分像素代价xDMVRSubPixelErrorSurface(notZeroCost, totalDeltaMV, deltaMV, pSADsArray);pu.mvdL0SubPu[num] = Mv(totalDeltaMV[0], totalDeltaMV[1]);num++;}}
//计算整像素点cost
void InterPrediction::xBIPMVRefine(int bd, Pel *pRefL0, Pel *pRefL1, uint64_t& minCost, int16_t *deltaMV, uint64_t *pSADsArray, int width, int height)
{const int32_t refStrideL0 = m_biLinearBufStride;const int32_t refStrideL1 = m_biLinearBufStride;Pel *pRefL0Orig = pRefL0;Pel *pRefL1Orig = pRefL1;for (int nIdx = 0; (nIdx < 25); ++nIdx){//!<计算25个整像素点对应的cost,找出代价最小的int32_t sadOffset = ((m_pSearchOffset[nIdx].getVer() * ((2 * DMVR_NUM_ITERATION) + 1)) + m_pSearchOffset[nIdx].getHor());pRefL0 = pRefL0Orig + m_pSearchOffset[nIdx].hor + (m_pSearchOffset[nIdx].ver * refStrideL0);pRefL1 = pRefL1Orig - m_pSearchOffset[nIdx].hor - (m_pSearchOffset[nIdx].ver * refStrideL1);if (*(pSADsArray + sadOffset) == MAX_UINT64){const uint64_t cost = xDMVRCost(bd, pRefL0, refStrideL0, pRefL1, refStrideL1, width, height);*(pSADsArray + sadOffset) = cost;}if (*(pSADsArray + sadOffset) < minCost){minCost = *(pSADsArray + sadOffset);deltaMV[0] = m_pSearchOffset[nIdx].getHor();deltaMV[1] = m_pSearchOffset[nIdx].getVer();}}
}
//计算分像素点cost
void xSubPelErrorSrfc(uint64_t *sadBuffer, int32_t *deltaMv)
{int64_t numerator, denominator;int32_t mvDeltaSubPel;int32_t mvSubPelLvl = 4;/*1: half pel, 2: Qpel, 3:1/8, 4: 1/16*///!<计算x_min                                                    /*horizontal*/numerator = (int64_t)((sadBuffer[1] - sadBuffer[3]) << mvSubPelLvl);denominator = (int64_t)((sadBuffer[1] + sadBuffer[3] - (sadBuffer[0] << 1)));if (0 != denominator){if ((sadBuffer[1] != sadBuffer[0]) && (sadBuffer[3] != sadBuffer[0])){mvDeltaSubPel = div_for_maxq7(numerator, denominator);deltaMv[0] = (mvDeltaSubPel);}else{if (sadBuffer[1] == sadBuffer[0]){deltaMv[0] = -8;// half pel}else{deltaMv[0] = 8;// half pel}}}/*vertical*/	//!<计算y_min numerator = (int64_t)((sadBuffer[2] - sadBuffer[4]) << mvSubPelLvl);denominator = (int64_t)((sadBuffer[2] + sadBuffer[4] - (sadBuffer[0] << 1)));if (0 != denominator){if ((sadBuffer[2] != sadBuffer[0]) && (sadBuffer[4] != sadBuffer[0])){mvDeltaSubPel = div_for_maxq7(numerator, denominator);deltaMv[1] = (mvDeltaSubPel);}else{if (sadBuffer[2] == sadBuffer[0]){deltaMv[1] = -8;// half pel}else{deltaMv[1] = 8;// half pel}}}return;
}

感兴趣的请关注微信公众号Video Coding

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1380526.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

ARVR技术 | AR, VR, MR和XR?想搞清楚不?

AR, VR, MR&#xff0c;现在还有XR ?这些缩写是什么?它们代表什么? 让我们快速梳理一下技术术语。 首先&#xff0c;虽然你可能熟悉其中的一些术语&#xff0c;如AR和VR, 但MR和XR对许多人来说仍然是新鲜的术语。 目前的共识是&#xff0c;所有这些互补形式的现实都落在一…

MDD(模型驱动开发)

前言导读 当下企业软件应用开发面临着需求复杂多变、新的需求和系统不断增长&#xff0c;软件系统变得越来越复杂&#xff0c;普通的软件开发方式难以快速满足用户需求。为了解决这些问题&#xff0c;就出现了很多新的方法&#xff0c;其中最突出的一个就是模型驱动开发 MDD &a…

RSCMVR

也是之前发了 ~~ 又带来马教授的~~ 神器稀疏卷积性能和稳健性超越ResNet 标题就是简写可好? 尽管深度神经网络在图像分类方面具有很强的经验性能&#xff08;empirical performance&#xff09;&#xff0c;但这类模型往往被视为「黑盒」&#xff0c;最为人诟病的就是「难以解…

EMD和VMD

作者&#xff1a;桂。 时间&#xff1a;2017-03-06 20:57:22 链接&#xff1a;http://www.cnblogs.com/xingshansi/p/6511916.html 前言 本文为Hilbert变换一篇的内容补充&#xff0c;主要内容为&#xff1a; 1&#xff09;EMD原理介绍 2&#xff09;代码分析 3&#xff09…

什么是MDM

MDM或移动设备管理是一种软件应用程序&#xff0c;用于管理企业中的终端&#xff0c;如笔记本电脑、智能手机、平板电脑等。随着越来越多的员工使用这些设备&#xff0c;各种形式和规模的企业现在都转向移动设备管理&#xff0c;以增强数据安全性并提高生产力。 MDM是什么意思…

AVS3中的AMVR和EMVR

在AVS2中运动预测中使用的MV都是1/4像素精度&#xff0c;通过在整像素间插值能显著提升非整像素运动预测的精度&#xff0c;同时带来的问题是随着MV精度的提高编码MVD所需的比特数也会增加。 AMVR AMVR支持的MVD编码5种精度的MVR{1/4,1/2,1,2,4}&#xff0c;索引为0到4&#x…

无线网络视频监控系统基本概念和术语

无线网络视频监控系统基本概念和术语 1.网络摄像机与模拟摄像机的区别 模拟摄像机&#xff0c;或称摄像头&#xff0c;输出CVBS模拟视频信号&#xff0c;PAL制或者NTSC制。模拟摄像机多采用CCD器件&#xff0c;目前也有采用CMOS器件的。有枪机、半球、球机等多种形式&#xff0…

掌握Python的X篇_27_Python中标准库文档查阅方法介绍

前面的博文介绍了python的基本语法、模块及其导入方法。前人将各种方法封装成模块、库、函数供我们使用&#xff0c;如何去使用前人做好的东西&#xff0c;那就需要去查阅文档。今天就介绍python中官方文档的查阅方式。对于初学者而言&#xff0c;python自带的文档就已经足够好…

基本动态规划问题的扩展

基本动态规划问题的扩展 应用动态规划可以有效的解决许多问题&#xff0c;其中有许多问题的数学模型&#xff0c;尤其对一些自从57年就开始研究的基本问题所应用的数学模型&#xff0c;都十分精巧。有关这些问题的解法&#xff0c;我们甚至可以视为标准——也就是最优的解法。…

shell脚本安装nginx

shell脚本原理 以删除桌面文件的脚本为例&#xff0c;执行脚本后&#xff0c;shell脚本将代码给内核&#xff0c;内核读取后执行命令&#xff0c;如果shell脚本也在桌面上&#xff0c;执行后这个脚本文件也会被删除。 变量 echo $SHELL$符表示SHELL是一个变量&#xff0c;变量…

Python(七十九)字符串的常用操作——字符串内容对齐操作的方法

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

docker实现Nginx

文章目录 1.docker 安装2.docker环境实现Nginx 1.docker 安装 1.使用环境为红帽8.1,添加源 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo2.安装 yum install docker-ce docker-ce-cli containerd.io显示出错 Docker C…

Vue [Day7] 综合案例

核心概念回顾 state&#xff1a;提供数据 getters&#xff1a;提供与state相关的计算属性 mutations&#xff1a;提供方法&#xff0c;用于修改state actions&#xff1a;存放异步操作 modules&#xff1a;存模块 功能分析 https://www.npmjs.com/package/json-server#ge…

反介入/区域拒止:现代战争的演变

译者说明 本文译自美国空军Christopher J. McCarthy少校的一篇文章&#xff0c;略去了原文最后的作者简介。 原文地址&#xff08;可能需要科学上网&#xff09;&#xff1a; https://www.usnwc.edu/Lucent/OpenPdf.aspx?id95 本文仅为翻译&#xff0c;不代表译者赞成或反对原…

UE4莫名其妙崩溃的解决办法

pin error stack edgraph balabala...... 先检查蓝图把报错的节点全部去掉&#xff0c;有的运行不会提示蓝图报错&#xff0c;只能一个一个找。。。。 c报错一般都会有提示&#xff0c;所以基本都可以解决 把磁盘空间留大一点,玄学 总是在这里报错&#xff0c;这个不用管&am…

叛乱怎么自定义服务器,» 叛乱:沙漠风暴 服务器安装Mod教程

叛乱:沙漠风暴 服务器安装Mod教程 4.6 (78) 叛乱:沙漠风暴 服务器 租用 v2pg.com 获取API KEY 比如 59f0601123331222f0755f9e8551ea639 就是申请的KEY, 保存好。 打开后台 “服务器设置” 然后编辑 Engine.ini

叛乱联机服务器未响应,叛乱沙漠风暴怎么开服 叛乱沙漠风暴开服操作指南详解 安装准备-游侠网...

叛乱沙漠风暴怎么开服?游戏一款多人联机操作游戏&#xff0c;在开服前期要做好相应的准备工作&#xff0c;也就是设置一些选项&#xff0c;这里给大家带来了“xudong162”分享的叛乱沙漠风暴开服操作指南详解&#xff0c;详情一起看下文中介绍吧。 推荐阅读&#xff1a; 开服操…

叛乱联机服务器未响应,叛乱沙漠风暴开服注意事项及操作指南经验一览

叛乱沙漠风暴开服注意事项及操作指南经验一览&#xff0c;该游戏其实是一款多人联机的操作游戏&#xff0c;玩家在开服前期要做好相应的准备工作&#xff0c;其实也不是什么困难的事&#xff0c;就是设置一些选项方便操作&#xff0c;这里给大家带来了叛乱沙漠风暴开服注意事项…

叛乱2 linux服务器,叛乱沙漠风暴服务器配置教程 叛乱沙漠风暴怎么开服

第 2 页 服务器配置 服务器配置 大多数服务器配置是通过INI文件和启动参数执行的。 可以使用任何纯文本编辑器编辑INI文件&#xff0c;例如Notepad&#xff0c;Notepad &#xff0c;Sublime Text和VSCode。 配置文件的位置位于以下目录中(相对于安装目录)&#xff1a; Windows:…

叛乱找不到社区服务器,叛乱沙漠风暴常见问题及解决方法_叛乱沙漠风暴常见问题QA_游戏堡...

《 1.Q&#xff1a;游戏卡在读取页面怎么办 A&#xff1a;看看你按回车键没 一直读取进不去游戏说明网络不好 直接卡死说明电脑玩不了这游戏了&#xff0c;建议升级配置 2.Q&#xff1a;游戏什么配置可以玩 A&#xff1a;可游玩最低配置&#xff1a;GTX950M&#xff0c;i74700&…