• VVC中图块划分结果在图像上显示(中间有一段没写完)


    参考

    改进《VVC/VTM中CU的划分结果打印》_pengyouyou的博客-CSDN博客

    VVC学习之二:VTM中CU划分结构QTMTT(3):打印QTMTT最终划分_Aidoneus_y的博客-CSDN博客

    VTM14

    思路: 如果只是想看图像划分结果,不在乎之后的解码时的影响。即可在重建值中将各个不同划分类型的CU染色

    记录下CU的划分类型,最后根据划分类型显示

    在划分开始的时候(递归开始),划分出子节点,此时将划分类型保存到CS之中;然后由CS告知其中的每个CU;最后,每个CU被编码后,将CU的划分信息回传给父节点(递归结束)。

    步骤:

     1.先在codingStructure和codingUnit这两个类中分别创建两个变量

    cs中为:

    uint8_t partype;//增加划分模式管理

    partype表示当前CS正在测试的划分模式

    cu中为:

    uint8_t finaltype; //增加划分模式信息

    finaltype表示当前CS的CU比较后最终采用的划分模式

    2.在xCheckModeSplit()函数的do while结构里,创建完tempSubCS和bestSubCS的语句下面,添加

     tempSubCS->partype=encTestMode.type; //保存当前subCu划分

     bestSubCS->partype = encTestMode.type;

    因为从xcompressCu()函数传输参数到xCheckModeSplit(),有一个变量叫currTestMode,是encTestMode类实例化的一个对象,由m_modeCtrl->currTestMode()赋值,值为当前块所测试的模式。而encTestMode类有type,opts,maxCostAllowed,qp这几个变量。所以这里保存的是当前即将测试的CU的父CU的划分模式(也可以理解为当前CU的被划分模式)

    3.在initSubStructure()函数中调用的addCU()函数里添加

    cu->finaltype = partype;//cu存入cs采用的划分类型

    initSubStructure()函数在xcompressCu()函数和xCheckModeSplit()函数中都默认isTuEnc为false,所以不会运行 addCU()函数,只有在estIntraPredLumaQT()中,默认isTuEnc为true(这里之后写了预测代码分析后再补上

    参照底下我的博客,addCU()函数目的是初始化 pcu的一些数据,然后据此推测出缩放后的CU,父CU的size,和idxptr,将这些数据存入AreaBuf。这里也将当前CS的partype存入了当前cu中.

     这里是128X128的CTU四叉树的第一个64X64在XcompressCu()中预测模式测试完后继续循环,在进入xCheckModeSplit()函数前,Cu中已经有了finaltype,值为7,代表QT

    initSubStructure()和addCU()函数(addCU还没写)_青椒鸡汤的博客-CSDN博客

    xCheckModeSplit()中的useSubStructure()函数,releaseIntermediateData()函数解析,add()函数解析(getBuf()函数没看)_青椒鸡汤的博客-CSDN博客

    4.在useSubStructure()函数中添加 :

    cu.finaltype = pcu->finaltype;

    解析:useSubStructure()这一段将当前子CU的信息赋给了subRecoBuf,然后再将将前面PelUnitBuf的subRecoBuf的信息存进picture所调用的PelUnitBuf

    1. UnitArea clippedArea = clipArea( subArea, *picture );
    2. setDecomp( clippedArea );
    3. CPelUnitBuf subPredBuf = cpyPred ? subStruct.getPredBuf( clippedArea ) : CPelUnitBuf();
    4. CPelUnitBuf subResiBuf = cpyResi ? subStruct.getResiBuf( clippedArea ) : CPelUnitBuf();
    5. CPelUnitBuf subRecoBuf = cpyReco ? subStruct.getRecoBuf( clippedArea ) : CPelUnitBuf();
    6. if( parent )
    7. {
    8. // copy data to picture
    9. if (cpyPred)
    10. {
    11. getPredBuf(clippedArea).copyFrom(subPredBuf);
    12. }
    13. if (cpyResi)
    14. {
    15. getResiBuf(clippedArea).copyFrom(subResiBuf);
    16. }
    17. if (cpyReco)
    18. {
    19. getRecoBuf(clippedArea).copyFrom(subRecoBuf);
    20. }
    21. if (cpyOrgResi)
    22. {
    23. getOrgResiBuf(clippedArea).copyFrom(subStruct.getOrgResiBuf(clippedArea));
    24. }
    25. }
    26. if (cpyPred)
    27. {
    28. picture->getPredBuf(clippedArea).copyFrom(subPredBuf);
    29. }
    30. if (cpyResi)
    31. {
    32. picture->getResiBuf(clippedArea).copyFrom(subResiBuf);
    33. }
    34. if (cpyReco)
    35. {
    36. picture->getRecoBuf(clippedArea).copyFrom(subRecoBuf);
    37. }

     将当前CU中的子CU里的finaltype信息更新

    1. // copy the CUs over
    2. if( subStruct.m_isTuEnc )
    3. {
    4. // don't copy if the substruct was created for encoding of the TUs
    5. }
    6. else
    7. {
    8. for( const auto &pcu : subStruct.cus )
    9. {
    10. // add an analogue CU into own CU store
    11. const UnitArea &cuPatch = *pcu;//当前子CU area
    12. CodingUnit &cu = addCU( cuPatch, pcu->chType );//在CUs中新建一个CU,新建一层(size),并写入父CU的一些基本信息
    13. // copy the CU info from subPatch
    14. cu = *pcu;//将新size的信息更新为子CU的
    15. cu.finaltype = pcu->finaltype;//cu是this指针(父cs),将cu中的finaltype更新为子CU的
    16. }
    17. }

     subStruct.cus一共有五层,都是已划分好CU的信息,加起来就是当前32X32的块

     pcu代表已划分的子CU,存有子CU的一切信息。addCU()函数根据当前CU的位置信息和亮色度信息,新建一层CU(size+1),然后将父CU的信息复制到这个新CU里(将父CU的finaltype值给了这个新的CU。比如现在的32X32块,所属划分模式就是7,因为是64X64四叉树划分形成的。这里这个新CU的finaltype也变成了7)

    接下来的

     cu = *pcu;

    将这个新CU层的信息用子CU(即当前pcu)的信息所覆盖。但这里没有把当前子CU的finaltype覆盖,所以还要加一句

     cu.finaltype = pcu->finaltype;

    Pcu中的 finaltype写到了父CU中(finaltype从7变成了{x = 0, y = 16, width = 32, height = 16}这个子CU的finaltype值 8)

     等于当前父CU(32X32)中的每一个划分好的子CU的信息都写入了subStruct.cus中,并存了下来。之后可以随时调用

     5.compressGOP中重建完成(pcPic->reconstructed = true;)之后,添加:

    1. #if SPLIT_SHOW
    2. PelUnitBuf recpic = pcPic->getRecoBuf();//重建结束后得到重建缓存
    3. AreaBuf<Pel>& recYpoint = recpic.Y();//得到Y分量
    4. AreaBuf<Pel>& recCbpoint = recpic.Cb();//得到Cb
    5. AreaBuf<Pel>& recCrpoint = recpic.Cr();//得到Cr
    6. uint64_t culength = pcPic->cs->cus.size();//总的cu数量
    7. for (uint64_t n = 0; n<culength; n++) {
    8. CodingUnit* finalCU = pcPic->cs->cus.at(n);//得到每一个CU
    9. Area curArea(finalCU->lumaPos(), finalCU->lumaSize());//CU大小和位置
    10. if (finalCU->chType == CHANNEL_TYPE_LUMA) {//cu是否亮度cu
    11. splitshow(recYpoint, recCbpoint, recCrpoint, curArea, finalCU->finaltype);
    12. }
    13. }
    14. #endif // SPLIT_SHOW

    得到重建缓存,存在PelUnitBuf实例化的对象里

     读取cus中的cu数量(这里有4700个)

     

    1. #if SPLIT_SHOW
    2. void splitshow(AreaBuf<Pel>& recYpoint, AreaBuf<Pel>& recCbpoint, AreaBuf<Pel>& recCrpoint, Area curArea,int type) {
    3. int x = curArea.x ;//偏置1个像素
    4. int y = curArea.y ;//
    5. int h = curArea.height;//
    6. int w = curArea.width;//
    7. int16_t Y_value=0,Cb_value=0,Cr_value=0;//
    8. switch (type) {
    9. case 10:Y_value = 327; Cb_value = 361; Cr_value = 960; break;//红色
    10. case 8:Y_value = 640; Cb_value = 215; Cr_value = 136; break;//绿色
    11. case 7:Y_value=164; Cb_value = 960; Cr_value = 440; break;//蓝色
    12. case 11:Y_value=426; Cb_value = 810; Cr_value = 888; break;//紫色
    13. case 9:Y_value = 901; Cb_value = 64; Cr_value = 584; break;//黄色
    14. case 12:Y_value = 739; Cb_value = 663; Cr_value = 64; break;//青色
    15. case 13:Y_value = 192; Cb_value = 656; Cr_value = 607; break;//靛青
    16. default:break;
    17. }
    18. //y,cb,cr纯红(327,361,960)纯绿(640,215,136)纯蓝(164,960,440)
    19. //淡紫色(426,810,888)黄色(901,64,584)青色(739,663,64)
    20. //靛青(192,656,607)
    21. for (int j = 0; j < h; j++) {
    22. //left
    23. //recYpoint.at(x, y + j) = Y_value; ///左边1
    24. //recYpoint.at(x + 1, y + j) = Y_value;//左边2
    25. // recCbpoint.at(x / 2, (y + j) / 2) = Cb_value; //cb分量
    26. //recCrpoint.at(x / 2, (y + j) / 2) = Cr_value;//cr分量
    27. //right
    28. recYpoint.at(x+w-2, y + j) = Y_value; ///1
    29. recYpoint.at(x+w-1, y + j) = Y_value;//2
    30. recCbpoint.at((x+w-2) / 2, (y + j) / 2) = Cb_value; //cb分量
    31. recCrpoint.at((x+w-2) / 2, (y + j) / 2) = Cr_value;//cr分量
    32. }
    33. for (int i = 0; i < w; i++) {
    34. //top
    35. //recYpoint.at(x + i, y) = Y_value; //上1
    36. //recYpoint.at(x + i, y + 1) = Y_value;//上2
    37. //recCbpoint.at((x + i) / 2, y / 2) = Cb_value; //cb分量
    38. //recCrpoint.at((x + i) / 2, y / 2) = Cr_value;//cr分量
    39. //down
    40. recYpoint.at(x + i, y+h-2) = Y_value; //1
    41. recYpoint.at(x + i, y+h-1) = Y_value;//2
    42. recCbpoint.at((x + i) / 2, (y+h-2) / 2) = Cb_value; //cb分量
    43. recCrpoint.at((x + i) / 2, (y+h-2) / 2) = Cr_value;//cr分量
    44. }
    45. }
    46. #endif

    得到每个CU的area信息,再根据每个CU最终的finaltype类型,选择CU周围像素颜色,赋给几个分量。

    at()是AreaBuf结构体自带的函数,输入的参数可定位CU中的像素。这里用for循环将CU的边界像素改颜色

    最后结果

     

  • 相关阅读:
    【Spring系列】- Bean生命周期底层原理
    2021 年全国职业院校技能大赛高职组“信息安全管理与评估”赛项 A 卷 第一阶段任务书
    【HarmonyOS】eTS开发是否支持在data/ethernet/创建文件
    基于SpringBoot+vue的汽车销售管理系统
    ChatGPT生产力|实用指令(prompt)
    jar包注册成windows服务
    Exploring Common Algorithms in Machine Learning
    java毕业设计健身房课程预约平台(附源码、数据库)
    30天啃透这份Framework 源码手册直接面进大厂
    Java进阶(8)——抽象类与接口
  • 原文地址:https://blog.csdn.net/dfhg54/article/details/125439581