【HEVC学习与研究】33、编码一个CU(帧内部分)2:帧内预测各种模式的实现

2023-11-23 04:48

本文主要是介绍【HEVC学习与研究】33、编码一个CU(帧内部分)2:帧内预测各种模式的实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

HEVC中一共定义了35中帧内编码预测模式,编号分别以0-34定义。其中模式0定义为平面模式(INTRA_PLANAR),模式1定义为均值模式(INTRA_DC),模式2~34定义为角度预测模式(INTRA_ANGULAR2~INTRA_ANGULAR34),分别代表了不同的角度。具体的示意图如标准文档的图8-1所示:


这三大类的预测方法均有实现的代码。首先看最简单的Intra_DC模式,该模式同角度预测模式实现在同一个函数Void TComPrediction::xPredIntraAng(...)中:

Void TComPrediction::xPredIntraAng(Int bitDepth, Int* pSrc, Int srcStride, Pel*& rpDst, Int dstStride, UInt width, UInt height, UInt dirMode, Bool blkAboveAvailable, Bool blkLeftAvailable, Bool bFilter )
{//......// Do the DC predictionif (modeDC){Pel dcval = predIntraGetPredValDC(pSrc, srcStride, width, height, blkAboveAvailable, blkLeftAvailable);for (k=0;k<blkSize;k++){for (l=0;l<blkSize;l++){pDst[k*dstStride+l] = dcval;}}}//......
}
在这个函数中可以看到,Intra_DC模式中所有预测块的像素值都是同一个值dcval,这个值是由一个函数predIntraGetPredValDC计算得到:

Pel TComPrediction::predIntraGetPredValDC( Int* pSrc, Int iSrcStride, UInt iWidth, UInt iHeight, Bool bAbove, Bool bLeft )
{Int iInd, iSum = 0;Pel pDcVal;if (bAbove){for (iInd = 0;iInd < iWidth;iInd++){iSum += pSrc[iInd-iSrcStride];}}if (bLeft){for (iInd = 0;iInd < iHeight;iInd++){iSum += pSrc[iInd*iSrcStride-1];}}if (bAbove && bLeft){pDcVal = (iSum + iWidth) / (iWidth + iHeight);}else if (bAbove){pDcVal = (iSum + iWidth/2) / iWidth;}else if (bLeft){pDcVal = (iSum + iHeight/2) / iHeight;}else{pDcVal = pSrc[-1]; // Default DC value already calculated and placed in the prediction array if no neighbors are available}return pDcVal;
}
在该函数中,编码器通过判断上方和左方参考像素是否有效而选择将相应的数据(指针pSrc指向的数据)累加到iSum中,并对这些参考数据取平均返回。所以,在DC模式下,所有预测像素值都是同一个值,也即参考数据的均值,这也是DC模式命名的由来。

第二种预测模式时平面模式,该模式定义在xPredIntraPlanar函数中。

Void TComPrediction::xPredIntraPlanar( Int* pSrc, Int srcStride, Pel* rpDst, Int dstStride, UInt width, UInt height )
{assert(width == height);Int k, l, bottomLeft, topRight;Int horPred;Int leftColumn[MAX_CU_SIZE], topRow[MAX_CU_SIZE], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE];UInt blkSize = width;UInt offset2D = width;UInt shift1D = g_aucConvertToBit[ width ] + 2;UInt shift2D = shift1D + 1;// Get left and above reference column and rowfor(k=0;k<blkSize+1;k++){topRow[k] = pSrc[k-srcStride];leftColumn[k] = pSrc[k*srcStride-1];}// Prepare intermediate variables used in interpolationbottomLeft = leftColumn[blkSize];topRight   = topRow[blkSize];for (k=0;k<blkSize;k++){bottomRow[k]   = bottomLeft - topRow[k];rightColumn[k] = topRight   - leftColumn[k];topRow[k]      <<= shift1D;leftColumn[k]  <<= shift1D;}// Generate prediction signalfor (k=0;k<blkSize;k++){horPred = leftColumn[k] + offset2D;for (l=0;l<blkSize;l++){horPred += rightColumn[k];topRow[l] += bottomRow[l];rpDst[k*dstStride+l] = ( (horPred + topRow[l]) >> shift2D );}}
}
首先从参考数据中获取的是顶行和左列的数据,并记录一下左下角和右上角的两个像素值。然后计算底行和右列的数据,方法是用左下角的像素减去 顶行相应位置的像素得到底行,右上角的像素减去左列相应位置的像素得到右列。预测块中每个像素的数据,就是对应的四个边的像素值的平均。

第三种预测模式,即mode=2~34时采用角度预测模式。实现的方式在xPredIntraAng中:

Void TComPrediction::xPredIntraAng(Int bitDepth, Int* pSrc, Int srcStride, Pel*& rpDst, Int dstStride, UInt width, UInt height, UInt dirMode, Bool blkAboveAvailable, Bool blkLeftAvailable, Bool bFilter )
{Int k,l;Int blkSize        = width;Pel* pDst          = rpDst;// Map the mode index to main prediction direction and angleassert( dirMode > 0 ); //no planarBool modeDC        = dirMode < 2;Bool modeHor       = !modeDC && (dirMode < 18);Bool modeVer       = !modeDC && !modeHor;Int intraPredAngle = modeVer ? (Int)dirMode - VER_IDX : modeHor ? -((Int)dirMode - HOR_IDX) : 0;//计算当前模式同水平/垂直模式之间的角度差Int absAng         = abs(intraPredAngle);Int signAng        = intraPredAngle < 0 ? -1 : 1;// Set bitshifts and scale the angle parameter to block sizeInt angTable[9]    = {0,    2,    5,   9,  13,  17,  21,  26,  32};Int invAngTable[9] = {0, 4096, 1638, 910, 630, 482, 390, 315, 256}; // (256 * 32) / AngleInt invAngle       = invAngTable[absAng];absAng             = angTable[absAng];intraPredAngle     = signAng * absAng;// ......// Do angular predictionselse{Pel* refMain;Pel* refSide;Pel  refAbove[2*MAX_CU_SIZE+1];Pel  refLeft[2*MAX_CU_SIZE+1];// Initialise the Main and Left reference array.if (intraPredAngle < 0){for (k=0;k<blkSize+1;k++){refAbove[k+blkSize-1] = pSrc[k-srcStride-1];}for (k=0;k<blkSize+1;k++){refLeft[k+blkSize-1] = pSrc[(k-1)*srcStride-1];}refMain = (modeVer ? refAbove : refLeft) + (blkSize-1);refSide = (modeVer ? refLeft : refAbove) + (blkSize-1);// Extend the Main reference to the left.Int invAngleSum    = 128;       // rounding for (shift by 8)for (k=-1; k>blkSize*intraPredAngle>>5; k--){invAngleSum += invAngle;refMain[k] = refSide[invAngleSum>>8];}}else{for (k=0;k<2*blkSize+1;k++){refAbove[k] = pSrc[k-srcStride-1];}for (k=0;k<2*blkSize+1;k++){refLeft[k] = pSrc[(k-1)*srcStride-1];}refMain = modeVer ? refAbove : refLeft;refSide = modeVer ? refLeft  : refAbove;}if (intraPredAngle == 0){for (k=0;k<blkSize;k++){for (l=0;l<blkSize;l++){pDst[k*dstStride+l] = refMain[l+1];}}if ( bFilter ){for (k=0;k<blkSize;k++){pDst[k*dstStride] = Clip3(0, (1<<bitDepth)-1, pDst[k*dstStride] + (( refSide[k+1] - refSide[0] ) >> 1) );}}}else{Int deltaPos=0;Int deltaInt;Int deltaFract;Int refMainIndex;for (k=0;k<blkSize;k++){deltaPos += intraPredAngle;deltaInt   = deltaPos >> 5;deltaFract = deltaPos & (32 - 1);if (deltaFract){// Do linear filteringfor (l=0;l<blkSize;l++){refMainIndex        = l+deltaInt+1;pDst[k*dstStride+l] = (Pel) ( ((32-deltaFract)*refMain[refMainIndex]+deltaFract*refMain[refMainIndex+1]+16) >> 5 );}}else{// Just copy the integer samplesfor (l=0;l<blkSize;l++){pDst[k*dstStride+l] = refMain[l+deltaInt+1];}}}}// Flip the block if this is the horizontal modeif (modeHor){Pel  tmp;for (k=0;k<blkSize-1;k++){for (l=k+1;l<blkSize;l++){tmp                 = pDst[k*dstStride+l];pDst[k*dstStride+l] = pDst[l*dstStride+k];pDst[l*dstStride+k] = tmp;}}}}
}
在图8.1中可以看出,模式18的预测方向相当于对角线预测。所以以模式18为分界线,2~17分为水平模式(modeHor),18~33分为垂直模式(modeVer),这样区分有利于减少代码的冗余。另外,从该图中也可以看出,模式10和26即相当于水平模式和垂直模式,在代码中也定义了两个宏HOR_IDX和VER_IDX表示,然后计算当前模式同水平/垂直模式之间的角度差,用intraPredAngle表示。intraPredAngle不同的取值对应的预测方向可以参考图8-2:

图中可见,intraPredAngle的取值可能出现正值或负值。当intraPredAngle取非负值时,垂直模式下只参考上方的参考点,水平模式下只参考左方的参考点;当intraPredAngle取负值的时候,refMain会依照refSide中的数据进行部分扩充,因此会同时参考左方和上方两部分的参考点。当intraPredAngle为0的时候,表示预测模式为10或者26,这是也就是水平或者垂直模式,直接复制参考像素的值就OK了;否则,会对角度做一个判断,如果对应的是参考像素中的整像素点那么就不需要进行计算,直接获取该点数据;如果对应的不是整像素点,那么会按照相邻两点按照“距离”进行加权平均作为参考像素点的值。

除此之外,这个函数还实现了对小于16×16尺寸块实现滤波操作,以及水平模式时将预测矩阵进行转置操作。

大致上Intra预测块的生成方法就这样了,下一个问题在于,参考像素是如何来的?pSrc指针指向的数据又是如何获取的?且听下回。


这篇关于【HEVC学习与研究】33、编码一个CU(帧内部分)2:帧内预测各种模式的实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

使用Vue-ECharts实现数据可视化图表功能

《使用Vue-ECharts实现数据可视化图表功能》在前端开发中,经常会遇到需要展示数据可视化的需求,比如柱状图、折线图、饼图等,这类需求不仅要求我们准确地将数据呈现出来,还需要兼顾美观与交互体验,所... 目录前言为什么选择 vue-ECharts?1. 基于 ECharts,功能强大2. 更符合 Vue

使用WPF实现窗口抖动动画效果

《使用WPF实现窗口抖动动画效果》在用户界面设计中,适当的动画反馈可以提升用户体验,尤其是在错误提示、操作失败等场景下,窗口抖动作为一种常见且直观的视觉反馈方式,常用于提醒用户注意当前状态,本文将详细... 目录前言实现思路概述核心代码实现1、 获取目标窗口2、初始化基础位置值3、创建抖动动画4、动画完成后

uniapp小程序中实现无缝衔接滚动效果代码示例

《uniapp小程序中实现无缝衔接滚动效果代码示例》:本文主要介绍uniapp小程序中实现无缝衔接滚动效果的相关资料,该方法可以实现滚动内容中字的不同的颜色更改,并且可以根据需要进行艺术化更改和自... 组件滚动通知只能实现简单的滚动效果,不能实现滚动内容中的字进行不同颜色的更改,下面实现一个无缝衔接的滚动

C#通过进程调用外部应用的实现示例

《C#通过进程调用外部应用的实现示例》本文主要介绍了C#通过进程调用外部应用的实现示例,以WINFORM应用程序为例,在C#应用程序中调用PYTHON程序,具有一定的参考价值,感兴趣的可以了解一下... 目录窗口程序类进程信息类 系统设置类 以WINFORM应用程序为例,在C#应用程序中调用python程序

利用Python实现可回滚方案的示例代码

《利用Python实现可回滚方案的示例代码》很多项目翻车不是因为不会做,而是走错了方向却没法回头,技术选型失败的风险我们都清楚,但真正能提前规划“回滚方案”的人不多,本文从实际项目出发,教你如何用Py... 目录描述题解答案(核心思路)题解代码分析第一步:抽象缓存接口第二步:实现两个版本第三步:根据 Fea

Go语言使用slices包轻松实现排序功能

《Go语言使用slices包轻松实现排序功能》在Go语言开发中,对数据进行排序是常见的需求,Go1.18版本引入的slices包提供了简洁高效的排序解决方案,支持内置类型和用户自定义类型的排序操作,本... 目录一、内置类型排序:字符串与整数的应用1. 字符串切片排序2. 整数切片排序二、检查切片排序状态:

python利用backoff实现异常自动重试详解

《python利用backoff实现异常自动重试详解》backoff是一个用于实现重试机制的Python库,通过指数退避或其他策略自动重试失败的操作,下面小编就来和大家详细讲讲如何利用backoff实... 目录1. backoff 库简介2. on_exception 装饰器的原理2.1 核心逻辑2.2

Java实现视频格式转换的完整指南

《Java实现视频格式转换的完整指南》在Java中实现视频格式的转换,通常需要借助第三方工具或库,因为视频的编解码操作复杂且性能需求较高,以下是实现视频格式转换的常用方法和步骤,需要的朋友可以参考下... 目录核心思路方法一:通过调用 FFmpeg 命令步骤示例代码说明优点方法二:使用 Jaffree(FF

基于C#实现MQTT通信实战

《基于C#实现MQTT通信实战》MQTT消息队列遥测传输,在物联网领域应用的很广泛,它是基于Publish/Subscribe模式,具有简单易用,支持QoS,传输效率高的特点,下面我们就来看看C#实现... 目录1、连接主机2、订阅消息3、发布消息MQTT(Message Queueing Telemetr

Java实现图片淡入淡出效果

《Java实现图片淡入淡出效果》在现代图形用户界面和游戏开发中,**图片淡入淡出(FadeIn/Out)**是一种常见且实用的视觉过渡效果,它可以用于启动画面、场景切换、轮播图、提示框弹出等场景,通过... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细