H.264中整数DCT变换,量化,反量化,反DCT究竟是如何实现的?(无代码,无真相)

视频编解码 — DCT变换量化 变换之后将4个小块的DC系数拿出来,组成2x2的DC块,再对这个2x2的DC块进行hadamard变换。H264为了减少这种浮点运算带来的误差,将DCT变换整数变化,DCT变换中的浮点运算和量化过程合并,这样就只有一次浮点运算过程。将图像块变换到频域后,AC系数比较多,一般幅值比较小,通过去除一些AC系数,达到压缩的目的。对于图像来说,空域是平时看到的图像,频率是图像做完DCT变换之后的数据。DCT变换是对残差块做的,通常情况下是在4X4的子块上进行变换的。,首先被划分成16个4x4的小块做整数变化。 阅读详情

        H.264中采用的是整数DCT变换,在实现的时候,该变换和量化又杂糅在一起,那么这些错综复杂的关系究竟是怎样纠缠的呢?在参考H.264乐园论坛会员cs1860wd的帖子和H.264 and MPEG-4 VIDEO COMPRESSION(第一版)这本书后,基于帖子和书上的讲解,给出相应的实现代码,并验证代码的正确性.

 

        还是以foreman视频第一帧第一个宏块第一个4*4块为例. 下面给出像素值:

====================== Y Data ======================
+----------------+----------------+----------------+----------------+
| 43,216,254,249,|251,254,254,253,|251,252,254,254,|254,254,254,253,|
| 49,198,193,211,|228,205,213,185,|211,207,186,248,|198,203,208,183,|
| 48,194,177,171,|197,173,185,136,|191,195,138,179,|142,176,177,135,|
| 46,214,225,169,|177,189,198,160,|203,208,177,165,|173,196,191,156,|
+----------------+----------------+----------------+----------------+
| 41,185,208,180,|203,228,226,200,|214,226,225,227,|228,225,224,210,|
| 31,130,173,178,|215,230,221,212,|220,229,227,228,|229,227,226,226,|
| 29,119,194,216,|211,213,219,222,|225,223,220,219,|218,218,218,218,|
| 25,126,219,224,|217,224,227,227,|227,226,225,224,|220,220,221,222,|
+----------------+----------------+----------------+----------------+
| 26,131,215,223,|226,225,225,225,|225,226,223,219,|221,221,219,220,|
| 30,136,216,226,|223,224,225,225,|224,221,217,221,|222,219,220,226,|
| 30,136,216,227,|224,224,225,223,|221,218,221,216,|211,224,224,211,|
| 29,135,217,225,|222,221,222,222,|221,209,181,155,|186,210,186,164,|
+----------------+----------------+----------------+----------------+
| 29,134,216,224,|226,230,230,227,|206,177,146,113,|149,162,147,150,|
| 29,135,219,231,|225,201,190,185,|163,144,153,140,|127,143,165,184,|
| 30,139,210,192,|165,142,134,133,|143,141,129,138,|150,178,201,207,|
| 30,125,166,145,|144,154,132,111,|118,161,175,180,|204,214,213,209,|
+----------------+----------------+----------------+----------------+

 

           该块的预测值为128(16个位置都是128),之前分析过,在JM8.6中,这一块在编码端和解码端的QDCT均为:

         9   -12   -11   -5

         3    -3      1     0 

         3    -1     -2     1

         0     0      0     0

 

         且用H.264visa从码流中得到的DCT系数为:(注意解码端的DCT与编码端的DCT必然不同)

====================== Y Data ======================
+------------------------+------------------------+------------------------+------------------------+
| 2304,-3840,-2816,-1600,|  768,  640, -256,  640,| 1280,  320,  256, -640,|  768, -320, -768,    0,|
960,-1200,  320, 0,|    0,    0,  320,    0,| -640, -800,    0,    0,|  960, -800,  320,    0,|
768, -320, -512,  320,|  512, -640,    0, -320,| -768,  320, -512,  320,|  768,    0,  256,    0,|
|    0,    0,    0,    0,|    0,    0,    0,    0,|    0,  400,    0,    0,| -320,    0,    0,    0,|
+------------------------+------------------------+------------------------+------------------------+
|-1024,-5120,-1792, -640,| 2560, -640, -256,    0,|  512,    0,    0,    0,|    0,    0,    0,    0,|
|    0, 1200, -640, -400,| -320,  400,    0,    0,|  640,    0,    0,    0,|  320,    0,    0,    0,|
|  512,    0, -256,    0,|    0,    0,    0,    0,|    0,    0,    0,    0,|    0,    0,    0,    0,|
|  320,    0,    0,    0,| -320,    0,    0,    0,|    0,    0,    0,    0,|    0,    0,    0,    0,|
+------------------------+------------------------+------------------------+------------------------+
|    0,  320,    0,    0,|    0,    0,    0,    0,| -768,  640,    0,    0,|  512,    0, -256,    0,|
|    0,    0,    0,    0,|    0,    0,    0,    0,|  640, -800,    0,    0,| -640, -400,  320,    0,|
|    0,    0,    0,    0,|    0,    0,    0,    0,| -256,  320,    0,    0,|    0,  320,    0,    0,|
|    0,    0,    0,    0,|    0,    0,    0,    0,|  320, -400,    0,    0,| -320,    0,    0,    0,|
+------------------------+------------------------+------------------------+------------------------+
| -512,  640, -256,    0,|    0,    0,    0,    0,| 1024, -320, -256,    0,| 1024, -320,    0,    0,|
|  960,-1200,  320,    0,|  960, -800,  320,    0,|-1280,  800,    0,  400,| -640,  400,    0,    0,|
| -512,  320,    0,    0,|    0,    0, -256,    0,|    0,    0, -256,    0,|  512,  640,    0,    0,|
|    0,    0,    0,    0,| -320,    0,    0,    0,| -640,  800,    0,    0,|    0,    0,    0,    0,|
+------------------------+------------------------+------------------------+------------------------+

 

           下面根据变换,量化,反量化和反变换公式给出如下程序,看看是否与上述数据一致.(需要特别指出的是:JM8.6中并不是这么实现的,但本质是相同的,最后结果也一样.)

 

#include <iostream>
#include <cmath>
#define BLOCK_SIZE 4
using namespace std;

int QP = 28; // 量化参数

//原始的YUV矩阵
int orgYUV[BLOCK_SIZE][BLOCK_SIZE] =
{
	43, 216, 254, 249,
    49, 198, 193, 211,
    48, 194, 177, 171,
    46, 214, 225, 169
};

//预测值矩阵
int predYUV[BLOCK_SIZE][BLOCK_SIZE] =
{
	128, 128, 128, 128,
	128, 128, 128, 128,
	128, 128, 128, 128,
	128, 128, 128, 128
};

int D[BLOCK_SIZE][BLOCK_SIZE];  //中间矩阵
int Di[BLOCK_SIZE][BLOCK_SIZE]; //中间矩阵

int W[BLOCK_SIZE][BLOCK_SIZE];  //核矩阵
int Z[BLOCK_SIZE][BLOCK_SIZE];  //QDCT矩阵
int Wi[BLOCK_SIZE][BLOCK_SIZE]; //Wi矩阵

int Xi[BLOCK_SIZE][BLOCK_SIZE]; //解码的残差矩阵

//Cf矩阵
int Cf[BLOCK_SIZE][BLOCK_SIZE]=
{
    1, 1,  1, 1,
    2, 1, -1, -2,
    1,-1, -1, 1,
    1,-2,  2, -1
};

//Ci矩阵      
int Ci[BLOCK_SIZE][BLOCK_SIZE]=
{
    2,  2,  2,  1,
    2,  1, -2, -2,
    2, -1, -2,  2,
    2, -2,  2, -1
};

//MF矩阵
int MF[6][3]=
{
    13107, 5243, 8066,
    11916, 4660, 7490,
    10082, 4194, 6554,
    9362,  3647, 5825,
    8192,  3355, 5243,
    7282,  2893, 4559
};

//Qstep矩阵
int V[6][3]=
{
    10, 16, 13,
    11, 18, 14,
    13, 20, 16,
    14, 23, 18,
    16, 25, 20,
    18, 29, 23
};

//矩阵转置
void matrixTransform(int a[][BLOCK_SIZE])
{
	int i, j, tmp;
	for(i = 0; i < BLOCK_SIZE; i++)
	{
		for(j = 0; j < BLOCK_SIZE; j++)
		{
			if(i < j)
			{
				tmp = a[i][j];
				a[i][j] = a[j][i];
				a[j][i] = tmp;
			}
		}
	}
}

//矩阵求差
void  matrixSubtract(int a[][BLOCK_SIZE],int b[][BLOCK_SIZE])
{
    int i, j;
    for(i = 0;i < BLOCK_SIZE; i++)
	{
        for(j = 0; j < BLOCK_SIZE; j++)
        {
            a[i][j] -= b[i][j];
		}
	}
}

//矩阵求积
void  matrixMultiply(int a[][BLOCK_SIZE],int b[][BLOCK_SIZE],int c[][BLOCK_SIZE])
{
	int i, j, k;
	for(i = 0; i < BLOCK_SIZE; i++)
	{
		for(j = 0; j < BLOCK_SIZE; j++)
		{
			c[i][j] = 0;
			for(k = 0; k < BLOCK_SIZE; k++)
			{
				c[i][j] += a[i][k] * b[k][j];  
			}
		}
	}      
}

//矩阵显示
void matrixShow(int a[][BLOCK_SIZE])
{
    int i, j;
    cout << "*****************************" << endl;
    for(i = 0; i < BLOCK_SIZE; i++)
	{
        for(j = 0; j < BLOCK_SIZE; j++)
        {
            cout << a[i][j] << "\t";
        }
		cout << endl;
	}

    cout << "*****************************" << endl << endl;
}

//求QDCT
void quantizeDCT(int W[][BLOCK_SIZE])
{
	// QP决定了qbits和f, QP和位置(i, j)共同决定了mf
	int qbits = 15 + floor(QP / 6);
	int f = (int)( pow(2.0, qbits) / 3 );
	int mf;

	int i, j, k;
	for(i = 0; i < BLOCK_SIZE; i++)
	{
		for(j = 0; j < BLOCK_SIZE; j++)
		{
			//以下均依公式实现
			
			//(0, 0), (2, 0), (0, 2), (2, 2)  mf为 MF[QP % 6][0]
			//(1, 1), (3, 1), (1, 3), (3, 3)  mf为 MF[QP % 6][1];
			// other positions                mf为 MF[QP % 6][2];

			if((0 == i || 2 == i) && (0 == j || 2 == j))
				k = 0;
			else if((1 == i || 3 == i) && (1 == j || 3 == j))
				k = 1;
			else
				k = 2;

			mf = MF[QP % 6][k];
              
			Z[i][j] = ( abs(W[i][j]) * mf + f ) >> qbits;

			if(W[i][j] < 0)
				Z[i][j] = -Z[i][j];
		} 
		
	}
}

//求Wi(即解码端的DCT) (Z为QDCT)
void reverseQuantize(int Z[][BLOCK_SIZE])
{     
	int t = floor(QP / 6);                
	int f = (int)pow(2, t); 
	int v;
	
	int i, j, k;
	for(i = 0; i < BLOCK_SIZE; i++)
	{
		for(j = 0; j < BLOCK_SIZE; j++)
		{
			//以下均依公式实现
			  
			if((0 == i || 2 == i) && (0 == j || 2 == j))
				k = 0;
			else if((1 == i || 3 == i) && (1 == j || 3 == j))
				k = 1;
			else
				k = 2;

			v = V[QP % 6 ][k];
			Wi[i][j] = Z[i][j] * v * f;
		}
	}
}

int main()
{
	matrixSubtract(orgYUV, predYUV);
	cout << "Residual matrix is" << endl;
    matrixShow(orgYUV);

	//此时orgYUV变为残差矩阵
    matrixMultiply(Cf, orgYUV, D);
    matrixTransform(Cf);
    matrixMultiply(D, Cf, W);        

	//得到的W即为核
	cout << "Matrix Core(W) is" << endl;
    matrixShow(W);

	//利用核W来得到QDCT(Z)
    quantizeDCT(W);
	cout << "Matrix QDCT(Z) is" << endl;
    matrixShow(Z);
  
    //利用QDCT(Z)得到解码端的DCT(Wi).(Wi与编码端DCT必然不同)
    reverseQuantize(Z);
	cout << "Matrix W'(解码端DCT) is" << endl;
    matrixShow(Wi);

    //利用Wi得到解码的残差矩阵Xi
    matrixMultiply(Ci, Wi, Di); 
	matrixTransform(Ci);        
    matrixMultiply(Di, Ci, Xi);
	int i,j;
    for(i = 0;i < 4; i++)
	{
        for(j = 0; j < 4; j++)
		{
			Xi[i][j] = int( Xi[i][j] / 256.0 + 0.5 );
		}
	}
	cout << "Matrix Xi(解码端残差) is" << endl;
    matrixShow(Xi);

	return 0;
}



           结果为:(可以看出,结果中的QDCT和解码端的DCT都与之前的数据吻合,从而证明上面程序的实现是正确的.)

 

Residual matrix is
*****************************
-85     88      126     121
-79     70      65      83
-80     66      49      43
-82     86      97      41
*****************************

Matrix Core(W) is
*****************************
609     -1255   -685    -560
277     -476    113     -73
175     -159    -119    98
-14     -13     4       1
*****************************

Matrix QDCT(Z) is
*****************************
9       -12     -11     -5
3       -3      1       0
3       -1      -2      1
0       0       0       0

*****************************

Matrix W'(解码端DCT) is
*****************************
2304    -3840   -2816   -1600
960     -1200   320     0
768     -320    -512    320
0       0       0       0

*****************************

Matrix Xi(解码端残差) is
*****************************
-77     88      132     110
-80     63      67      77
-82     62      48      39
-79     87      93      32
*****************************

           下面,简要看看整数DCT变换的原理.(关于整数DCT变换公式的推倒,请参考余兆明的《图像编码标准H.264技术》). 

          

           DCT变换为:      DCT = A * X * At

           量化为:           QDCT =  floor(DCT/Qstep)

           反量化为:        DCT‘  = QDCT * Qstep

           反DCT为:              X’ = At * DCT‘ * A

 

           但在H.264中采用的是整数DCT, 在JM8.6中的实现方式也很有讲究:( .* 表示矩阵对应元素相乘)

          整数DCT变化为:       DCT = (Cf * X *Cft) .*E

          量化为:                    QDCT = floor(DCT/Qstep)

          反量化为:                  DCT‘ = QDCT * Qstep

          整数反DCT变换为:        X’ = Ci * (DCT‘ .* Ei) *Ci

 

          在实现的时候,经常不直接得到DCT系数,而是将变换和量化结合在一起实现. 整数DCT变换有很多好处:没有除法,没有浮点数,所以高效且准确,而且减少了矩阵运算.    

        

           最后感慨一下:如果上面的程序用matlab来仿真,就简单多了,matlab太适合处理矩阵问题了.

 

 

 

Matlab DCT详解 DCT变换DCT又称离散余弦变换,是一种块变换方式,只使用余弦函数来表达信号,与傅里叶变换紧密相关。常用于图像数据的压缩,通过将图像分成大小相等(一般为8*8)的块,利用DCT对其进行变换,得到更加简洁的数据。因为图像像素间存在较大的空间相关性,DCT可以大大减小这些相关性,使图像能量集中在左上角区域,从而利于数据压缩。变换后得到的数据称为DCT系数。这一过程是无损的。二维DCT变换这里来看看二维D 阅读详情

相关推荐

H.264 VS H.265 变换编码及量化过程分析(2)

量化是视频编码中产生失真的根本原因,它同时影响着编码质量和比特率。 Quantize原理 Quantization parameter and step Quantization在编码中的应用 Quantization在编码中的实现 Quantization在编码中,不同系数采用的方案 Quantization在编码中,优化方案 Quantization在编码中,涉及的码流参数 Quantize原理 量化是指将信号的连续取值,映射为有限多个离散幅值的过程,实现信号多对一的映射。量.

biaobiao009的专栏 1974

H.264/AVC视频编解码技术详解

H.264/AVC是目前业界应用为广泛的视频压缩编码标准,包含了先进而且较为成熟的视频编码技术。本课程将从原理、标准和实现等多个角度,详细讲述了H.264/AVC视频编码标准的整体架构与技术细节,不但讲解了H.264/AVC标准协议文档中的内容,还通过实际的H.264码流分析/解码程序的开发来帮助观众更深入地理解H.264编码标准的原理。

H 264整数DCT变换量化反量化DCT究竟是如何实现无代码,无真相

H 264整数DCT变换量化反量化DCT究竟是如何实现无代码,无真相

sjhfkhsf的博客 414

DCT变换编码matlab,图像压缩编解码实验(DCT编码+量化+熵编码(哈夫曼编码))【MATLAB】...

Input: an intra-frame or a residue picture after motion compensation.Task: Code the input picture into a bitstream and decode the picture from the generated bitstream.Specifications: Implement a tran...

weixin_39846364的博客 1626

图像的DCT变换

参考1:JPEG压缩原理与DCT离散余弦变换参考2:H.264整数DCT变换量化反量化DCT究竟是如何实现的?(无代码,无真相)

qq_32245927的博客 2038

流媒体协议介绍

一、协议篇 1. rtsp协议详解(http://www.mikewootc.com/wiki/net/protocol/rtsp.html) 2. rtp与rtcp协议详解(http://www.mikewootc.com/wiki/net/protocol/rtp.html) 3. rtsp协议详解,这个是对rtsp协议英文版的中文翻译,有98页,详细介绍了rtsp协议(http://p...

行者-崛起之路 507

流媒体协议学习

一、协议篇 1. rtsp协议详解(http://www.mikewootc.com/wiki/net/protocol/rtsp.html) 2. rtp与rtcp协议详解(http://www.mikewootc.com/wiki/net/protocol/rtp.html) 3. rtsp协议详解,这个是对rtsp协议英文版的中文翻译,有98页,详细介绍了rtsp协议(http:/

fei的专栏 1408

智能会议系统(9)---流媒体协议学习

流媒体协议学习 一、协议篇 1. rtsp协议详解(http://www.mikewootc.com/wiki/net/protocol/rtsp.html) 2. rtp与rtcp协议详解(http://www.mikewootc.com/wiki/net/protocol/rtp.html) 3. rtsp协议详解,这个是对rtsp协议英文版的中文翻译,有98页,详细介绍了rtsp协...

zhangbijun1230的专栏 365

纪录流媒体学习的过程

1. rtsp协议详解(http://www.mikewootc.com/wiki/net/protocol/rtsp.html) 2. rtp与rtcp协议详解(http://www.mikewootc.com/wiki/net/protocol/rtp.html) 3. rtsp协议详解,这个是对rtsp协议英文版的中文翻译,有98页,详细介绍了rtsp协议(http://pan.baid

depthlove1的专栏 639

【编解码:H.264原理浅析】

H264原理

weixin_47852035的博客 982

H264量化

前言 残差矩阵经过整数DCT变换后即需要对变换后的DCT系数进行量化操作。且注意:前期DCT变换Mn⋅X⋅MnTM_n·X·M_n^TMn​⋅X⋅MnT​以及优化成了整数DCT变换Cf⋅X⋅CfT⨂SfCf·X·Cf^T\bigotimes SfCf⋅X⋅CfT⨂Sf,其中的⨂Sf\bigotimes Sf⨂Sf动作放到了量化的过程中实现。 规定 QP是量化参数,是量化步长Qstep的编号,...

workspace 2702

JPEG图片存储格式及原理

JPEG是联合图象专家组(Joint Picture Expert Group)的英文缩写,是国际标准化组织(ISO)和CCITT联合制定的静态图象的压缩编码标准。和相同图象质量的其它常用文件格式(如GIF,TIFF,PCX)相比,JPEG是目前静态图象中压缩比最高的。我们给出具体的数据来对比一下。例图采用Windows95目录下的Clouds.bmp,原图大小为640*480,256色。用工具S

huangxy10的专栏 3万+

H264中的DCT变换量化

下图为intra16x16 block的正向变换变换过程,和非intra16x16 block相比,intra16x16 会进一步把这16个小块的DC分量再做哈达玛变换,然后再量化,所以对于每个小块中的16个系数,DC系数为先做DCT变换再做哈达玛变换的结果,15个AC系数为DCT变换的结果。变换和正向变换的顺序相变换为先对16个小块的DC分量做哈达玛变换,然后再把每个小块的DC分量和它的AC分量放在一起,组成16个系数,然后对它再做反量化,接着IDCT,恢复block中的像素值。

音视频图像相关 1312

H265和H264编解码中DCT变换过程中scaling 和 strong_intra_smooth

strong_intra_smooth:是H265的intra预测过程中,对相邻pix进行的双线性滤波,属于协议内容 scaling是DCT变换过程中的,用于归一化,为了保证残差块经过变换变换之后基准相同,HEVC在变换模块中还增加了额外的缩放参考HEVC中变换(Transform)过程中的scaling操作的理解 ...

cy413026的博客 1517

DCT变换

DCT变换 1.DCT变换公式及其性质 傅里叶变换表明,任何信号都能表示为多个不同振幅和频率的正弦或者余弦信号的叠加。如果采用的是余弦函数,则信号分解过程称为余弦变换;若输入信号是离散的,则称之为离散余弦变换(Discrete Cosine Transform,DCT)。数学上共存在8种类型的DCT。公式如下: ​ 其中,在图像视频领域中,最常用的是DCT-Ⅱ,平常说的DCT一般指的是...

BigDream123的博客 3万+

H264-整数DCT变换和蝶形变换代码实现

背景 为压缩数据,H264标准需要使用整数DCT变换把图像信号转换到频域。变换过程实际上就是矩阵乘法,使用蝶形变换可以减少运算量,提升算法性能。 原理 整数DCT变换公式推导过程不再赘述,可以参考《深入理解视频编解码技术 --基于H264标准及参考模型》。 以4x4为例,变换公式如下: Y = Cf * X * Cf.T 其中 Cf = [1, 1, 1, 1, 2, 1, -1, -2, 1,-1, -1, 1, 1,-2, 2, -1] 展开如下:

qq_42139383的博客 3621
上一篇: 如何在JM8.6编码端提取QDCT?
下一篇: warning和error的区别
涛歌依旧
涛歌依旧 优质创作者: 后端开发技术领域 优质创作者: 后端开发技术领域 领域专家: C/C++技术领域 领域专家: C/C++技术领域
博客等级 码龄14年 28万+粉丝 2592原创
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值