jm86之get_block() 1/4亮度像素内插详述

http://blog.csdn.net/zhangji1983/article/details/1502035

理论方面的知识在这里不详细讲述,毕书222页和264标准上的8.4.2.2.1章节都有非常详细的说明。这里,我主要讲的是程序是如何使具体代码对应理论公式。

void get_block(int ref_frame, StorablePicture **list, int x_pos, int y_pos, struct img_par *img, int block[BLOCK_SIZE][BLOCK_SIZE])

函数一开始定义了6抽头系数,这个很容易明白。接着给6个变量赋值,这边我们来看下这6个变量的物理含义。

static const int COEF[6] = { 1, -5, 20, 20, -5, 1 };

dx = x_pos&3;

dy = y_pos&3;

x_pos = (x_pos-dx)/4;

y_pos = (y_pos-dy)/4;

maxold_x = dec_picture->size_x-1;

maxold_y = dec_picture->size_y-1;

jm86之get_block() 1/4亮度像素内插详述_第1张图片

上图中,我已经标出了,现在说明一下,红色填充块表示整像素点,蓝色填充点2表示红色填充点1在前一帧中的预测点。所以:

dx表示预测点距离自己最近的左上整像素点的横坐标(1/4像素单位)

dy表示预测点距离自己最近的左上整像素点的纵坐标(1/4像素单位)

x_pos表示离预测点最近的左上整像素点相对于图像左上顶点的横坐标(整像素单位)

y_pos表示离预测点最近的左上整像素点相对于图像左上顶点的纵坐标(整像素单位)

maxold_x表示程序中图像的宽最大值。

maxold_y表示程序中图像的高最大值。

接下来我们先总体看一下函数中是如何处理内插像素的,如下图,图中已经有简单说明,我就不在重复。下面,我们就将这6种情况一一分析。

jm86之get_block() 1/4亮度像素内插详述_第2张图片

情况一:预测点正好落在整像素点上,即0区域

if (dx == 0 && dy == 0)

{

}

这一部分是最简单的,因为正好预测点落在了整像素点上,所以也不需要任何的内插动作,直接把相关的4x4(下图中在黑框内的16个整像素点)拷贝到当前丢失块中。

jm86之get_block() 1/4亮度像素内插详述_第3张图片

情况二:预测点落在图中的1_2_3区域

if (dy == 0)

{

if ((dx&1) == 1)

{

}

}

我们看到这个区域含有3个内插像素点,其中1点和3点是1/4像素点,而2点是1/2像素点,所以这边代码先进行6抽头插值,接着就有了这个判断if ((dx&1) == 1),作用就是如果落在了1点或者3点这样的1/4像素点,那么就要继续进行双线性插值。

jm86之get_block() 1/4亮度像素内插详述_第4张图片

情况三:预测点落在图中的4_8_12区域

else if (dx == 0)

{

if ((dy&1) == 1)

{

}

}

这部分跟情况二的类似,我就不重复,看下图即可。

jm86之get_block() 1/4亮度像素内插详述_第5张图片

情况四:预测点落在图中的6_10_14区域

else if (dx == 2)

{

if ((dy&1) == 1)

{

}

}

我们看到这个区域也含有3个内插像素点,其中6点和14点是1/4像素点,而10点是1/2像素点,所以这边代码先进行6抽头插值,接着就有了这个判断if ((dy&1) == 1),作用就是如果落在了6或者14这样的1/4像素点,那么就要继续进行双线性插值。但是这边的计算显然要比上面的情况复杂,因为中间这个1/2像素点要通过附近的1/2像素点进行6抽头插值才能得到,所以首先肯定要得到这些附近的1/2像素点。

jm86之get_block() 1/4亮度像素内插详述_第6张图片

对于图中上方的10像素点是通过abcdef6个半像素的中间量进行6抽头插值得到,而对于下方的10像素点则是通过defghi6个半像素的中间量进行6抽头插值得到。因为我们知道get_block处理基本单位的是4x4的整像素块,所以这边tmp_res[4][9]为什么需要9个元素,我想在这里就明白了,以tmp_res[0][0]~tmp_res[0][8]为例,分别存储的就是abcdefghi9个需要用到的半像素的中间量。其他部分我想对照了标准也就没有什么问题了。

情况五:预测点落在图中的9_10_11区域

else if (dy == 2)

{

if ((dx&1) == 1)

{

}

}

这部分跟情况四的类似,我就不重复,看下图即可。

jm86之get_block() 1/4亮度像素内插详述_第7张图片

情况六:预测点落在图中的5_7_13_15区域

else

{

}

这一区域的点都是1/4像素点,计算也有些特殊,是通过对角线上的半像素点进行双线性插值得到,所以,程序中两个for循环就是计算这些半像素点,也就是下图中绿色填充点。

jm86之get_block() 1/4亮度像素内插详述_第8张图片

附录

注意点一:

程序的一开始有这么一段代码,请注意:

if (dec_picture->mb_field[img->current_mb_nr])

maxold_y = dec_picture->size_y/2 - 1;

这边是在判断如果为场图像,那么高度只有帧图像的一半

注意点二:

jm86之get_block() 1/4亮度像素内插详述_第9张图片

图中的蓝色填充块是我们需要插值的1/2像素点,一般情况,我们取半像素点同一纵坐标上的左右各3个最近整像素点,但是明显此时右边已经到了图像的边界,缺2个整像素点,那么此时参考代码中的做法就是用d点的像素值去人为的补两个出来,即d1=d2=d,从而来完成6抽头插值。

你可能感兴趣的:(list,struct,存储)