H264編碼的整數DCT的測試代碼

整數DCT的作用是變換編碼,提取信號特徵。H264的整數DCT分兩步:

1、DCT整數部分變換;

2、DCT實數部分變換。

實數部分和量化在一起進行,可以統一損失精度,也可以降低運算複雜度。

整數部分用蝶形變換,以最常見的4x4宏塊爲例,代碼如下:

#include <iostream>
using namespace std;
#define BLOCK_SIZE 4
int block[BLOCK_SIZE][BLOCK_SIZE], tblock[BLOCK_SIZE][BLOCK_SIZE];

//蝶形算法
void forward4x4(int pos_y, int pos_x)
{
	int i, ii;
	int tmp[16] = { 0 };
	int *pTmp = tmp, *pblock;
	int p0, p1, p2, p3;
	int t0, t1, t2, t3;

	// Horizontal
	for (i = pos_y; i < pos_y + BLOCK_SIZE; i++)
	{
		pblock = &block[i][pos_x];
		p0 = *(pblock++);
		p1 = *(pblock++);
		p2 = *(pblock++);
		p3 = *(pblock);

		t0 = p0 + p3;
		t1 = p1 + p2;
		t2 = p1 - p2;
		t3 = p0 - p3;

		*(pTmp++) = t0 + t1;
		*(pTmp++) = (t3 << 1) + t2;
		*(pTmp++) = t0 - t1;
		*(pTmp++) = t3 - (t2 << 1);
	}

	// Vertical 
	for (i = 0; i < BLOCK_SIZE; i++)
	{
		pTmp = tmp + i;
		p0 = *pTmp;
		p1 = *(pTmp += BLOCK_SIZE);
		p2 = *(pTmp += BLOCK_SIZE);
		p3 = *(pTmp += BLOCK_SIZE);

		t0 = p0 + p3;
		t1 = p1 + p2;
		t2 = p1 - p2;
		t3 = p0 - p3;

		ii = pos_x + i;
		tblock[pos_y][ii] = t0 + t1;
		tblock[pos_y + 1][ii] = t2 + (t3 << 1);
		tblock[pos_y + 2][ii] = t0 - t1;
		tblock[pos_y + 3][ii] = t3 - (t2 << 1);
	}
}

void inverse4x4(int pos_y, int pos_x)
{
	int i, ii;
	int tmp[16] = { 0 };
	int *pTmp = tmp, *pblock;
	int p0, p1, p2, p3;
	int t0, t1, t2, t3;

	// Horizontal
	for (i = pos_y; i < pos_y + BLOCK_SIZE; i++)
	{
		pblock = &tblock[i][pos_x];
		t0 = *(pblock++);
		t1 = *(pblock++);
		t2 = *(pblock++);
		t3 = *(pblock);

		p0 = t0 + t2;
		p1 = t0 - t2;
		p2 = (t1 >> 1) - t3;
		p3 = t1 + (t3 >> 1);

		*(pTmp++) = p0 + p3;
		*(pTmp++) = p1 + p2;
		*(pTmp++) = p1 - p2;
		*(pTmp++) = p0 - p3;
	}

	//  Vertical 
	for (i = 0; i < BLOCK_SIZE; i++)
	{
		pTmp = tmp + i;
		t0 = *pTmp;
		t1 = *(pTmp += BLOCK_SIZE);
		t2 = *(pTmp += BLOCK_SIZE);
		t3 = *(pTmp += BLOCK_SIZE);

		p0 = t0 + t2;
		p1 = t0 - t2;
		p2 = (t1 >> 1) - t3;
		p3 = t1 + (t3 >> 1);

		ii = i + pos_x;
		block[pos_y][ii] = p0 + p3;
		block[pos_y + 1][ii] = p1 + p2;
		block[pos_y + 2][ii] = p1 - p2;
		block[pos_y + 3][ii] = p0 - p3;
	}
}

int main()
{
	cout << "hello init block and tblock" << endl;
	int pos_y = 0, pos_x = 0;
	int cnt = 0;
	for (int i = 0; i < BLOCK_SIZE; i++)
	{
		for (int j = 0; j < BLOCK_SIZE; j++)
		{
			block[i][j] = cnt;
			tblock[i][j] = 0;
			cnt++;
			cout << "(" << block[i][j] << "," << tblock[i][j] << ") ";
		}
		cout << endl;
	}

	forward4x4(pos_y, pos_x);
	cout << "after DCT" << endl;
	for (int i = 0; i < BLOCK_SIZE; i++)
	{
		for (int j = 0; j < BLOCK_SIZE; j++)
		{
			block[i][j] = 0;
			//tblock[i][j] = rshift_rnd_sf(tblock[i][j],8);
			cout << "(" << block[i][j] << "," << tblock[i][j] << ") ";
		}
		cout << endl;
	}
	inverse4x4(pos_y, pos_x);
	cout << "after IDCT" << endl;
	for (int i = 0; i < BLOCK_SIZE; i++)
	{
		for (int j = 0; j < BLOCK_SIZE; j++)
		{
			tblock[i][j] = 0;
			cout << "(" << block[i][j] << "," << (block[i][j] + 30) / 20 << "," << tblock[i][j] << ") ";
		}
		cout << endl;
	}
	getchar();
	return 0;
}

其中forward4x4是整數DCT的整數部分,inverse4x4是整數DCT的反變換。

由於forward4x4和inverse4x4只有移位和加減,導致的數據沒有被縮放,反變換要想恢復原數據,我添加了(block[i][j]+30)/20的操作,模擬量化步驟中的縮放,由於測試數據是0,1,2,3 ... 15,所以用30和20實現了無損還原,在實際的H264標準中,是以經驗值代替的。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章