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.帧内预测各种模式实现的更多相关文章

  1. 【HEVC】2、HM-16.7编码一个CU(帧内部分) 1.帧内预测相邻参考像素获取

    HEVC帧内预测的35中预测模式是在PU基础上定义的,实际帧内预测的过程则以TU为单位.PU以四叉树划分TU,一个PU内所有TU共享同一种预测模式.帧内预测分3个步骤: (1) 判断当前TU相邻像素点 ...

  2. HM中字典编码分析

    LZ77算法基本过程 http://jpkc.zust.edu.cn/2007/dmt/course/MMT03_05_2.htm LZ77压缩算法详解 http://wenku.baidu.com/ ...

  3. JSON C# Class Generator是一个从JSON文本中生成C#内的应用程序

    JSON C# Class Generator是一个从JSON文本中生成C#内的应用程序 .NET平台开源项目速览(18)C#平台JSON实体类生成器JSON C# Class Generator   ...

  4. 判断一个IP地址是否是本局域网内地址

    //        /// <summary>        /// 判断一个IP地址是否是本局域网内地址,是返回true 否则返回false,        /// </summa ...

  5. TensorFlow-Bitcoin-Robot:一个基于 TensorFlow LSTM 模型的 Bitcoin 价格预测机器人

    简介 TensorFlow-Bitcoin-Robot:一个基于 TensorFlow LSTM 模型的 Bitcoin 价格预测机器人. 文章包括一下几个部分: 1.为什么要尝试做这个项目? 2.为 ...

  6. 290.单词模式。给定一种 pattern(模式) 和一个字符串 str ,判断 str 是否遵循相同的模式。(c++方法)

    题目描述: 给定一种 pattern(模式) 和一个字符串 str ,判断 str 是否遵循相同的模式. 这里的遵循指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之 ...

  7. TensorFlow-Bitcoin-Robot:一个基于 TensorFlow LSTM 模型的 Bitcoin 价格预测机器人。

    简介 TensorFlow-Bitcoin-Robot:一个基于 TensorFlow LSTM 模型的 Bitcoin 价格预测机器人. 文章包括一下几个部分: 1.为什么要尝试做这个项目? 2.为 ...

  8. 【python系统学习16】编码基础知识

    编码 计算机是怎么传输和存储数据的? 就是把人类认识的中英文字.其他国家语言.数字甚至运算符等符号转成二进制的0.1,并进行存储和传输. 编码 人类语言:中英文字.其他国家语言.数字甚至运算符等符号 ...

  9. CI Weekly #16 | 从另一个角度看开发效率:flow.ci 数据统计功能上线

    很开心的告诉大家,flow.ci 数据统计功能已正式上线. 进入 flow.ci 控制台,点击「数据分析」按钮,你可以按照时间日期筛选,flow.ci 将多维度地展示「组织与项目」的构建数据指标与模型 ...

随机推荐

  1. ionic的tabs

    <ion-tabs class="tabs-icon-top/bottom(决定这个tabs是置于上面还是底部)  tabs-color-active-positive(图标与字体色) ...

  2. Unix系统小知识(转)

    Unix操作系统的小知识 2.VI添加行号/翻页/清屏 .在对话模式时(即输完Esc再输入: ),输入“:set number”可以将编辑的文本加上行号.跟玩俄罗斯方块一样方便的上下左右移动箭头的快捷 ...

  3. Hbase的flush机制

    Hbase Flush机制最小Flush单元为HRegion,尽量减少CF数量以减少HStrore数量从而减少MemStore的数量,最终减少每次Flush的开销.1.Region级别触发条件:   ...

  4. Python2.7.12开发环境构建(自动补全)

    一.安装readline-devel包 Python的编译安装依赖于这个包 yum -y install readline-devel 二.安装Python2.7.12 Python官方网站(到此处下 ...

  5. Kali Linux 2.0配置并安装常用的工具

    Kali Linux 前身是著名渗透测试系统BackTrack ,是一个基于 Debian 的 Linux 发行版,包含很多安全和取证方面的相关工具. Kali Linux 2.0是基于Debian ...

  6. JSPatch – 动态更新iOS APP

    原文:http://blog.cnbang.net/works/2767/ JSPatch是最近业余做的项目,只需在项目中引入极小的引擎,就可以使用JavaScript调用任何Objective-C的 ...

  7. 00 alv抬头等

    *&---------------------------------------------------------------------* *& Report ZHJ_TEST0 ...

  8. ubuntu下安装rpm 文件

      正想着如何把rpm package 安装到ubuntu上, 发现了这篇文章,转载一下 Ubuntu的软件包格式是deb,如果要安装rpm的包,则要先用alien把rpm转换成deb. sudo a ...

  9. Ubuntu16.04+Tensorlow+caffe+opencv3.1+theano部署

    1.首先安装Ubuntu16.04系统. 2.安装显卡驱动 在官网上下载最新的NVIDIA-Linux-x86_64-375.26.run驱动.然后 Ctrl+Alt+F1进入控制台,输入 sudo ...

  10. ios 写项目的时候遇到的问题及解决方案(3)

    22.看了苹果的文档,里面有这一句话:All launch images must be PNG files and must reside in the top level of your appl ...