|
3.2.5 运动估计与补偿
通过对一幅已知图的一块相邻像素值的重定位来预测一幅图中一块像素的值,运动被描述为一个二维的运动矢量,它指出从用以预测当前块像素值以前的编码图的什么地方来恢复一块像素值。最简单的例子就是摄像机不移动,且场景中的物体也不运动的情况,对每幅图像的位置相同,像素值都相同,且每块的运动矢量为零。
运动补偿(Motion Compensation)实际上是对活动图像进行压缩时所使用的一种帧间编码技术,活动图像主要指一系列静止图像的连续排列,当它们以不小于24帧/秒的数率连续显示时,由于人眼的视觉暂留特性,使人产生了连续的感觉,因此一般情况下,相邻帧间的内容实际上没有太大的变化(场景切换等除外),有很大一部分可能是完全一样的,所以相邻帧间有较大的相关性,这种相关性称为时域相关性。运动补偿的目的正是要将这种时域相关性可能地去除。
运动补偿地基本原理是,当编码器对图像序列中地第N帧进行处理时,利用运动补偿中地核心技术-运动估值ME(Motion Estimation),得到第N帧得预测帧N´。在实际编码传输时,并不总时传输第N帧,而是第N帧和其预测帧N´得差值△。如果运动估计十分有效,△中得概率基本上分布在零附近,从而导致△比原始图像第N帧得能量小得多,编码传输△所需得比特数也就少得多。这就是运动补偿技术能够去除信源中时间冗余度得本质所在。运动补偿原理如图3.17所示。
|
| 图3.17 运动估计基本原理 |
运动补偿的步骤如下:
(1)图像分割为静止得和运动的两部分,估计物体得位移向量(位移值)。 (2)按照估计得到的位移向量取得前一帧的图像数据。 (3)通过使用预测滤波器,得到前一帧图像数据的预测像素。 一个简单的运动补偿过程如图3.16所示。
|
| 图3.16 运动补偿过程 |
运动估值算法
运动估值算法被归纳为两大类,一类是像素递归算法PRA,另一类是块匹配算法。PRA是基于递归思想,如果连续帧中,像素数据得变化是因为物体得位移引起得,算法就会在剃度方向几个像素周围得若干像素做叠代运算,使连续得运算最后收敛于一个运动估计矢量,从而预测该像素得位移;而BMA则使基于当前帧中一定大小得块,在当前帧得前后帧得一定区域内搜索该像素块得最佳匹配块,做为它得预测块,尽管PRA对比较复杂得运动形式来说,其预测精度要较BMA高,当使由于其计算量比BMA大得多,同时BMA算法本省得性能并不完善,所以MPEG推荐BMA。
BMA算法使一种非常直观得运动估计算法,它使基于平移运动得机理来进行运动估值得,在平移运动中,物体上得每一点均又相同得速度大小和方向,在物体运动得估计上,当前时刻所处位置使由前一时刻位置偏移而得到的。把这种认识应用到图像序列中,也就是第N帧中的内容是由第N-1帧中的相应部分经不同方向的平移而形成的,于是,将每帧图像被分成的二维的16X16像素的子块,假定每个子块内的像素都作相等的平移运动,在其相邻帧中相对应的几何位置周围的一定范围内,通过某种匹配准则,寻找这些16x16像素块的最佳匹配块。一旦找到,便将最佳匹配块与当前的相对位移(通常所说的运动矢量)送出,并传输到接收端。 实际应用时,只将运动矢量及最佳匹配块与当前块之间的差值块一起编码传输。在接收端,通过运动矢量在已经恢复的相邻帧中找到当前块的最佳匹配块,并与接收到的差值块相加恢复出当前块,这就是运动补偿基本过程。从BMA的实现原理中可以看到由二个问题需要解决,搜索方式和匹配准则。搜索方式
在众多搜索方式中,计算量最大、精度最高的搜索方式是全搜索方式,它是在搜索窗口SW中的所有可能的偏移位置上对当前块均进行一次匹配运算,最后对素有的寄过进行比较,从而得到最佳匹配及其偏移位置。由于全搜索方式计算匹配次数太多,计算量大,以此在实际过程中产生了许多快速算法。 匹配准则则不仅涉及到搜索进度,而且设计搜索速度。衡量匹配好坏的准测由归一化相关函数NCCF、均方误差MSE和平均绝对误差MAD。采用3种准则所得的估值寄过差别不大,因MAD便于计算和易于硬件实现,而广泛应用。
块匹配是一种在当前图像块和前一帧图像有限区域内的多个侯选块中进行最佳匹配搜索的相关性技术。
整像素运动估计
对最佳匹配MB的搜索由Y分量的整数像素的位移完成。在当前MB和先前原始VOP中被替代的MB间进行比较,并在搜索窗口内进行全搜索,该窗口在原始MB周围水品和垂直方向熵31.5各像素范围内。
这里,x,y≤±31.5,而N=16或8。
(1)16x16或8x8预测模式的判决
为了得到半像素16x16矢量的最佳匹配,SAD记做SAD16(x,y),其中若矢量为(0,0),SAD会减少100,对整个MB为找到最佳匹配的半像素8x8矢量,SAD计算如下:
这里,NB是VOP内的MB像素数。从最低SAD16所得的一对(x,y)值被选作16x16整数像素的MV,V0.相应的SAD为SAD16(x,y)。 (2)INTRA(帧内)/NITER(帧间)模式判决 当整数像素运动估计完成后,编码器要判定是用INTRA还是INTER编码模式,4个8x8MV代表每个16x16MB。MB基于SAD的8x8像块如下:
这里,0<k≤4是位于VOP轮廓内的8x8像块数。
如果A<(SADinter-2NB),则选择INTRA模式。若选择了 NITRA模式,对于运动搜索不需要进一步的操作,然而,如果选择了NITER模式,运动搜索将围绕V0位置继续半像素的搜索。 计算SAD代码如下:
//计算宏块 int SAD_Macroblock (unsigned char *ii, unsigned char *act_block, int h_length, int Min_FRAME) { int i; int sad = 0; unsigned char *kk; kk = act_block; i = 16; while (i--) { sad += (abs (*ii - *kk) + abs (*(ii + 1) - *(kk + 1)) + abs (*(ii + 2) - *(kk + 2)) + abs (*(ii + 3) - *(kk + 3)) + abs (*(ii + 4) - *(kk + 4)) + abs (*(ii + 5) - *(kk + 5)) + abs (*(ii + 6) - *(kk + 6)) + abs (*(ii + 7) - *(kk + 7)) + abs (*(ii + 8) - *(kk + 8)) + abs (*(ii + 9) - *(kk + 9)) + abs (*(ii + 10) - *(kk + 10)) + abs (*(ii + 11) - *(kk + 11)) + abs (*(ii + 12) - *(kk + 12)) + abs (*(ii + 13) - *(kk + 13)) + abs (*(ii + 14) - *(kk + 14)) + abs (*(ii + 15) - *(kk + 15))); ii += h_length; kk += 16; if (sad > Min_FRAME) return INT_MAX; } return sad; } //计算块 int SAD_Block (unsigned char *ii, unsigned char *act_block, int h_length, int min_sofar) { int i; int sad = 0; unsigned char *kk; kk = act_block; i = 8; while (i--) { sad += (abs (*ii - *kk) + abs (*(ii + 1) - *(kk + 1)) + abs (*(ii + 2) - *(kk + 2)) + abs (*(ii + 3) - *(kk + 3)) + abs (*(ii + 4) - *(kk + 4)) + abs (*(ii + 5) - *(kk + 5)) + abs (*(ii + 6) - *(kk + 6)) + abs (*(ii + 7) - *(kk + 7))); ii += h_length; kk += 16; if (sad > min_sofar) return INT_MAX; } return sad; } 运动补偿代码如下: void MotionEstimation (unsigned char *curr, unsigned char *reference, int x_curr, int y_curr, int xoff, int yoff, int seek_dist, MotionVector * MV[7][MBR + 1][MBC + 2], int *SAD_0, int estimation_type, int backward_pred, int pmv0, int pmv1) { int Min_FRAME[7]; MotionVector MV_FRAME[7]; unsigned char *act_block, *aa, *ii; unsigned char *search_area, *adv_search_area = NULL, *zero_area = NULL; int sxy, i, k, j, l; int xlim, ylim; int ihigh, ilow, jhigh, jlow, h_length, v_length; int adv_ihigh, adv_ilow, adv_jhigh, adv_jlow, adv_h_length, adv_v_length; int xmax, ymax, block, sad, lx; int adv_x_curr, adv_y_curr, xvec, yvec; #ifndef FULLSEARCH static htp[4] = {-1, 0, 1, 0}; static vtp[4] = {0, 1, 0, -1}; int j_min_now, i_min_now, i_min_next, j_min_next, sad_layr; int distortion_0, distortion_1, distortion_2; int m; #endif xmax = pels; ymax = lines; xlim = ylim = seek_dist; if ( (!long_vectors) || (estimation_type == PB_PICTURE_ESTIMATION) ) { //高级预测模式 if (mv_outside_frame) { //查找范围 xlim = mmin (15 - (2 * DEF_8X8_WIN + 1), xlim); ylim = mmin (15 - (2 * DEF_8X8_WIN + 1), ylim);
xoff = mmin (16, mmax (-16, xoff)); yoff = mmin (16, mmax (-16, yoff));
ilow = x_curr + xoff - xlim; ihigh = x_curr + xoff + xlim;
jlow = y_curr + yoff - ylim; jhigh = y_curr + yoff + ylim;
lx = pels + 32;
if (ilow < -15) ilow = -15; if (ihigh > xmax) ihigh = xmax; if (jlow < -15) jlow = -15; if (jhigh > ymax) jhigh = ymax; } //没有用高级模式 else { //最大查找范围 xlim = mmin (15, xlim); ylim = mmin (15, ylim); ilow = x_curr + xoff - xlim; ihigh = x_curr + xoff + xlim; jlow = y_curr + yoff - ylim; jhigh = y_curr + yoff + ylim; lx = pels; if (ilow < 0) ilow = 0; if (ihigh > xmax - 15) ihigh = xmax - 15; if (jlow < 0) jlow = 0; if (jhigh > ymax - 15) jhigh = ymax - 15; } } else { //RVLC if(EPTYPE) { // UUI = '01' if (unlimited_unrestricted_motion_vectors) { // xlim = xmax; ylim = ymax; // PLUSPTYPE ilow = x_curr - xlim; ihigh = x_curr + xlim;
jlow = y_curr - ylim; jhigh = y_curr + ylim; lx = pels + 64; if (ilow < -15) ilow = -15; if (ihigh > xmax) ihigh = xmax; if (jlow < -15) jlow = -15; if (jhigh > ymax) jhigh = ymax; } // UUI = '1' else { #ifdef FULLSEARCH //附录D xlim = (pels < 353) 31 : (pels < 705) 63 : (pels < 1409) 127 : 255; ylim = (lines < 289) 31 : (lines < 577) 63 : 127; // PLUSPTYPE ilow = x_curr - xlim; ihigh = x_curr + xlim;
jlow = y_curr - ylim; jhigh = y_curr + ylim; #else //范围 xlim = (pels < 353) 15 : (pels < 705) 31 : (pels < 1409) 63 : 255; ylim = (lines < 289) 15 : (lines < 577) 31 : 127; // if (mv_outside_frame) { xlim = mmin (xlim - (2 * DEF_8X8_WIN + 1), xlim); ylim = mmin (ylim - (2 * DEF_8X8_WIN + 1), ylim); } // If PLUSPTYPE ilow = x_curr - xlim; ihigh = x_curr + xlim;
jlow = y_curr - ylim; jhigh = y_curr + ylim; #endif //PLUSPTYPE lx = pels + 64; if (ilow < -15) ilow = -15; if (ihigh > xmax) ihigh = xmax; if (jlow < -15) jlow = -15; if (jhigh > ymax) jhigh = ymax; } } else { xlim = 31; ylim = 31; if (use_4mv) { xlim = mmin (xlim - (2 * DEF_8X8_WIN + 1), xlim); ylim = mmin (ylim - (2 * DEF_8X8_WIN + 1), ylim); } xoff = mmin (31, mmax (-31, xoff)); yoff = mmin (31, mmax (-31, yoff)); if (pmv0 < -31) { ilow = x_curr - xlim; ihigh = x_curr - 1; } else /*if (xoff > 16)*/ if (pmv0 > 32) { ilow = x_curr + 1; ihigh = x_curr + xlim; } else { ilow = x_curr + xoff - 15; ihigh = x_curr + xoff + 14; } // if (yoff < -15) if (pmv1 < -31) { jlow = y_curr - ylim; jhigh = y_curr - 1; } else /*if (yoff > 16)*/ if (pmv1 > 32) { jlow = y_curr + 1; jhigh = y_curr + ylim; } else { jlow = y_curr + yoff - 15; jhigh = y_curr + yoff + 14; } lx = pels + 64; if (ilow < -31) ilow = -31; if (ihigh > xmax + 15) ihigh = xmax + 15; if (jlow < -31) jlow = -31; if (jhigh > ymax + 15) jhigh = ymax + 15; } } h_length = ihigh - ilow + 16; v_length = jhigh - jlow + 16; act_block = LoadArea (curr, x_curr, y_curr, 16, 16, pels); search_area = LoadArea (reference, ilow, jlow, h_length, v_length, lx); for (k = 0; k < 7; k++) { Min_FRAME[k] = INT_MAX; MV_FRAME[k].x = 0; MV_FRAME[k].y = 0; MV_FRAME[k].x_half = 0; MV_FRAME[k].y_half = 0; } //零向量查找 if (x_curr - ilow < 0 || y_curr - jlow < 0 || x_curr - ilow + MB_SIZE > h_length || y_curr - jlow + MB_SIZE > v_length) { //零向量 zero_area = LoadArea (reference, x_curr, y_curr, 16, 16, lx); *SAD_0 = SAD_Macroblock (zero_area, act_block, 16, Min_FRAME[0]) - PREF_NULL_VEC; free (zero_area); } else { ii = search_area + (x_curr - ilow) + (y_curr - jlow) * h_length; *SAD_0 = SAD_Macroblock (ii, act_block, h_length, Min_FRAME[0]) - PREF_NULL_VEC; } if (xoff == 0 && yoff == 0) { Min_FRAME[0] = *SAD_0; MV_FRAME[0].x = 0; MV_FRAME[0].y = 0; } else { ii = search_area + (x_curr + xoff - ilow) + (y_curr + yoff - jlow) * h_length; Min_FRAME[0] = SAD_Macroblock (ii, act_block, h_length, Min_FRAME[0]); MV_FRAME[0].x = xoff; MV_FRAME[0].y = yoff; } //NB sxy = mmax(xlim,ylim); //全象素查找 #ifdef FULLSEARCH for (l = 1; l <= sxy; l++) { i = x_curr + xoff - l; j = y_curr + yoff - l; for (k = 0; k < 8*l; k++) { if (i>=ilow && i<=ihigh && j>=jlow && j<=jhigh) { //16x16 ii = search_area + (i-ilow) + (j-jlow)*h_length; sad = SAD_Macroblock(ii, act_block, h_length, Min_FRAME[0]); if (sad < Min_FRAME[0]) { MV_FRAME[0].x = i - x_curr; MV_FRAME[0].y = j - y_curr; Min_FRAME[0] = sad; } } if (k<2*l) i++; else if (k<4*l) j++; else if (k<6*l) i--; else j--; } } #else //快速查找 i_min_now = x_curr + xoff; j_min_now = y_curr + yoff; distortion_0 = distortion_1 = distortion_2 = 65536; for (l = 1; l <= 2 * sxy; l++) { sad_layr = 65536; for (m = 0; m < 4; m++) { i = i_min_now + htp[m]; j = j_min_now + vtp[m]; if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh) { //16x16 ii = search_area + (i - ilow) + (j - jlow) * h_length; sad = SAD_Macroblock (ii, act_block, h_length, sad_layr); //map if (sad < Min_FRAME[0]) { MV_FRAME[0].x = i - x_curr; MV_FRAME[0].y = j - y_curr; Min_FRAME[0] = sad; } if (sad < sad_layr) { sad_layr = sad; i_min_next = i; j_min_next = j; } } } i_min_now = i_min_next; j_min_now = j_min_next; distortion_2 = distortion_1; distortion_1 = distortion_0; distortion_0 = sad_layr; if (distortion_1 <= distortion_0 && distortion_2 <= distortion_0) { break; } } #endif //使用4个运动矢量 if (use_4mv) { //8x8 xvec = MV_FRAME[0].x; yvec = MV_FRAME[0].y;
if (!long_vectors || estimation_type == PB_PICTURE_ESTIMATION) { if (xvec > 15 - DEF_8X8_WIN) { xvec = 15 - DEF_8X8_WIN; } if (yvec > 15 - DEF_8X8_WIN) { yvec = 15 - DEF_8X8_WIN; } if (xvec < -15 + DEF_8X8_WIN) { xvec = -15 + DEF_8X8_WIN; } if (yvec < -15 + DEF_8X8_WIN) { yvec = -15 + DEF_8X8_WIN; } } adv_x_curr = x_curr + xvec; adv_y_curr = y_curr + yvec; sxy = DEF_8X8_WIN; adv_ilow = adv_x_curr - xlim; adv_ihigh = adv_x_curr + xlim; adv_jlow = adv_y_curr - ylim; adv_jhigh = adv_y_curr + ylim; adv_h_length = adv_ihigh - adv_ilow + 16; adv_v_length = adv_jhigh - adv_jlow + 16; adv_search_area = LoadArea (reference, adv_ilow, adv_jlow, adv_h_length, adv_v_length, lx); for (block = 0; block < 4; block++) { ii = adv_search_area + (adv_x_curr - adv_ilow) + ((block & 1) << 3) + (adv_y_curr - adv_jlow + ((block & 2) << 2)) * adv_h_length; aa = act_block + ((block & 1) << 3) + ((block & 2) << 2) * 16; Min_FRAME[block + 1] = SAD_Block (ii, aa, adv_h_length, Min_FRAME[block + 1]); MV_FRAME[block + 1].x = MV_FRAME[0].x; MV_FRAME[block + 1].y = MV_FRAME[0].y; } //全象素查找 #ifdef FULLSEARCH for (l = 1; l <= sxy; l++) { i = adv_x_curr - l; j = adv_y_curr - l; for (k = 0; k < 8*l; k++) { if (i>=adv_ilow && i<=adv_ihigh && j>=adv_jlow && j<=adv_jhigh) {
//8x8 for (block = 0; block < 4; block++) { ii = adv_search_area + (i-adv_ilow) + ((block&1)<<3) + (j-adv_jlow + ((block&2)<<2) )*adv_h_length; aa = act_block + ((block&1)<<3) + ((block&2)<<2)*16; sad = SAD_Block(ii, aa, adv_h_length, Min_FRAME[block+1]); if (sad < Min_FRAME[block+1]) { MV_FRAME[block+1].x = i - x_curr; MV_FRAME[block+1].y = j - y_curr; Min_FRAME[block+1] = sad; } }
} if (k<2*l) i++; else if (k<4*l) j++; else if (k<6*l) i--; else j--; } } #else //快速查找 for (block = 0; block < 4; block++) { i_min_now = adv_x_curr; j_min_now = adv_y_curr; distortion_0 = distortion_1 = distortion_2 = 65536; for (l = 1; l <= 2 * sxy; l++) { sad_layr = 65536; for (m = 0; m < 4; m++) { i = i_min_now + htp[m]; j = j_min_now + vtp[m]; if (i >= adv_ilow && i <= adv_ihigh && j >= adv_jlow && j <= adv_jhigh) { //8x8 ii = adv_search_area + (i - adv_ilow) + ((block & 1) << 3) + (j - adv_jlow + ((block & 2) << 2)) * adv_h_length; aa = act_block + ((block & 1) << 3) + ((block & 2) << 2) * 16; sad = SAD_Block (ii, aa, adv_h_length, sad_layr); if (sad < Min_FRAME[block + 1]) { MV_FRAME[block + 1].x = i - x_curr; MV_FRAME[block + 1].y = j - y_curr; Min_FRAME[block + 1] = sad; } if (sad < sad_layr) { sad_layr = sad; i_min_next = i; j_min_next = j; } } } } i_min_now = i_min_next; j_min_now = j_min_next; distortion_2 = distortion_1; distortion_1 = distortion_0; distortion_0 = sad_layr; if (distortion_1 <= distortion_0 && distortion_2 <= distortion_0) { break; } } #endif } i = x_curr / MB_SIZE + 1; j = y_curr / MB_SIZE + 1; //没有使用4运动矢量 if (!use_4mv) { if(!backward_pred) { MV[0][j][i]->x = MV_FRAME[0].x; MV[0][j][i]->y = MV_FRAME[0].y; MV[0][j][i]->min_error = Min_FRAME[0]; } else { MV[5][j][i]->x = MV_FRAME[0].x; MV[5][j][i]->y = MV_FRAME[0].y; MV[5][j][i]->min_error = Min_FRAME[0]; } } else { for (k = 0; k < 5; k++) { MV[k][j][i]->x = MV_FRAME[k].x; MV[k][j][i]->y = MV_FRAME[k].y; MV[k][j][i]->min_error = Min_FRAME[k]; } } free (act_block); free (search_area); if (use_4mv) free (adv_search_area); return; } | 图像运动补偿代码如下:
void MotionEstimatePicture( unsigned char *curr, unsigned char *prev, unsigned char *next, unsigned char *prev_ipol, unsigned char *next_ipol, int seek_dist, MotionVector *MV[7][MBR+1][MBC+2], int gobsync, int estimation_type) { int i,j,k; int pmv0,pmv0b,pmv1,pmv1b,xoff,yoff, xoffb, yoffb; int curr_mb[16][16]; int sad8 = INT_MAX, sad16, sad16b, sad0, sad0b; int newgob; MotionVector *f0,*f1,*f2,*f3,*f4,*fBack; for ( j = 0; j < lines/MB_SIZE; j++) { newgob = 0; if (gobsync && j%gobsync == 0) { newgob = 1; } for ( i = 0; i < pels/MB_SIZE; i++) { f0 = MV[0][j+1][i+1]; f1 = MV[1][j+1][i+1]; f2 = MV[2][j+1][i+1]; f3 = MV[3][j+1][i+1]; f4 = MV[4][j+1][i+1]; fBack = MV[5][j+1][i+1]; //PB预测 if (B_PICTURE_ESTIMATION != estimation_type) { // PMV FindPMV(MV,i+1,j+1,&pmv0,&pmv1,0,newgob,0); if (long_vectors && (estimation_type != PB_PICTURE_ESTIMATION) ) { // xoff = pmv0/2; yoff = pmv1/2; } else { xoff = yoff = 0; } MotionEstimation( curr, prev, i*MB_SIZE, j*MB_SIZE, xoff, yoff, seek_dist, MV, &sad0,estimation_type, 0,pmv0,pmv1); sad16 = f0->min_error; if (use_4mv) { sad8 = f1->min_error + f2->min_error + f3->min_error + f4->min_error; } f0->Mode = ChooseMode(curr,i*MB_SIZE,j*MB_SIZE, mmin(sad8,sad16)); if(intra_mb_refresh && intra_refresh[j+1][i+1]>=intra_mb_refresh) { f0->Mode = MODE_INTRA; } //半像素查找 if (f0->Mode != MODE_INTRA) { FindMB(i*MB_SIZE,j*MB_SIZE ,curr, curr_mb); FindHalfPel(i*MB_SIZE,j*MB_SIZE,f0, prev_ipol, &curr_mb[0][0],16,0); sad16 = f0->min_error; if (use_4mv) { FindHalfPel(i*MB_SIZE,j*MB_SIZE,f1, prev_ipol, &curr_mb[0][0],8,0); FindHalfPel(i*MB_SIZE,j*MB_SIZE,f2, prev_ipol, &curr_mb[0][8],8,1); FindHalfPel(i*MB_SIZE,j*MB_SIZE,f3, prev_ipol, &curr_mb[8][0],8,2); FindHalfPel(i*MB_SIZE,j*MB_SIZE,f4, prev_ipol, &curr_mb[8][8],8,3); sad8 = f1->min_error +f2->min_error +f3->min_error +f4->min_error; sad8 += PREF_16_VEC;
//零向量 if (sad0 < sad8 && sad0 < sad16) { f0->x = f0->y = 0; f0->x_half = f0->y_half = 0; } else { if (sad8 < sad16) f0->Mode = MODE_INTER4V; } } else { //零向量 if (sad0 < sad16) { f0->x = f0->y = 0; f0->x_half = f0->y_half = 0; } } } else { for (k = 0; k < 5; k++) { ZeroVec(MV[k][j+1][i+1]); } } } //bp else { //pmv块 FindPMV(MV,i+1,j+1,&pmv0,&pmv1,0,newgob,0); FindPMV(MV,i+1,j+1,&pmv0b,&pmv1b,5,newgob,0);
if (long_vectors && (estimation_type != PB_PICTURE_ESTIMATION) ) { //是2就关 xoff = pmv0/2; yoff = pmv1/2; xoffb = pmv0b/2; yoffb = pmv1b/2; } else { xoff = yoff = xoffb = yoffb = 0; } //向前预测 MotionEstimation( curr, prev, i*MB_SIZE, j*MB_SIZE, xoff, yoff, seek_dist, MV, &sad0, estimation_type, 0, pmv0, pmv1); sad16 = f0->min_error; //向后预测 MotionEstimation( curr, next, i*MB_SIZE, j*MB_SIZE, xoffb, yoffb, seek_dist, MV, &sad0b, estimation_type, 1, pmv0b, pmv1b); sad16b = fBack->min_error; FindMB(i*MB_SIZE, j*MB_SIZE, curr, curr_mb); FindHalfPel(i*MB_SIZE,j*MB_SIZE, f0, prev_ipol, &curr_mb[0][0],16,0); sad16 = f0->min_error; //16x16零向量 if (sad0 < sad16) { f0->x = f0->y = 0; f0->x_half = f0->y_half = 0; } FindHalfPel(i*MB_SIZE,j*MB_SIZE, fBack, next_ipol, &curr_mb[0][0],16,0); sad16b = fBack->min_error; //16x16零向量 if (sad0b < sad16b) { fBack->x = fBack->y = 0; fBack->x_half = fBack->y_half = 0; } } } } #ifdef PRINTMV fprintf(stdout,"Motion estimation\n"); fprintf(stdout,"16x16 vectors:\n"); for ( j = 0; j < lines/MB_SIZE; j++) { for ( i = 0; i < pels/MB_SIZE; i++) { //BP帧模式 if (B_PICTURE_ESTIMATION == estimation_type) { //向前预测 fprintf(stdout," forward (B): %3d%3d", 2*MV[0][j+1][i+1]->x + MV[0][j+1][i+1]->x_half, 2*MV[0][j+1][i+1]->y + MV[0][j+1][i+1]->y_half); fprintf(stdout," backward (B): %3d%3d", 2*MV[5][j+1][i+1]->x + MV[5][j+1][i+1]->x_half, 2*MV[5][j+1][i+1]->y + MV[5][j+1][i+1]->y_half); } //P帧 else if (MV[0][j+1][i+1]->Mode != MODE_INTRA) { fprintf(stdout," %3d%3d", 2*MV[0][j+1][i+1]->x + MV[0][j+1][i+1]->x_half, 2*MV[0][j+1][i+1]->y + MV[0][j+1][i+1]->y_half); } else { fprintf(stdout," . . "); } } fprintf(stdout,"\n"); } if (use_4mv) { fprintf(stdout,"8x8 vectors:\n"); for (k = 1; k < 5; k++) { fprintf(stdout,"Block: %d\n", k-1); for ( j = 0; j < lines/MB_SIZE; j++) { for ( i = 0; i < pels/MB_SIZE; i++) { if (MV[0][j+1][i+1]->Mode != MODE_INTRA) fprintf(stdout," %3d%3d", 2*MV[k][j+1][i+1]->x + MV[k][j+1][i+1]->x_half, 2*MV[k][j+1][i+1]->y + MV[k][j+1][i+1]->y_half); else fprintf(stdout," . . "); } fprintf(stdout,"\n"); } } } #endif return; }
| 【责任编辑: 夏书 TEL:(010)68476606】
|