HM --帧内预测代码

本文主要介绍了HEVC帧内预测的详细流程,包括遍历预测模式、残差信号处理、率失真代价计算以及预测模式的选择。同时,详细解析了HM编码函数estIntraPredQT的工作过程,涉及快速搜索模式和普通模式下的处理策略,最终确定最优预测模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在做RDOQ算法优化和硬件系统结构设计,建立其时序模型,估算算法的硬件复杂度。在做这部分工作的同时,博主学习了HEVC算法所有的算法原理,为了便于形成完整的知识体系结构,将相关的知识点框架总结如下:

参考博客:https://blog.youkuaiyun.com/NB_vol_1/article/details/55522822

HEVC帧内预测的大致流程是这样的
  • 遍历所有的预测模式,得到每种模式下的残差信号,再对残差信号进行Hadamard变换计算SATD值
  • 利用SATD值计算每种预测模式的率失真代价,选取率失真代价最小的几种模式(与PU大小相关)为预测模式集
  • 将已编码相邻块的预测模式补充到预测模式集中
  • 遍历模式集合中的所有模式,并对残差信号进行正常编码(熵编码),计算率失真代价
  • 选取最优的预测模式作为该PU的最优模式
  • 当亮度块的模式确定之后,把该模式以及DC、planar、水平方向模式、垂直方向模式作为色度块的候选模式,选取最优的模式即可
HM编码函数

入口函数是estIntraPredQT,流程如下:

  • 1.遍历CU下面的每一个PU,对于每一个PU,进行下面的操作
  • 2.先初始化访问相邻像素块的工具类
  • 3.调用initAdiPattern,对参考像素值进行预处理和滤波
  • 4.首先计算需要进行完整RD率失真优化操作的模式的数量numModesForFullRD,可以根据PU的宽度来得到RMD模式的个数与PU的大小有关。PU较小(4x4或8x8)时,RMD个数为8;PU较大(16x16或32x32或64x64)时,RMD个数为3。选择RMD时,uiMode按代价uiCost在CandCostList中从小到大排列在CandModeList中。
  • 5.检测快速搜索标识doFastSearch,通过比较numModesForFullRD和帧内预测模式的总数量(35种)是否相等,如果不相等,那么使用快速搜索模式,否则使用普通模式;(一般来说doFastSearch都是true)
  • 6.如果doFastSearch是true,那么进行下面的操作:
    (1)遍历帧内预测的35种模式,对于每一种模式进行帧内预测,然后使用Hadamard变换计算SATD值,利用SATD的值计算每种模式的率失真代价
    (2)从35个模式中选取numModesForFullRD个代价比较优的模式,组成模式候选列表
    (3)调用getIntraDirLumaPredictor,根据相邻块的预测模式来对当前块的模式进行预测,若干预测模式
    (4)遍历预测模式,如果它不在候选模式列表中,那么把它添加到候选模式列表中
  • 7.如果doFastSearch是false,那么表示numModesForFullRD的数量是35,那么所有的帧内预测模式都被添加到候选模式列表中
  • 8.用一句话表述步骤6和7,那就是,快速搜索模式下,只选取几种最优可能的模式作为候选模式,普通模式下,所有的帧内预测模式都是候选模式
  • 9.遍历候选模式列表,对于其中的每一模式,进行下面的操作:
    (1)调用xRecurIntraCodingQT,进行预测变换量化,注意该函数倒数第二个参数是true,表示会按照四叉树的方式继续向下划分
    (2)根据率失真代价选取最优的模式
  • 10.经过步骤9,我们已经选取了最优的模式,但是该模式下的编码块是继续向下划分的,因此,我们还要计算该模式下,编码块不向下划分的时候的代价(调用xRecurIntraCodingQT,倒数第二个参数设置为false),通过比较编码块划分和不划分两种情况,得到最优的参数和模式
  • 11.经过了上面的步骤之后,我们已经得到最优模式和变换系数了,此时我们应该重建当前块,因为后面的PU需要使用该重建块作为预测块。
/*
** 亮度块的帧内预测的入口函数
*/
Void TEncSearch::estIntraPredQT( TComDataCU* pcCU, 
	TComYuv*    pcOrgYuv, 
	TComYuv*    pcPredYuv, 
	TComYuv*    pcResiYuv, 
	TComYuv*    pcRecoYuv,
	UInt&       ruiDistC,
	Bool        bLumaOnly )
{
   
   
	// 删除无关代码*****
 
	// 候选的cost列表
	Double  CandCostList[ FAST_UDI_MAX_RDMODE_NUM ];
 
	//===== set QP and clear Cbf =====
	// 设置QP参数,清理Cbf
	if ( pcCU->getSlice()->getPPS()->getUseDQP() == true)
	{
   
   
		pcCU->setQPSubParts( pcCU->getQP(0), 0, uiDepth );
	}
	else
	{
   
   
		// 进入此处
		pcCU->setQPSubParts( pcCU->getSlice()->getSliceQp(), 0, uiDepth );
	}
 
	//===== loop over partitions =====
	UInt uiPartOffset = 0;
 
	// 循环处理CU下的每一个预测块PU
	for( UInt uiPU = 0; uiPU < uiNumPU; uiPU++, uiPartOffset += uiQNumParts )
	{
   
   
		//===== init pattern for luma prediction =====
		Bool bAboveAvail = false; // 上面的块是否有效
		Bool bLeftAvail  = false;	// 左边的块是否有效
 
		// 初始化访问相邻块的工具类
		pcCU->getPattern()->initPattern   ( pcCU, uiInitTrDepth, uiPartOffset );
 
		// 这个函数很重要:主要是在着帧内预测之前,使用重建后的YUV图像对当前PU的相邻样点进行滤波,为接下来的进行的角度预测
		// 提供参考样点值
		pcCU->getPattern()->initAdiPattern( pcCU, uiPartOffset, uiInitTrDepth, m_piYuvExt, m_iYuvExtStride, m_iYuvExtHeight, bAboveAvail, bLeftAvail );
 
		//===== determine set of modes to be tested (using prediction signal only) =====
		// 35种帧内预测模式
		Int numModesAvailable     = 35; //total number of Intra modes
 
		// 在原始的YUV中获取获亮度的地址
		Pel* piOrg         = pcOrgYuv ->getLumaAddr( uiPU, uiWidth );
		// 在预测的YUV中获取亮度的地址
		Pel* piPred        = pcPredYuv->getLumaAddr( uiPU, uiWidth );
 
		// 偏移
		UInt uiStride      = pcPredYuv->getStride(); // 8
 
		UInt uiRdModeList[FAST_UDI_MAX_RDMODE_NUM];
		Int numModesForFullRD = g_aucIntraModeNumFast[ uiWidthBit ];//8
 
		Bool doFastSearch = (numModesForFullRD != numModesAvailable);//true
 
		// 使用快速搜索模式
		if (doFastSearch)
		{
   
   
			assert(numModesForFullRD < numModesAvailable);
 
			for( Int i=0; i < numModesForFullRD; i++ ) 
			{
   
   
				// 用于存储每一种模式的消耗
				CandCostList[ i ] = MAX_DOUBLE;
			}
			CandNum = 0;
 
			// 遍历35种帧内预测模式,选取若干个代价比较小的模式作为后续处理的模式
			for( Int modeIdx = 0; modeIdx < numModesAvailable; modeIdx++ ) // 总共有35种模式,numModesAvailable = 35
			{
   
   
				UInt uiMode = modeIdx;
 
				// 对亮度块进行预测
				predIntraLumaAng( pcCU->getPattern(), uiMode, piPred, uiStride, uiWidth, uiHeight, bAboveAvail, bLeftAvail );
 
				// use hadamard transform here
				// 使用hadamard变换,计算SATD的值
				UInt uiSad = m_pcRdCost->calcHAD(g_bitDepthY, piOrg, uiStride, piPred, uiStride, uiWidth, uiHeight );
 
				UInt   iModeBits = xModeBitsIntra( pcCU
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值