【HEVC】4、HM-16.7编码一个CU(帧内部分) 3.帧内预测各种模式实现
HEVC中一共定义了35中帧内编码预测模式,编号分别以0-34定义。其中模式0定义为平面模式(INTRA_PLANAR),模式1定义为均值模式(INTRA_DC),模式2~34定义为角度预测模式(INTRA_ANGULAR2~INTRA_ANGULAR34),分别代表了不同的角度。
最简单的Intra_DC模式,DC模式适用于大面积平摊区域,当前预测值可由其左侧和上方(不包含左上角,左下方和右上方)参考像素的平均值得到。该模式同角度预测模式实现在同一个函数Void TComPrediction::xPredIntraAng(...)中:
Void TComPrediction::xPredIntraAng( Int bitDepth,
const Pel* pSrc, Int srcStride,
Pel* pTrueDst, Int dstStrideTrue,
UInt uiWidth, UInt uiHeight, ChannelType channelType,
UInt dirMode, const Bool bEnableEdgeFilters
)
{
Int width=Int(uiWidth);
Int height=Int(uiHeight); // Map the mode index to main prediction direction and angle
assert( dirMode != PLANAR_IDX ); //no planar
const Bool modeDC = dirMode==DC_IDX; // Do the DC prediction
if (modeDC)
{
const Pel dcval = predIntraGetPredValDC(pSrc, srcStride, width, height); for (Int y=height;y>;y--, pTrueDst+=dstStrideTrue)
{
for (Int x=; x<width;) // width is always a multiple of 4.
{
pTrueDst[x++] = dcval;
}
}
}
else // Do angular predictions
{
//........ }
}
在这个函数中可以看到,Intra_DC模式中所有预测块的像素值都是同一个值dcval,这个值是由一个函数predIntraGetPredValDC计算得到:
Pel TComPrediction::predIntraGetPredValDC( const Pel* pSrc, Int iSrcStride, UInt iWidth, UInt iHeight)
{
assert(iWidth > && iHeight > );
Int iInd, iSum = ;
Pel pDcVal; for (iInd = ;iInd < iWidth;iInd++)
{
iSum += pSrc[iInd-iSrcStride];//左列参考像素总和
}
for (iInd = ;iInd < iHeight;iInd++)
{
iSum += pSrc[iInd*iSrcStride-];//上方行参考像素总和
} pDcVal = (iSum + iWidth) / (iWidth + iHeight);//取平均值 return pDcVal;
}
其次是Planar模式,该模式定义在xPredIntraPlanar函数中。适用于像素值缓慢变化的区域,Planar使用水平和垂直方向的两个线性滤波器,并将二者的平均值作为当前像素的预测值。Planar能够使像素平缓变化,与其他模式相比能够提升视频的主管质量。
Void TComPrediction::xPredIntraPlanar( const Pel* pSrc, Int srcStride, Pel* rpDst, Int dstStride, UInt width, UInt height )
{
assert(width <= height); Int leftColumn[MAX_CU_SIZE+], topRow[MAX_CU_SIZE+], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE];
UInt shift1Dhor = g_aucConvertToBit[ width ] + ;
UInt shift1Dver = g_aucConvertToBit[ height ] + ; // Get left and above reference column and row
for(Int k=;k<width+;k++)//记录顶行数据
{
topRow[k] = pSrc[k-srcStride];
} for (Int k=; k < height+; k++)//记录左列数据
{
leftColumn[k] = pSrc[k*srcStride-];
} // Prepare intermediate variables used in interpolation
Int bottomLeft = leftColumn[height];//左下角像素值
Int topRight = topRow[width];//右上角像素值
/*计算底行的数据,方法是用左下角的像素减去顶行相应位置的像素得到底行。*/
for(Int k=;k<width;k++)
{
bottomRow[k] = bottomLeft - topRow[k];
topRow[k] <<= shift1Dver;
}
/*计算右列的数据,方法是用右上角的像素减去左列相应位置的像素得到右列。*/
for(Int k=;k<height;k++)
{
rightColumn[k] = topRight - leftColumn[k];
leftColumn[k] <<= shift1Dhor;
} const UInt topRowShift = ; // Generate prediction signal
for (Int y=;y<height;y++)
{
Int horPred = leftColumn[y] + width;
for (Int x=;x<width;x++)
{
horPred += rightColumn[y];//竖直方向(x,y)预测值
topRow[x] += bottomRow[x]; Int vertPred = ((topRow[x] + topRowShift)>>topRowShift);//水平方向(x,y)预测值
rpDst[y*dstStride+x] = ( horPred + vertPred ) >> (shift1Dhor+);//预测像素是水平和垂直两个方向预测值得平均值
}
}
}
最后是角度预测,mode=2~34时采用角度预测模式。实现的方式在xPredIntraAng中:
Void TComPrediction::xPredIntraAng( Int bitDepth,
const Pel* pSrc, Int srcStride,
Pel* pTrueDst, Int dstStrideTrue,
UInt uiWidth, UInt uiHeight, ChannelType channelType,
UInt dirMode, const Bool bEnableEdgeFilters
)
{
Int width=Int(uiWidth);
Int height=Int(uiHeight); // Map the mode index to main prediction direction and angle
assert( dirMode != PLANAR_IDX ); //no planar
const Bool modeDC = dirMode==DC_IDX; // Do the DC prediction
if (modeDC)
{
const Pel dcval = predIntraGetPredValDC(pSrc, srcStride, width, height); for (Int y=height;y>;y--, pTrueDst+=dstStrideTrue)
{
for (Int x=; x<width;) // width is always a multiple of 4.
{
pTrueDst[x++] = dcval;
}
}
}
else // Do angular predictions
{
const Bool bIsModeVer = (dirMode >= );
const Int intraPredAngleMode = (bIsModeVer) ? (Int)dirMode - VER_IDX : -((Int)dirMode - HOR_IDX);
const Int absAngMode = abs(intraPredAngleMode);
const Int signAng = intraPredAngleMode < ? - : ;
const Bool edgeFilter = bEnableEdgeFilters && isLuma(channelType) && (width <= MAXIMUM_INTRA_FILTERED_WIDTH) && (height <= MAXIMUM_INTRA_FILTERED_HEIGHT); // Set bitshifts and scale the angle parameter to block size
static const Int angTable[] = {, , , , , , , , };
static const Int invAngTable[] = {, , , , , , , , }; // (256 * 32) / Angle
Int invAngle = invAngTable[absAngMode];
Int absAng = angTable[absAngMode];
Int intraPredAngle = signAng * absAng; Pel* refMain;
Pel* refSide; Pel refAbove[*MAX_CU_SIZE+];
Pel refLeft[*MAX_CU_SIZE+]; // Initialize the Main and Left reference array.
if (intraPredAngle < )
{
const Int refMainOffsetPreScale = (bIsModeVer ? height : width ) - ;
const Int refMainOffset = height - ;
for (Int x=;x<width+;x++)
{
refAbove[x+refMainOffset] = pSrc[x-srcStride-];
}
for (Int y=;y<height+;y++)
{
refLeft[y+refMainOffset] = pSrc[(y-)*srcStride-];
}
refMain = (bIsModeVer ? refAbove : refLeft) + refMainOffset;
refSide = (bIsModeVer ? refLeft : refAbove) + refMainOffset; // Extend the Main reference to the left.
Int invAngleSum = ; // rounding for (shift by 8)
for (Int k=-; k>(refMainOffsetPreScale+)*intraPredAngle>>; k--)
{
invAngleSum += invAngle;
refMain[k] = refSide[invAngleSum>>];
}
}
else
{
for (Int x=;x<*width+;x++)
{
refAbove[x] = pSrc[x-srcStride-];
}
for (Int y=;y<*height+;y++)
{
refLeft[y] = pSrc[(y-)*srcStride-];
}
refMain = bIsModeVer ? refAbove : refLeft ;
refSide = bIsModeVer ? refLeft : refAbove;
} // swap width/height if we are doing a horizontal mode:
Pel tempArray[MAX_CU_SIZE*MAX_CU_SIZE];
const Int dstStride = bIsModeVer ? dstStrideTrue : MAX_CU_SIZE;
Pel *pDst = bIsModeVer ? pTrueDst : tempArray;
if (!bIsModeVer)
{
std::swap(width, height);
} if (intraPredAngle == ) // pure vertical or pure horizontal
{
for (Int y=;y<height;y++)
{
for (Int x=;x<width;x++)
{
pDst[y*dstStride+x] = refMain[x+];
}
} if (edgeFilter)
{
for (Int y=;y<height;y++)
{
pDst[y*dstStride] = Clip3 (, (( << bitDepth) - ), pDst[y*dstStride] + (( refSide[y+] - refSide[] ) >> ) );
}
}
}
else
{
Pel *pDsty=pDst; for (Int y=, deltaPos=intraPredAngle; y<height; y++, deltaPos+=intraPredAngle, pDsty+=dstStride)
{
const Int deltaInt = deltaPos >> ;
const Int deltaFract = deltaPos & ( - ); if (deltaFract)
{
// Do linear filtering
const Pel *pRM=refMain+deltaInt+;
Int lastRefMainPel=*pRM++;
for (Int x=;x<width;pRM++,x++)
{
Int thisRefMainPel=*pRM;
pDsty[x+] = (Pel) ( ((-deltaFract)*lastRefMainPel + deltaFract*thisRefMainPel +) >> );
lastRefMainPel=thisRefMainPel;
}
}
else
{
// Just copy the integer samples
for (Int x=;x<width; x++)
{
pDsty[x] = refMain[x+deltaInt+];
}
}
}
} // Flip the block if this is the horizontal mode
if (!bIsModeVer)
{
for (Int y=; y<height; y++)
{
for (Int x=; x<width; x++)
{
pTrueDst[x*dstStrideTrue] = pDst[x];
}
pTrueDst++;
pDst+=dstStride;
}
}
}
}
帧内预测是在TComPrediction::predIntraAng(...)实现:
Void TComPrediction::predIntraAng( const ComponentID compID, UInt uiDirMode, Pel* piOrg /* Will be null for decoding */, UInt uiOrgStride, Pel* piPred, UInt uiStride, TComTU &rTu, const Bool bUseFilteredPredSamples, const Bool bUseLosslessDPCM )
{
const ChannelType channelType = toChannelType(compID);
const TComRectangle &rect = rTu.getRect(isLuma(compID) ? COMPONENT_Y : COMPONENT_Cb);
const Int iWidth = rect.width;
const Int iHeight = rect.height; assert( g_aucConvertToBit[ iWidth ] >= ); // 4x 4
assert( g_aucConvertToBit[ iWidth ] <= ); // 128x128
//assert( iWidth == iHeight ); Pel *pDst = piPred; // get starting pixel in block
const Int sw = ( * iWidth + ); if ( bUseLosslessDPCM )//如果预测方式为垂直或水平,则bUseLosslessDPCM =1
{
const Pel *ptrSrc = getPredictorPtr( compID, false );
// Sample Adaptive intra-Prediction (SAP)
if (uiDirMode==HOR_IDX)//竖直方向预测
{
// left column filled with reference samples
// remaining columns filled with piOrg data (if available).
for(Int y=; y<iHeight; y++)
{
piPred[y*uiStride+] = ptrSrc[(y+)*sw];
}
if (piOrg!=)
{
piPred+=; // miss off first column
for(Int y=; y<iHeight; y++, piPred+=uiStride, piOrg+=uiOrgStride)
{
memcpy(piPred, piOrg, (iWidth-)*sizeof(Pel));
}
}
}
else // VER_IDX 水平方向预测
{
// top row filled with reference samples
// remaining rows filled with piOrd data (if available)
for(Int x=; x<iWidth; x++)
{
piPred[x] = ptrSrc[x+];
}
if (piOrg!=)
{
piPred+=uiStride; // miss off the first row
for(Int y=; y<iHeight; y++, piPred+=uiStride, piOrg+=uiOrgStride)
{
memcpy(piPred, piOrg, iWidth*sizeof(Pel));
}
}
}
}
else //平面和角度预测
{
const Pel *ptrSrc = getPredictorPtr( compID, bUseFilteredPredSamples ); if ( uiDirMode == PLANAR_IDX )
{
xPredIntraPlanar( ptrSrc+sw+, sw, pDst, uiStride, iWidth, iHeight );
}
else
{
// Create the prediction
TComDataCU *const pcCU = rTu.getCU();
const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
const Bool enableEdgeFilters = !(pcCU->isRDPCMEnabled(uiAbsPartIdx) && pcCU->getCUTransquantBypass(uiAbsPartIdx));
#if O0043_BEST_EFFORT_DECODING
const Int channelsBitDepthForPrediction = rTu.getCU()->getSlice()->getSPS()->getStreamBitDepth(channelType);
#else
const Int channelsBitDepthForPrediction = rTu.getCU()->getSlice()->getSPS()->getBitDepth(channelType);
#endif
xPredIntraAng( channelsBitDepthForPrediction, ptrSrc+sw+, sw, pDst, uiStride, iWidth, iHeight, channelType, uiDirMode, enableEdgeFilters ); if( uiDirMode == DC_IDX )
{
xDCPredFiltering( ptrSrc+sw+, sw, pDst, uiStride, iWidth, iHeight, channelType );
}
}
} }
【HEVC】4、HM-16.7编码一个CU(帧内部分) 3.帧内预测各种模式实现的更多相关文章
- 【HEVC】2、HM-16.7编码一个CU(帧内部分) 1.帧内预测相邻参考像素获取
HEVC帧内预测的35中预测模式是在PU基础上定义的,实际帧内预测的过程则以TU为单位.PU以四叉树划分TU,一个PU内所有TU共享同一种预测模式.帧内预测分3个步骤: (1) 判断当前TU相邻像素点 ...
- HM中字典编码分析
LZ77算法基本过程 http://jpkc.zust.edu.cn/2007/dmt/course/MMT03_05_2.htm LZ77压缩算法详解 http://wenku.baidu.com/ ...
- JSON C# Class Generator是一个从JSON文本中生成C#内的应用程序
JSON C# Class Generator是一个从JSON文本中生成C#内的应用程序 .NET平台开源项目速览(18)C#平台JSON实体类生成器JSON C# Class Generator ...
- 判断一个IP地址是否是本局域网内地址
// /// <summary> /// 判断一个IP地址是否是本局域网内地址,是返回true 否则返回false, /// </summa ...
- TensorFlow-Bitcoin-Robot:一个基于 TensorFlow LSTM 模型的 Bitcoin 价格预测机器人
简介 TensorFlow-Bitcoin-Robot:一个基于 TensorFlow LSTM 模型的 Bitcoin 价格预测机器人. 文章包括一下几个部分: 1.为什么要尝试做这个项目? 2.为 ...
- 290.单词模式。给定一种 pattern(模式) 和一个字符串 str ,判断 str 是否遵循相同的模式。(c++方法)
题目描述: 给定一种 pattern(模式) 和一个字符串 str ,判断 str 是否遵循相同的模式. 这里的遵循指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之 ...
- TensorFlow-Bitcoin-Robot:一个基于 TensorFlow LSTM 模型的 Bitcoin 价格预测机器人。
简介 TensorFlow-Bitcoin-Robot:一个基于 TensorFlow LSTM 模型的 Bitcoin 价格预测机器人. 文章包括一下几个部分: 1.为什么要尝试做这个项目? 2.为 ...
- 【python系统学习16】编码基础知识
编码 计算机是怎么传输和存储数据的? 就是把人类认识的中英文字.其他国家语言.数字甚至运算符等符号转成二进制的0.1,并进行存储和传输. 编码 人类语言:中英文字.其他国家语言.数字甚至运算符等符号 ...
- CI Weekly #16 | 从另一个角度看开发效率:flow.ci 数据统计功能上线
很开心的告诉大家,flow.ci 数据统计功能已正式上线. 进入 flow.ci 控制台,点击「数据分析」按钮,你可以按照时间日期筛选,flow.ci 将多维度地展示「组织与项目」的构建数据指标与模型 ...
随机推荐
- Groovy入门教程
Groovy入门教程 kmyhy@126.com 2009-5-13 一.groovy是什么 简单地说,Groovy 是下一代的java语言,跟java一样,它也运行在 JVM 中. 作为跑在JVM ...
- Enhanced Mitigation Experience Toolkit 软件安全性强化工具
Enhanced Mitigation Experience Toolkit软件是微软为应对互联网中层出不穷的漏洞而推出的一款安全工具,可以在Window Update未获取到补丁前,对系统进行保护. ...
- 【我是老中医】VMware在win8.1下开Ubuntu提示”内部错误"解决方案
这个题目起得很洋气啊,其实问题也比较好解决,但是我想多码几个字!!! 友情提示:如果不想看废话,请直接看最后的红字! 好的,咱们从头说(废话)起.话说我们学院每年都会组织大三的进行校企联合实训(其实就 ...
- JSPatch 实现原理详解
原文地址https://github.com/bang590/JSPatch/wiki/JSPatch-%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%E8%AF%A6%E8 ...
- 【OpenGL】 第一篇 OpenGL概览
---------------------------------------------------------------------------------------------------- ...
- error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
以前一直用的VC6.0,最近换成VS2010了.哎这几天光折腾VS2010了. 曾经我以为程序没啥头绪忒头疼,现在觉得乱七八糟的编译问题才叫一个头裂=口= 原因:VC6.0中,如果没有直接显示指定的返 ...
- 成员资格、授权 – ASP.NET MVC 4 系列
ASP.NET MVC 不像 ASP.NET WEB FORMS 那样提供了很多自动保护机制来保护页面不受恶意用户的攻击,更明确的说,后者是致力于使应用程序免受攻击: 服务器组件对显示的 ...
- Ext GridPanel
Extjs GridPanel用法详解 创建GridPanel 要使用GridPanel,首先要定义Store,而在创建Store的时候必须要有Model,因此我们首先来定义Model: //1.定义 ...
- C(C++)输入输出格式
c&c++输入输出控制格式 许多情况下,都需要控制输出结果的表现形式.如输出宽度.输出精度.输出格式等.C++的iomanip.h中定义了许多控制符,这些控制符可以直接插入到流中,控制数据的输 ...
- SQL NULL 值【摘自W3C】
SQL NULL 值 本章讲解 IS NULL 和 IS NOT NULL 操作符. NULL 值是遗漏的未知数据.默认地,表的列可以存放 NULL 值. 如果表中的某个列是可选的,那么我们可以在不向 ...