介绍完QTMTT在VTM中的实现,相信很多人包括我也对QTMTT的最终划分结果很感兴趣,于是我尝试将最终的划分结果进行可视化显示。
在xCompressCU
中,将对CTU进行递归划分,用RDcost选择出最优的划分方式,因此在xCompressCU
中很难提取到QTMTT的最优划分方式。因此,要得到最终划分结果,必须在xCompressCU
之后。VTM提供了遍历每个CodingStructure
中所有CU的函数traverseCUs()
,因此只需要在xCompressCU
之后,遍历CTU中每个CU就可以得到其位置和尺寸信息。
为了可视化显示CU,需要修改CU边界像素值,但是重建像素将会用作参考,直接修改重建值将会影响帧间预测的运动估计和运动补偿,因此不能直接修改CU的重建值。我用了最笨的方法,copy重建帧,在copy上进行可视化,并保存下来。
下面给出实现过程
// 遍历每帧图像中所有CTU,对每个CTU遍历所有CU
for (int y = 0; y < pcv.heightInCtus; y++)
{
for (int x = 0; x < pcv.widthInCtus; x++)
{
const UnitArea ctuArea(pcv.chrFormat, Area(x << pcv.maxCUWidthLog2, y << pcv.maxCUHeightLog2, pcv.maxCUWidth, pcv.maxCUWidth));
// CU-based painting
if (CS::isDualITree(cs))
{
for (auto &currCU : cs.traverseCUs(CS::getArea(cs, ctuArea, CH_L), CH_L))
{
xDrawCUIntraColor(currCU, Height, Width, pbufY, pbufU, pbufV);
}
}
else
{
for (auto &currCU : cs.traverseCUs(CS::getArea(cs, ctuArea, CH_L), CH_L))
{
xDrawCUColor(currCU, Height, Width, pbufY, pbufU, pbufV);
}
}
}
}
// 这里根据每个CU的编码模式,选择了不同的显示颜色
void xDrawCUIntraColor(CodingUnit& cu, int orgHeight, int orgWidth, unsigned char* tempY, unsigned char* tempU, unsigned char* tempV)
{
const CompArea& lumaArea = cu.block(COMPONENT_Y);
int cuX = lumaArea.x;
int cuY = lumaArea.y;
int cuH = lumaArea.height;
int cuW = lumaArea.width;
int chromaX = cuX >> 1;
int chromaY = cuY >> 1;
int chromaH = cuH >> 1;
int chromaW = cuW >> 1;
unsigned char y = 0, u = 0, v = 0;
if (cu.firstPU->intraDir[CHANNEL_TYPE_LUMA] < 2)
{
rgb2yuv(0, 0, 255, y, u, v); // blue
}
else
{
rgb2yuv(255, 0, 0, y, u, v); // red
}
int tempLumaIdx;
for (int i = 0; i < cuH; i++)
{
for (int j = 0; j < cuW; j++)
{
tempLumaIdx = (i + cuY) * orgWidth + cuX + j;
if (i == cuH - 1 || j == cuW - 1) //i == 0 || i == cuH - 1 || j == 0 || j == cuW - 1
{
tempY[tempLumaIdx] = y;
}
}
}
int tempChromaIdx;
for (int i = 0; i < chromaH; i++)
{
for (int j = 0; j < chromaW; j++)
{
tempChromaIdx = (i + chromaY) * orgWidth / 2 + (chromaX + j);
if (i == chromaH - 1|| j == chromaW - 1) //i == 0 || i == chromaH - 1 || j == 0 || j == chromaW - 1
{
tempU[tempChromaIdx] = u;
tempV[tempChromaIdx] = v;
}
}
}
}
最终的效果如下:
帧内划分结果
帧间划分结果