转:JM8.6之get_block() 1/4亮度像素内插详述

理论方面的知识在这里不详细讲述,毕书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;

  

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

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

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

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

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

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

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

   

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

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

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

{

}

    

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

情况二:预测点落在图中的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像素点,那么就要继续进行双线性插值。

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

    else if (dx == 0)

    {

        if ((dy&1) == 1)

        {

        }

    }

   

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

情况四:预测点落在图中的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像素点。

对于图中上方的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)

        {

        }

    }

   

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

   

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

    else

    {

}

   

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

   

   

附录

注意点一:

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

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

        maxold_y = dec_picture->size_y/2 - 1;

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

注意点二:

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

 

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

posted @ 2012-07-28 20:25  Mr.Rico  阅读(636)  评论(0编辑  收藏  举报