该技术的核心是当前块与参考块之间存在线性光照变化,并且此变化是线性变化。通过当前块和参考块的相邻重构像素(模板),拟合出线性函数a*p[x]+b来补偿光照变化。其中p[x]为参考块,a为缩放因子,b为偏移量,如下图所示

其中a和b利用最小二乘法推导得到:

LIC使用条件:

  • CIIP模式和IBC模式禁用
  • 面积小于32的块禁用
  • LIC flag 没有时域继承性
  • 生成merge候选列表时无需基于LIC flag进行修剪
  • 不可用于双向预测()
  • LIC应用于1616的处理单元时,使用当前CU中左上角1616的单元进行参数推导,并且用于CU内其他部分,如图所示
  • LIC 应用于子块模式,其中 LIC 参数是根据在子块基础上导出的样本导出的,但仅限于左上角的第一个 16x16 处理单元,如图所示

编码端的优化:

  1. 未开启LIC时的运动搜索结果将在LIC开启时重复使用(JVET-MJVET-M0182提出)
  2. 若相邻4 * 4子块的LIC使用率超过阈值TH(0.10),则开启LIC下,以MR-SAD为标准进行运动搜索

代码:
LIC的主函数为xLocalIlluComp,该函数由xPredInterBlk所调用。函数内部主要分为三个步骤:

  1. 获取当前块和参考块的模板像素 ——xGetSublkTemplate函数
  2. 根据模板像素,利用最小二乘法,确定线性变换的参数a、b ——xGetLICParamGeneral函数
  3. 将当前块的像素带入线性变换中,进行光照补偿 ——linearTransform函数
oid InterPrediction::xLocalIlluComp(const PredictionUnit& pu,const ComponentID     compID,const Picture&        refPic,const Mv&             mv,const bool            biPred,PelBuf&               dstBuf
)
{Pel* refLeftTemplate  = m_pcLICRefLeftTemplate;//LJY:用于保存参考块的模板像素Pel* refAboveTemplate = m_pcLICRefAboveTemplate;Pel* recLeftTemplate  = m_pcLICRecLeftTemplate;//LJY:用于保存当前快的模板像素指针Pel* recAboveTemplate = m_pcLICRecAboveTemplate;int numTemplate[2] = { 0 , 0 }; // 0:Above, 1:Left//LJY:获取当前块和参考块的模板像素xGetSublkTemplate(*pu.cu, compID, refPic, mv, pu.blocks[compID].width, pu.blocks[compID].height, 0, 0, numTemplate, refLeftTemplate, refAboveTemplate, recLeftTemplate, recAboveTemplate);//LJY:根据最小二乘法,确定参数a、bint 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);//LJY:将当前块的像素带入表达式,进行线性变换,修正像素值
}

xGetSublkTemplate函数用于获取当前块和参考块的模板像素,其中主要通过xGetPredBlkTpl函数获取。

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();//LJY:获取当前块的像素const CPelBuf refBuf = cuAbove || cuLeft ? refPic.getRecoBuf(refPic.blocks[compID]) : CPelBuf();//LJY:获取参考块的像素std::vector<Pel>& invLUT = m_pcReshape->getInvLUT();// aboveif (cuAbove && posH == 0)//LJY:获取上模板像素{xGetPredBlkTpl<true>(cu, compID, refBuf, mv, posW, posH, sublkWidth, refAboveTemplate);//LJY:获取参考块的模板像素,保存在refAboveTemplateconst Pel*    rec = recBuf.bufAt(cu.blocks[compID].pos().offset(0, -1));for (int k = posW; k < posW + sublkWidth; k++)//LJY:逐点进行处理,移位,放入容器中{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]++;//LJY:该值不为0说明存在上相邻模板,后期拟合系数需要}}// leftif (cuLeft && posW == 0)//LJY:获取左模板像素{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]++;//LJY:该值不为0说明存在左相邻模板,后期拟合系数需要}}
}

xGetLICParamGeneral函数采用最小二乘法,确定亮度变化线性关系中的参数a和b

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;const int       cuHeight = cu.blocks[compID].height;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;//LJY:初始化最小二乘所需的参数// aboveif (numTemplate[0] != 0)//LJY:说明上相邻模板存在,进行拟合,得到最小二乘的参数{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)//LJY:说明左相邻模板存在,进行拟合,得到最小二乘的参数{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);//LJY:缩放ascale = 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;//LJY:偏移量boffset = Clip3(minOffset, maxOffset, offset);
}

【ECM技术】局部光照补偿技术(LIC)相关推荐

  1. 深入剖析iLBC的丢包补偿技术(PLC)

    转自:http://blog.csdn.net/wanggp_2007/article/details/5136609 丢包补偿技术(Packet Loss Concealment--PLC)是iLB ...

  2. 【转】深入剖析iLBC的丢包补偿技术(PLC)

    丢包补偿技术(Packet Loss Concealment--PLC)是iLBC Codec中非常重要的一项技术,更是VOIP Codec应用中不可缺少的组成部分.iLBC的PLC只是在解码端进行封 ...

  3. jlist动态添加元素后刷新_小米电视5再曝光:MEMC动态画质补偿技术

    [TechWeb]10月30日,最近小米对即将发布的小米CC9Pro.小米手表.小米电视5进行了每天一曝的预热,今天小米对小米电视5继续预热,抛出了MEMC动态画质补偿技术. 昨日,小米电视官方微博发 ...

  4. 【模拟IC】系统频率稳定性分析与极点补偿技术介绍

    文章目录 前言 一.负反馈 二.稳定性 2.1直流和低频响应 2.2高频响应 2.3一阶负反馈系统 2.4 二阶负反馈系统 2.5高阶负反馈系统 三.补偿技术 3.1 主极点补偿 3.2 线性补偿技术 ...

  5. 详解运放及其补偿技术

    运放补偿虽然很常见,但有时候也极具挑战性,尤其是在要求和约束条件超过设计师控制的情况下,设计师必须选择一种最优补偿技术之时.也许极具挑战性的原因之一是一般文献资料更多地专注于不同补偿技术之间的区别而不 ...

  6. 液晶电视的MEMC(运动画质补偿技术)的优势不足

    MEMC: Motion Estimate and Motion Compensation;即运动估计和运动补偿,液晶电视中用到的运动画质补偿技术.其原理是采用动态映像系统,在传统的两帧图像之间加插一 ...

  7. 怎么理解集成运放并联电压正反馈_「硬见小百科」详解运放及其补偿技术

    运放补偿虽然很常见,但有时候也极具挑战性,尤其是在要求和约束条件超过设计师控制的情况下,设计师必须选择一种最优补偿技术之时.也许极具挑战性的原因之一是一般文献资料更多地专注于不同补偿技术之间的区别而不 ...

  8. 电容补偿技术的作用(转载)

    电容补偿技术的作用与使用方法 时间:2016-01-21 09:44:20编辑:电工栏目:电容器 导读:有关电容补偿技术的作用与使用方法,电容补偿技术可用于防止涌流.防止系统谐波的影响.防止产生自励, ...

  9. 安科瑞BR系列罗氏线圈变送器,对电网中的交流大电流进行实时测量,采用真有效值和线性补偿技术,将其隔离变换为标准的直流信号输出

    1 .概述 BR系列产品应用电磁感应原理,对电网中的交流大电流进行实时测量,采用真有效值和线性补偿技术,将其隔离变换为标准的直流信号输出.DC24V安全电压供电,具有高精度.高隔离.高安全性.低功耗等 ...

  10. 压力传感器误差补偿技术

    目前市场上压力传感器种类丰富多样,这使得设计工程师可以选择系统所需的压力传感器.这些压力传感器既包括最基本的变送器,也包括更为复杂的带有片上电路的高集成度传感器.由于存在这些差异,设计工程师必须尽可能 ...

最新文章

  1. 修改httpd默认端口号
  2. 快手基于RocketMQ的在线消息系统建设实践
  3. HDU - 4348 To the moon
  4. oFono安装和启动
  5. Xcode9的xib只支持iOS7.0及以上版本
  6. spring教程(上)
  7. 项目管理如何真正实现降本增效?
  8. 步数精灵v4.0霸占好友排行榜首位 安卓版
  9. 认知水平越低,人越固执
  10. 使用R语言制作树状图
  11. gerrit/git操作中遇到的问题
  12. hadoop大数据平台搭建
  13. dell服务器接2k显示器,4K、2K已成主流DELL高分辨率显示器推荐
  14. Coursera | Applied Plotting, Charting Data Representation in Python(UMich)| Assignment3
  15. 首发Metamask小狐狸盗助记词钱包源码
  16. 程序员如何写好简历 一份优秀的程序员简历是什么样的?
  17. air dots 配对_Redmi AirDots可以作为iphone的合格伴侣吗?
  18. 分享三个网页访问(点击)统计脚本,展示访问来源地图分布
  19. 国产AR SDK介绍+国外arSdk带过
  20. java学习笔记(file类):

热门文章

  1. 网络安全策略和网络安全机制
  2. 52单片机蜂鸣器葫芦娃c语言代码,arduino上实现葫芦娃播放
  3. 电脑如何连接无线打印服务器,电脑怎么联接无线路由器打印机
  4. 基于matlab分析的商业保险案例
  5. html5手机端纵向时间轴,html5触屏手机端响应式时间轴内容切换特效
  6. backdrop-filter 与 filter 模糊效果的区别
  7. Java大作业——手把手教你写俄罗斯方块
  8. 帝国CMS7.2管理员密码重置
  9. 学一点Wi-Fi:WEP
  10. CSDN余额充值协议