编码块划分

CTU划分

现在的视频编码都是基于块进行的,将一帧视频划分成不同的块,然后对每个块再分别进行编码处理。由于原始YUV格式视频有3个通道,一个亮度通道Y,两个色度通道UV,这里块的划分以亮度通道Y为例,色度通道类似。

在H.264中,一帧图像首先被划分为大小相同的16x16的块,称为宏块(Marco Block,MB),宏块还可以进一步划分,划分方式如下。所以H.264支持7种尺寸的宏块,16x16,16x8,8x16,8x8,8x4,4x8,4x4,最小的宏块尺寸为4x4

H.265里块的划分更加灵活尺寸也更多变,一帧图像首先被划分为64x64大小的编码树单元(Coding Tree Unit,CTU),一个CTU由一个亮度编码树块(Coding Tree Block,CTB),和两个对应的色度CTB及相应的句法元素构成。对于亮度CTB其按四叉树的方式向下划分,最大为64x64,最小为8x8,划分方式如下。

可见1个64x64的CTB可以划分为4个32x32的CTB,每个32x32的CTB又可以划分为4个16x16的CTB,每个16x16的CTB可划分为4个8x8的CTB。最小的亮度CTB为8x8,所以最多只能划分3层。四叉树划分这种划分方式的表示也很容易,只要给出其划分深度就能知道块的大小。

CTB的划分在有的图像上还有问题,例如对于高清视频,每帧图像分辨率为1920x1080,若划分为64x64的块,则每行有30块,而1080/64=16.875不是整数,所以最下边1行块必须进一步划分,使整帧图像划分为30x17CTBs,如下图所示。

PU划分

当CTU划分成CU后,每个CU还要进行预测、变换等。当进行预测时,CU还要继续划分为不同的预测单元(Predict Unit,PU)。(关于预测是怎么进行的会在后面的文章中介绍,现在只需要知道预测分为帧内预测和帧间预测两类)。PU是进行预测的基本单元,一个CU内的所有PU的预测方式相同都为帧内预测或都为帧间预测。且CU到PU只允许一层划分,其划分方式如下。

一共8种划分方式,4种对称划分,2Nx2N(即不划分,整个CU就是一个PU),2NxN, Nx2N, NxN,和4种不对称划分,2NxnU, 2NxnD, nLx2N, nRx2N,不对称划分都是在1/4处进行划分,例如32x32的块进行2NxnU划分会分成一个32x8的块和一个32x24的块,H.265规定只有在亮度CU尺寸大于等于16x16时才允许不对称划分。

帧间预测的CU划分成PU可以按上面8种任意模式划分。而帧内预测的CU若尺寸大于8x8则只能按2Nx2N模式划分,若帧内预测CU尺寸等于8x8可以按NxN划分成4个4x4的PU,此时对应的两个色度PU也为4x4而不是2x2因为H.265里最小的块为4x4。

TU划分

当CU完成预测后,就要进行变换,CU会划分成不同的变换单元(Transform Unit,TU)。TU是进行变换和量化的基本单元,和PU类似TU也是在CU基础上划分,但是PU和TU的划分互不影响。TU的划分方式和CTU类似,也是四叉树划分,因为CU完成预测后CU内的值不再是像素值而是残差值,所以CU按四叉树方式划分成TU后会形成一个残差四叉树(Residual Quad Tree,RQT),CU是树根,TU是树叶,由于CU和TU都是按四叉树划分形成的,所以CU和TU都是方形的。

上图中红色边缘的块就是划分成的TU,TU最大尺寸为64x64,最小为4x4,但是由于DCT变换运算的最大尺寸为32x32,所以64x64的TU隐含着必须进一步划分成4个32x32的TU。同样若亮度TU为4x4其对应的2个色度TU也是4x4而不进一步划分。

下面是一个划分实例。

代码实现

如何用代码实现编码块的划分呢?这里以H.265/HEVC的官方参考软件HM-16.18的实现为例进行讲解,HM编译安装方法参考。首先通过递归实现CTU到CU的四叉树划分,然后再CU里遍历每种PU划分方式选择最优PU划分模式。具体实现代码在TEncCu.cpp里的xCompressCU()函数里,为了节省篇幅只保留了相关部分代码。

#if AMP_ENC_SPEEDUP
Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const UInt uiDepth DEBUG_STRING_FN_DECLARE(sDebug_), PartSize eParentPartSize )
#else
Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const UInt uiDepth )
#endif
{......// 选择帧间模式, NxN, 2NxN, and Nx2Nif( rpcBestCU->getSlice()->getSliceType() != I_SLICE ){// 2Nx2N, NxN
​if(!( (rpcBestCU->getWidth(0)==8) && (rpcBestCU->getHeight(0)==8) ))  //!<块尺寸不能为8x8{if( uiDepth == sps.getLog2DiffMaxMinCodingBlockSize() && doNotBlockPu)   //!<只有当CU是最小块时才进行NxN划分{ //!<计算帧间NxN模式代价并比较xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_NxN DEBUG_STRING_PASS_INTO(sDebug)   );rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );}}
​if(doNotBlockPu){ //!<计算帧间Nx2N模式代价并比较xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_Nx2N DEBUG_STRING_PASS_INTO(sDebug)  );rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_Nx2N ){doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;}}if(doNotBlockPu){xCheckRDCostInter      ( rpcBestCU, rpcTempCU, SIZE_2NxN DEBUG_STRING_PASS_INTO(sDebug)  );rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxN){doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;}}//!<尝试非对称尺寸//! Try AMP (SIZE_2NxnU, SIZE_2NxnD, SIZE_nLx2N, SIZE_nRx2N)if(sps.getUseAMP() && uiDepth < sps.getLog2DiffMaxMinCodingBlockSize() ){
#if AMP_ENC_SPEEDUPBool bTestAMP_Hor = false, bTestAMP_Ver = false;
​
#if AMP_MRGBool bTestMergeAMP_Hor = false, bTestMergeAMP_Ver = false;
​deriveTestModeAMP (rpcBestCU, eParentPartSize, bTestAMP_Hor, bTestAMP_Ver, bTestMergeAMP_Hor, bTestMergeAMP_Ver);
#elsederiveTestModeAMP (rpcBestCU, eParentPartSize, bTestAMP_Hor, bTestAMP_Ver);
#endif
​//! Do horizontal AMPif ( bTestAMP_Hor ){if(doNotBlockPu){//2NxnU划分xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnU DEBUG_STRING_PASS_INTO(sDebug) );rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnU ){doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;}}if(doNotBlockPu){//2NxnD划分xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnD DEBUG_STRING_PASS_INTO(sDebug) );rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnD ){doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;}}}
#if AMP_MRGelse if ( bTestMergeAMP_Hor ){if(doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnU DEBUG_STRING_PASS_INTO(sDebug), true );rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnU ){doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;}}if(doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnD DEBUG_STRING_PASS_INTO(sDebug), true );rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnD ){doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;}}}
#endif
​//! Do horizontal AMPif ( bTestAMP_Ver ){if(doNotBlockPu){//nLx2N划分xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nLx2N DEBUG_STRING_PASS_INTO(sDebug) );rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_nLx2N ){doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;}}if(doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nRx2N DEBUG_STRING_PASS_INTO(sDebug) );rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );}}
#if AMP_MRGelse if ( bTestMergeAMP_Ver ){if(doNotBlockPu){//进行nLx2N划分xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nLx2N DEBUG_STRING_PASS_INTO(sDebug), true );rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_nLx2N ){doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;}}if(doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nRx2N DEBUG_STRING_PASS_INTO(sDebug), true );rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );}}..................
//帧内模式
xCheckRDCostIntra( rpcBestCU, rpcTempCU, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug) ); //!<计算帧内2Nx2N预测模式代价rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );if( uiDepth == sps.getLog2DiffMaxMinCodingBlockSize() ){if( rpcTempCU->getWidth(0) > ( 1 << sps.getQuadtreeTULog2MinSize() ) ){//只有最小尺寸8x8才进行NxN划分,因为按四叉树               //划分所以CU边长都是2的幂次xCheckRDCostIntra( rpcBestCU, rpcTempCU, SIZE_NxN DEBUG_STRING_PASS_INTO(sDebug)   );  //!<计算帧内NxN预测模式代价rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );}}}................................................//递归进行四叉树划分xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth );..............................................
}​

在TypeDef.h里定义了各种划分模式

//!<PU的8种划分方式,4种对称方式,4种非对称方式
enum PartSize
{SIZE_2Nx2N           = 0,           ///< symmetric motion partition,  2Nx2NSIZE_2NxN            = 1,           ///< symmetric motion partition,  2Nx NSIZE_Nx2N            = 2,           ///< symmetric motion partition,   Nx2NSIZE_NxN             = 3,           ///< symmetric motion partition,   Nx NSIZE_2NxnU           = 4,           ///< asymmetric motion partition, 2Nx( N/2) + 2Nx(3N/2)SIZE_2NxnD           = 5,           ///< asymmetric motion partition, 2Nx(3N/2) + 2Nx( N/2)SIZE_nLx2N           = 6,           ///< asymmetric motion partition, ( N/2)x2N + (3N/2)x2NSIZE_nRx2N           = 7,           ///< asymmetric motion partition, (3N/2)x2N + ( N/2)x2NNUMBER_OF_PART_SIZES = 8
};

感兴趣的扫码关注微信公众号Video Coding

视频编码中编码块划分相关推荐

  1. VVC系列(二)编码结构和块划分准则

    文章目录 VVC的编码结构 VVC 块划分准则 VVC针对边界处CU划分的处理 VVC针对CU冗余划分的限制 VVC从硬件效率的角度对CU Size的限制 相关语法元素 VVC的编码结构 同HEVC类 ...

  2. 视频编码中的块效应、振铃效应和呼吸效应分析

    1.块效应: (1)概念: 主要是由视频图像采用基于块的编码方式和量化造成相邻块之间存在明显差异的现象,在视频编码中人眼察觉到的小块边界处的不连续. (2)产生原因: 1.编码过程中对残差进行DCT变 ...

  3. 【Codecs系列】之视频编码中的块效应、振铃效应和呼吸效应分析

    Date: 2018.5.28 1.块效应: (1)概念: 主要是由视频图像采用基于块的编码方式和量化造成相邻块之间存在明显差异的现象,在视频编码中人眼察觉到的小块边界处的不连续. (2)产生原因: ...

  4. H.266/VVC的编码结构和块划分

    一.将一帧图像划分成CTUs VVC中一帧图像分成许多编码树单元(CTU).CTU的概念与HEVC的相同.对于一帧具有三通道的图像,CTU由一个N×N的亮度样本块和两个相应的色度样本块组成.图1显示了 ...

  5. VVC/VTM的编码结构和块划分

    本文参考了JVET-J1002:Algorithm description for Versatile Video Coding and Test Model 1 (VTM 1) VVC的编码结构 V ...

  6. H.266/VVC相关技术学习笔记4:HEVC和VVC中块划分的差别

    关于H.265/HEVC和H.266/VVC中的块划分的区别: 一.HEVC中首先需要将一个图像固定划分为多个CTU. ① CTU的尺寸固定划分为64×64,一个CTU由一个亮度CTB和两个色度CTB ...

  7. 01 VVC中编码块的划分结构

    前言: VVC中块的结构划分,在HEVC中四叉树(QT)递归划分的基础之上,又增加二叉树(BT)和三叉树两种划分方式,所以在VVC中大块进行划分之后会出现矩形块,这点与HEVC不同,HEVC中由于采用 ...

  8. VVC中块划分的快速编码

    新一代视频编码标准VVC中,灵活的分区是关键技术之一.与HEVC相比,仅分区就节省了8.5%的比特率.但是,增加的灵活性是以大量搜索空间扩展为代价的.本文概述了VVC中块划分的快速编码器选择策略,总共 ...

  9. 【待更新】感知视频编码中的感知检测技术(显著性物体检测向)

    之前对ROI编码感兴趣,做了显著性检测方面的文献综述.截至到2019年1月13号有13400字. 现在搬上来,一来交流,二来重温 感知视频编码PVC HVS 针对HVS所构建的数学模型分类 基于HVS ...

最新文章

  1. PHP函数stream_context_create()模拟POST/GET
  2. grafana安装升级部署
  3. php 输出答案,php 如何只输出最后生成的那个值??
  4. Tomcat7基于Redis的Session共享实战二
  5. 【软件工程】解决方案构想
  6. 运行批处理bat文件不出现黑框
  7. git reset和revert的区别
  8. 远程桌面服务器连接失败,Windows服务器远程桌面连接失败是什么原因
  9. js 微信聊天框的时间显示规则,以及输出的时间格式(已优化)
  10. Mendeley--免费的文献管理工具,给论文自动插入参考文献
  11. 彻底卸载微软拼音输入法
  12. LVGL 7.8模拟时钟
  13. [Economist] Print me a phone 给我印一部手机
  14. 【matplotlib复杂的频数分布直方图】多子图,共享横纵坐标名,横坐标位置居中及标签显示,显示每个bar的频数
  15. 思科路由器限速设置全解
  16. kafka之Consumer消费者基本概念
  17. 前端入门之特效、动画
  18. SaaS软件建立平台生态的挑战
  19. 名企过来人畅谈IT求职两注意
  20. 板翅式换热器设计校核计算作业

热门文章

  1. 银行存款利率C语言程序设计,存款利息的计算 有1000元,想存5年,可按以下5种办法存:...
  2. TensorFlow 高性能数据输入管道设计指南
  3. 白领最痛恨的四大发明
  4. Event 对象--target 事件属性
  5. 逆天了,俄罗斯黑客一口气黑掉60多所大学和政府机构
  6. 阿里LinkWAN SDK使用之mqtt数据流
  7. 三菱FX2N编程口通信协议
  8. 2017软院金山WPS补题 L
  9. 众安在线2018半年报:亏损6.668亿元,综合成本率高达124.0%
  10. Flutter练习:实现自定义的分页指示器