ECM技术学习:单向局部光照补偿(unidirectional local illumination compensation)

本文主要是介绍ECM技术学习:单向局部光照补偿(unidirectional local illumination compensation),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

局部光照补偿 (local illumination compensation,LIC)技术基于光照变化的线性模型,认为当前块和参考块之间存在线性关系,表示为α*p[x]+β,其中p[x]是当前块单向预测MV指向的参考块,α和β是分别是缩放因子和偏移项,通过当前块模板和参考块模板(下图蓝色区域)推导得到,如下图所示。

 LIC的使用条件:

  • 仅用于帧间单向预测
  • 对亮度样本少于32的块禁用 LIC
  • 参考块模板的样本是通过使用当前块MV运动补偿生成的,无需将其舍入到整数像素精度
  • 不和CIIPIBC共同使用
  • LIC用于亮度、色度分量

LIC的线性模型参数是通过当前块的模板像素(相邻重建像素,模板宽度为1)和参考块的模板像素(当前块的模板通过使用当前块的MV通过MC生成的)通过最小二乘法构造的,主要包括以下两种情况:

(1)对于非子块模式,LIC 参数推导是基于当前CU对应的模板块样本,如下图所示,LIC的参数是通过当前CU的模板样本(左图的蓝色像素点)和参考CU的模板样本(右图的黄色像素点)通过最小二乘法推导得到。

 (2)对于子块模型(Affine),LIC 参数基于边界子块导出,导出的单个模型应用于整个块,如下图所示,由于每个子Pu的MV各不相同,因此参考块的模板样本是通过边界各个子PU的MV各自进行运动补偿后得到的样本拼接而成(右图黄色像素点)。

 最小二乘法的计算公式如下图所示,其中ref指代参考模板样本,Cur指代的是当前模板样本

相关代码:

xLocalIlluComp函数是LIC技术的关键代码,主要包括:

  • 调用xGetSublkTemplate函数获取重建模板和参考模板
  • xGetLICParamGeneral函数计算线性参数alpha和beta
  • linearTransform函数进行线性变换
void InterPrediction::xLocalIlluComp(const PredictionUnit& pu,const ComponentID     compID,const Picture&        refPic,const Mv&             mv,const bool            biPred,PelBuf&               dstBuf
)
{Pel* refLeftTemplate  = m_pcLICRefLeftTemplate; // 左侧参考模板Pel* refAboveTemplate = m_pcLICRefAboveTemplate; // 上参考模板Pel* recLeftTemplate  = m_pcLICRecLeftTemplate; // 左相邻重建模板Pel* recAboveTemplate = m_pcLICRecAboveTemplate; // 上相邻重建模板int numTemplate[2] = { 0 , 0 }; // 0:Above 上侧模板可用像素数, 1:Left左侧模板可用像素数// 获取重建模板和参考模板xGetSublkTemplate(*pu.cu, compID, refPic, mv, pu.blocks[compID].width, pu.blocks[compID].height, 0, 0, numTemplate, refLeftTemplate, refAboveTemplate, recLeftTemplate, recAboveTemplate);// 计算线性参数alpha和betaint shift = 0, scale = 0, offset = 0;xGetLICParamGeneral(*pu.cu, compID, numTemplate, refLeftTemplate, refAboveTemplate, recLeftTemplate, recAboveTemplate, shift, scale, offset);const ClpRng& clpRng = pu.cu->cs->slice->clpRng(compID);dstBuf.linearTransform(scale, shift, offset, true, clpRng); 
}

 xGetSublkTemplate函数用来重建模板和参考模板,参考模板是通过xGetPredBlkTpl函数,使用当前块的MV进行运动补偿得到的。

void InterPrediction::xGetSublkTemplate(const CodingUnit& cu,const ComponentID compID,const Picture&    refPic,const Mv&         mv,const int         sublkWidth,const int         sublkHeight,const int         posW,const int         posH,int*              numTemplate,Pel*              refLeftTemplate,Pel*              refAboveTemplate,Pel*              recLeftTemplate,Pel*              recAboveTemplate)
{const int       bitDepth = cu.cs->sps->getBitDepth(toChannelType(compID));const int       precShift = std::max(0, bitDepth - 12);const Picture&  currPic = *cu.cs->picture; // 当前重建图const CodingUnit* const cuAbove = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID)); const CodingUnit* const cuLeft = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID));const CPelBuf recBuf = cuAbove || cuLeft ? currPic.getRecoBuf(cu.cs->picture->blocks[compID]) : CPelBuf();const CPelBuf refBuf = cuAbove || cuLeft ? refPic.getRecoBuf(refPic.blocks[compID]) : CPelBuf();std::vector<Pel>& invLUT = m_pcReshape->getInvLUT();// above 上侧模板if (cuAbove && posH == 0){// 通过运动补偿获取上参考模板xGetPredBlkTpl<true>(cu, compID, refBuf, mv, posW, posH, sublkWidth, refAboveTemplate);// 当前块相邻重建像素const Pel*    rec = recBuf.bufAt(cu.blocks[compID].pos().offset(0, -1));for (int k = posW; k < posW + sublkWidth; k++){int refVal = refAboveTemplate[k];int recVal = rec[k];if (isLuma(compID) && cu.cs->picHeader->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()){recVal = invLUT[recVal];}recVal >>= precShift;refVal >>= precShift;refAboveTemplate[k] = refVal;recAboveTemplate[k] = recVal;numTemplate[0]++; // 上侧模板计数 + 1}}// left 左侧模板if (cuLeft && posW == 0){xGetPredBlkTpl<false>(cu, compID, refBuf, mv, posW, posH, sublkHeight, refLeftTemplate);const Pel*    rec = recBuf.bufAt(cu.blocks[compID].pos().offset(-1, 0));for (int k = posH; k < posH + sublkHeight; k++){int refVal = refLeftTemplate[k];int recVal = rec[recBuf.stride * k];if (isLuma(compID) && cu.cs->picHeader->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()){recVal = invLUT[recVal];}recVal >>= precShift;refVal >>= precShift;refLeftTemplate[k] = refVal;recLeftTemplate[k] = recVal;numTemplate[1]++; // 左侧模板计数 + 1}}
}

xGetLICParamGeneral函数计算线性参数α和β

void InterPrediction::xGetLICParamGeneral(const CodingUnit& cu,const ComponentID compID,int*              numTemplate,Pel*              refLeftTemplate,Pel*              refAboveTemplate,Pel*              recLeftTemplate,Pel*              recAboveTemplate,int&              shift,int&              scale,int&              offset
)
{const int       cuWidth = cu.blocks[compID].width; // CU的宽度const int       cuHeight = cu.blocks[compID].height; // CU的高度const int       bitDepth = cu.cs->sps->getBitDepth(toChannelType(compID));const int       precShift = std::max(0, bitDepth - 12);const int       maxNumMinus1 = 30 - 2 * std::min(bitDepth, 12) - 1;const int       minDimBit = floorLog2(std::min(cuHeight, cuWidth));const int       minDim = 1 << minDimBit; // 最小的维度尺寸(宽度和高度较小的尺寸)int       minStepBit = minDim > 8 ? 1 : 0;while (minDimBit > minStepBit + maxNumMinus1) { minStepBit++; } //make sure log2(2*minDim/tmpStep) + 2*min(bitDepth,12) <= 30const int       numSteps = minDim >> minStepBit; // 上模板和左侧模板选取相同数目的像素const int       dimShift = minDimBit - minStepBit;//----- get correlation data -----int x = 0, y = 0, xx = 0, xy = 0, cntShift = 0;// aboveif (numTemplate[0] != 0){for (int k = 0; k < numSteps; k++){CHECK(((k * cuWidth) >> dimShift) >= cuWidth, "Out of range");int refVal = refAboveTemplate[((k * cuWidth) >> dimShift)];int recVal = recAboveTemplate[((k * cuWidth) >> dimShift)];x += refVal;y += recVal;xx += refVal * refVal;xy += refVal * recVal;}cntShift = dimShift;}// leftif (numTemplate[1] != 0){for (int k = 0; k < numSteps; k++){CHECK(((k * cuHeight) >> dimShift) >= cuHeight, "Out of range");int refVal = refLeftTemplate[((k * cuHeight) >> dimShift)];int recVal = recLeftTemplate[((k * cuHeight) >> dimShift)];x += refVal;y += recVal;xx += refVal * refVal;xy += refVal * recVal;}cntShift += (cntShift ? 1 : dimShift);}//----- determine scale and offset -----shift = m_LICShift;if (cntShift == 0){scale = (1 << shift);offset = 0;return;}const int cropShift = std::max(0, bitDepth - precShift + cntShift - 15);const int xzOffset = (xx >> m_LICRegShift);const int sumX = x << precShift;const int sumY = y << precShift;const int sumXX = ((xx + xzOffset) >> (cropShift << 1)) << cntShift;const int sumXY = ((xy + xzOffset) >> (cropShift << 1)) << cntShift;const int sumXsumX = (x >> cropShift) * (x >> cropShift);const int sumXsumY = (x >> cropShift) * (y >> cropShift);int a1 = sumXY - sumXsumY;int a2 = sumXX - sumXsumX;int scaleShiftA2 = getMSB(abs(a2)) - 6;int scaleShiftA1 = scaleShiftA2 - m_LICShiftDiff;scaleShiftA2 = std::max(0, scaleShiftA2);scaleShiftA1 = std::max(0, scaleShiftA1);const int scaleShiftA = scaleShiftA2 + 15 - shift - scaleShiftA1;a1 = a1 >> scaleShiftA1;a2 = Clip3(0, 63, a2 >> scaleShiftA2);scale = int((int64_t(a1) * int64_t(m_LICMultApprox[a2])) >> scaleShiftA); // scale = a1 /  a2,此处应该是为了避免除法将a2映射到小数了scale = Clip3(0, 1 << (shift + 2), scale);const int maxOffset = (1 << (bitDepth - 1)) - 1;const int minOffset = -1 - maxOffset;offset = (sumY - ((scale * sumX) >> shift) + ((1 << (cntShift)) >> 1)) >> cntShift;offset = Clip3(minOffset, maxOffset, offset);
}

这篇关于ECM技术学习:单向局部光照补偿(unidirectional local illumination compensation)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/188753

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

金融业开源技术 术语

金融业开源技术  术语 1  范围 本文件界定了金融业开源技术的常用术语。 本文件适用于金融业中涉及开源技术的相关标准及规范性文件制定和信息沟通等活动。

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识