深入剖析H.264的1/2像素(无代码,无真相,彻底弄清分数像素)

        H.264的亮度块预测时,支持分数像素,如1/2像素、1/4像素、1/8像素(1/8像素作用不是特别大,现逐渐在取消).开始学习时,对分数像素的理解颇为困难. 其实,分数像素并不是说像素的值是分数形式的,而是说像素的位置是通过插值得来的,认为它的位置在分数位置,体现在运动矢量上就是分数形式的运动矢量. 1/4像素和1/2像素的本质是相同的,为了简便起见,下面仅讨论1/2像素. (视频序列为foreman, 用JM8.6的baseline将其头三帧编码为IPP,分析工具为H.264visa, 插值代码是在VC++6.0中写的.)

 

      用H.264visa打开码流,选择第二帧(P帧)的一个宏块,该宏块信息为:

 

==== MB 30(8, 2) ====
    Location : (128, 32),
    Slice No. : 0
    Slice Type : P Slice
    MB Type : (4)P_8x8ref0
    NumMbPart : 4
    MbPartSize : (8, 8)
    Subblock Type:
       +-----------------+----------------+
       |    (0)P_L0_8x8  |    (3)P_L0_4x4 |
       +-----------------+----------------+
       |    (0)P_L0_8x8  |    (1)P_L0_8x4 |
       +-----------------+----------------+

****** Inter Info ******

Block(0, 0):
  (0,0) L0=MV(-2, 0),POC: 0,refIdx:0,DecNo: 1

Block(1, 0):
  (0,0) L0=MV(14,14),POC: 0,refIdx:0,DecNo: 1
  (1,0) L0=MV(-1, 1),POC: 0,refIdx:0,DecNo: 1
  (0,1) L0=MV(-1, 1),POC: 0,refIdx:0,DecNo: 1
  (1,1) L0=MV( 0, 1),POC: 0,refIdx:0,DecNo: 1

Block(0, 1):
  (0,0) L0=MV(-16, 1),POC: 0,refIdx:0,DecNo: 1

Block(1, 1):
  (0,0) L0=MV(-2, 1),POC: 0,refIdx:0,DecNo: 1
  (0,1) L0=MV(-15, 1),POC: 0,refIdx:0,DecNo: 1

 

       由  (0,0) L0=MV(-2, 0),POC: 0,refIdx:0,DecNo: 1可知:该小块的实际运动矢量为(-1/2, 0). 从H.264visa中得到该宏块的预测值为:

 

====================== Y Data ======================
+----------------+----------------+----------------+----------------+
|204,204,204,206,|206,205,204,201,|143,113,118,115,|115,129,176,206,|
|204,204,204,204,|203,201,207,214,|199,142,111,122,|130,115,130,172,|
|204,203,203,203,|200,200,204,199,|210,199,148,114,|118,125,112,120,|
|204,203,203,203,|199,199,201,192,|205,215,203,151,|118,118,120,107,|
+----------------+----------------+----------------+----------------+
|203,203,202,202,|204,205,194,174,|197,205,204,213,|157,117,114,124,|
|202,202,202,202,|202,203,203,202,|203,203,204,204,|203,160,123,117,|
|203,203,203,203,|203,204,204,208,|206,204,204,203,|212,206,166,124,|
|203,203,204,204,|204,204,204,202,|201,203,204,205,|204,216,209,171,|
+----------------+----------------+----------------+----------------+
|204,204,204,204,|204,205,204,204,|202,201,202,204,|205,206,207,219,|
|204,203,203,203,|204,205,206,206,|203,201,201,203,|204,204,206,205,|
|213,211,209,208,|208,207,206,206,|203,201,200,202,|203,203,205,206,|
|214,213,213,212,|211,209,209,209,|203,201,200,202,|203,204,204,206,|
+----------------+----------------+----------------+----------------+
|183,186,188,190,|197,199,204,210,|211,207,204,204,|203,201,201,201,|
|170,169,170,172,|183,185,189,192,|198,202,204,204,|204,202,201,200,|
|179,178,177,177,|180,181,185,187,|184,193,200,203,|204,203,202,200,|
|177,178,180,181,|182,183,185,186,|184,185,194,204,|203,203,202,200,|
+----------------+----------------+----------------+----------------+

 

        意料之中的是,在第一帧(I帧)的重建值中并不能找到上面那个8*8小块,因为,运动矢量是分数形式的,所以上面的预测值是通过对第一帧的重建值进行插值而得到的.  根据H.264中1/2像素的插值原理可知,当运动矢量为 (-1/2, 0)时,要插出8*8个像素值,需要8*13个像素(竖直方向分量为0,不用插值),详细解释如下:

        假设像素横排为:x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x 12 x13, 那么x1 x2 x3 x4 x5 x6可以插出y1, 即x1 x2 x3y1 x4 x5 x6, 同理x2 x3 x4 x5 x6 x7可以插出y2, 即x2 x3 x4y2 x5 x6 x7, 依次类推,x8 x9 x10 x11 x 12 x13可出插出y8,即x8 x9 x10y8 x11 x 12 x13.

       

        根据运动矢量(-1/2, 0),  选择对应的8*13个像素值来插值,这8 * 13个像素值为第一帧中对应的宏块和它左边的宏块的重建值,如下:

 

Frame: 1, MB Position: 8, 2

====================== Y Data ======================
+----------------+----------------+----------------+----------------+
|204,204,205,206,|206,205,203,183,|118,107,122,131,|113,152,193,210,|
|204,204,204,203,|202,203,212,208,|171,123,115,133,|121,119,151,191,|
|203,203,203,202,|199,202,203,202,|222,184,128,107,|126,118,114,144,|
|203,203,203,202,|198,201,198,189,|200,216,186,128,|115,123,115,103,|
+----------------+----------------+----------------+----------------+
|203,203,202,203,|205,201,184,176,|205,205,205,205,|143,112,115,123,|
|202,202,202,202,|202,203,202,202,|202,203,205,205,|195,146,117,118,|
|203,203,203,203,|203,204,205,209,|205,204,204,204,|214,198,151,119,|
|203,203,204,204,|204,204,203,201,|202,203,204,204,|204,217,203,153,|
+----------------+----------------+----------------+----------------+
|204,204,204,204,|205,203,202,202,|201,201,203,204,|205,208,212,214,|
|204,205,205,205,|205,205,203,203,|202,201,202,203,|204,205,207,208,|
|205,206,206,206,|206,206,203,203,|202,200,201,202,|203,204,206,206,|
|212,209,207,206,|206,208,204,203,|202,200,201,202,|203,204,205,205,|
+----------------+----------------+----------------+----------------+
|201,203,208,213,|213,208,204,204,|203,200,201,201,|203,204,204,205,|
|185,187,191,195,|201,205,203,203,|204,202,201,200,|201,203,205,205,|
|180,181,185,187,|184,192,203,203,|204,203,202,200,|201,203,205,205,|
|181,182,185,186,|184,183,190,203,|204,203,202,200,|201,203,205,205,|
+----------------+----------------+----------------+----------------+

       

Frame: 1, MB Position: 7, 2   (该宏块在MB Position: 8, 2 的左边)

====================== Y Data ======================
+----------------+----------------+----------------+----------------+
|233,233,232,232,|230,229,227,223,|218,212,208,206,|205,205,204,204,|
|233,233,232,232,|230,229,227,223,|219,215,209,206,|205,205,205,204,|
|233,233,232,232,|230,229,227,224,|221,217,210,205,|205,205,204,204,|
|233,233,232,232,|230,230,227,225,|223,220,212,206,|205,205,204,204,|
+----------------+----------------+----------------+----------------+
|233,233,232,232,|231,230,228,227,|224,220,211,202,|205,204,203,203,|
|233,233,232,232,|231,230,229,228,|227,221,210,202,|204,203,202,202,|
|232,232,231,231,|230,230,229,229,|229,226,215,207,|204,203,202,202,|
|232,231,230,230,|230,230,230,231,|230,228,220,212,|205,204,203,203,|
+----------------+----------------+----------------+----------------+
|232,232,231,231,|230,230,230,231,|231,229,223,215,|204,204,204,204,|
|233,233,232,232,|231,231,231,232,|232,230,223,220,|203,203,203,203,|
|235,234,233,233,|233,233,233,234,|233,231,225,218,|209,207,206,205,|
|206,205,204,204,|204,204,206,207,|217,225,225,221,|218,216,215,214,|
+----------------+----------------+----------------+----------------+
|159,160,165,170,|173,172,174,176,|178,180,184,186,|191,194,196,197,|
|145,150,155,159,|162,163,165,167,|166,166,167,167,|168,168,169,172,|
|128,131,136,140,|151,157,166,173,|176,177,177,178,|178,177,176,176,|
|113,115,120,122,|123,128,139,145,|175,175,176,176,|177,177,178,179,|
+----------------+----------------+----------------+----------------+

          

        所以,待插值的8*13的像素值为:

205,204,204,204,204,205,206,206,205,203,183,118,107,
205,205,204,204,204,204,203,202,203,212,208,171,123,
205,204,204,203,203,203,202,199,202,203,202,222,184,
205,204,204,203,203,203,202,198,201,198,189,200,216,
204,203,203,203,203,202,203,205,201,184,176,205,205,
203,202,202,202,202,202,202,202,203,202,202,202,203,
203,202,202,203,203,203,203,203,204,205,209,205,204,
204,203,203,203,203,204,204,204,204,203,201,202,203,

 

        根据H.264的1/2像素的插值原理可知,横向1/2插值的最终结果为:(以第一行为例)

205, 204, 204, y1, 204, y2 ,204, y3, 205, y4, 206, y5, 206, y6, 205, y7, 203, y8, 183, 118, 107

 

      具体插值的代码如下:

#include<iostream>
using namespace std;

// H.264中6抽头系数的1/2像素插值
int tap6Interpolate(int a[], int start)
{
	return int((a[start] - 5 * a[start + 1]  + 
		20 * a[start + 2] + 20 * a[start + 3] 
		- 5 * a[start + 4] + a[start + 5])/32.0 + 0.5);
}

int main()
{
	// 待插值的像素值
	int ref[8][13] = 
	{
		205,204,204,204,204,205,206,206,205,203,183,118,107,
		205,205,204,204,204,204,203,202,203,212,208,171,123,
		205,204,204,203,203,203,202,199,202,203,202,222,184,
		205,204,204,203,203,203,202,198,201,198,189,200,216,
		204,203,203,203,203,202,203,205,201,184,176,205,205,
		203,202,202,202,202,202,202,202,203,202,202,202,203,
		203,202,202,203,203,203,203,203,204,205,209,205,204,
		204,203,203,203,203,204,204,204,204,203,201,202,203
	};

	// 插值后的像素值(实际上就是预测矩阵)
	int predict[8][8];

	int i, j;
	for(i = 0; i < 8; i++)
	{
		for(j = 0; j < 8; j++)
		{
			// 插值
			predict[i][j] = tap6Interpolate(ref[i], j);
		}
	}

	for(i = 0; i < 8; i++)
	{
		for(j = 0; j < 8; j++)
		{
			// 输出矩阵
			cout << predict[i][j] << "\t";
		}
		cout << endl;
	}

	return 0;
}


       结果为:

 

204     204     204     206     206     205     204     201
204     204     204     204     203     201     207     214
204     203     203     203     200     200     204     199
204     203     203     203     199     199     201     192
203     203     202     202     204     205     194     174
202     202     202     202     202     203     203     202
203     203     203     203     203     204     204     208
203     203     204     204     204     204     204     202

 

        回头再看第二帧对应宏块的预测值:

====================== Y Data ======================
+----------------+----------------+----------------+----------------+
|204,204,204,206,|206,205,204,201,|143,113,118,115,|115,129,176,206,|
|204,204,204,204,|203,201,207,214,|199,142,111,122,|130,115,130,172,|
|204,203,203,203,|200,200,204,199,|210,199,148,114,|118,125,112,120,|
|204,203,203,203,|199,199,201,192,|205,215,203,151,|118,118,120,107,|
+----------------+----------------+----------------+----------------+
|203,203,202,202,|204,205,194,174,|197,205,204,213,|157,117,114,124,|
|202,202,202,202,|202,203,203,202,|203,203,204,204,|203,160,123,117,|
|203,203,203,203,|203,204,204,208,|206,204,204,203,|212,206,166,124,|
|203,203,204,204,|204,204,204,202,|201,203,204,205,|204,216,209,171,|
+----------------+----------------+----------------+----------------+
|204,204,204,204,|204,205,204,204,|202,201,202,204,|205,206,207,219,|
|204,203,203,203,|204,205,206,206,|203,201,201,203,|204,204,206,205,|
|213,211,209,208,|208,207,206,206,|203,201,200,202,|203,203,205,206,|
|214,213,213,212,|211,209,209,209,|203,201,200,202,|203,204,204,206,|
+----------------+----------------+----------------+----------------+
|183,186,188,190,|197,199,204,210,|211,207,204,204,|203,201,201,201,|
|170,169,170,172,|183,185,189,192,|198,202,204,204,|204,202,201,200,|
|179,178,177,177,|180,181,185,187,|184,193,200,203,|204,203,202,200,|
|177,178,180,181,|182,183,185,186,|184,185,194,204,|203,203,202,200,|
+----------------+----------------+----------------+----------------+

 

         一切一目了然.

       

      

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值