Chinaunix首页 | 论坛 | 博客

分类: LINUX

2012-12-26 20:35:42

近邻取样插值原理  
   

      缩放后图片         原来的图片

    对于缩放后图片中的某点 (Dx, Dy) 对应于原图片中的点 (Sx, Sy),它们之间存在如下的比例关系:
    (Sx-0)/(SW-0)=(Dx-0)/(DW-0)
    (Sy-0)/(SH-0)=(Dy-0)/(DH-0)

    因此,已知缩放后图片中的任意一点
(Dx, Dy),可以求得其对应的原图片中的点 Sx=Dx*SW/DW,Sy=Dy*SH/DH。

近邻取样插值算法及其优化
struct image_info {
    int width;             /* 图像宽度 */
    int height;            /* 图像高度 */
    int bpp;               /* 每像素占据的位数,单位bit */
    int line_width;        /* 图像每行占据的字节数,单位byte */
    unsigned char *data;   /* 图像像素数据 */
};

void zoom0(struct image *src_image, struct image *dst_image)
{
    int x, y;
    int srcx, srcy;
    for(x=0; xwidth; x++)   
    {
        for(y=0; yheight; y++)
        {
            srcx = (x * src_image->width / dst_image->width);
            srcy = (y * src_image->height / dst_image->height);   
            Pixel(dst_image, x, y) = Pixel(src_image, srcx, srcy);
        }
    }
}
   
函数 zoom0() 并没有按照颜色数据在内存中的排列顺序读写(图片的像素数据是逐行存储的),将造成 CPU 缓存预读失败和内存颠簸导致巨大的性能损失,很多硬件都有这种特性,包括缓存、内存、显存、硬盘等,优化顺序访问,随机访问时会造成巨大的性能损失,所以先交换x,y循环的顺序:
void zoom1(struct image *src_image, struct image *dst_image)
{
    int x, y;
    int srcx, srcy;
    for(y=0; yheight; y++)
    {
        for(x=0; xwidth; x++)   
        {
            srcx = (x * src_image->width / dst_image->width);
            srcy = (y * src_image->height / dst_image->height);
            Pixel(dst_image, x, y) = Pixel(src_image, srcx, srcy);
        }
    }
}
    可以发现 srcy 的值和 x 变量无关,可以提前到 x 循环之前:
void zoom2(struct image *src_image, struct image *dst_image)
{
    int x, y;
    int srcx, srcy;
    for(y=0; yheight; y++)
    {
        srcy = (y * src_image->height / dst_image->height);
        for(x=0; xwidth; x++)   
        {
            srcx = (x * src_image->width / dst_image->width);   
            Pixel(dst_image, x, y) = Pixel(src_image, srcx, srcy);
        }
    }
}
    每一行的缩放比例是固定的,那么可以预先建立一个缩放映射表格:
void zoom3(struct image *src_image, struct image *dst_image)
{
    int x, y;
    int srcy;
    unsigned int *xtable;
    xtable = (unsigned int *)malloc(dst_image->width * 4);
    for(x=0; xwidth; x++)
        xtable[x] = (x * src_image->width / dst_image->width);
   
    for(y=0; yheight; y++)
    {
        srcy = (y * src_image->height / dst_image->height);
        for(x=0; xwidth; x++)   
        {
            Pixel(dst_image, x, y) = Pixel(src_image, xtable[x], srcy);
        }
    }
}
    除法运算属于很慢的操作,比一般的加减运算慢几十倍,因此使用定点数的方法来优化它:
void zoom4(struct image *src_image, struct image *dst_image)
{
    int x, y;
    int srcy;
    int xscale, yscale;
    unsigned int *xtable;
    xtable = (unsigned int *)malloc(dst_image->width * 4);
    /* 函数能够处理的最大图片尺寸 65536*65536 */
    xscale = (src_image->width << 16) / dst_image->width;
    yscale = (src_image->height << 16) / dst_image->height

    for(x=0; xwidth; x++)
        xtable[x] = (x * xscale) >> 16;   
    for(y=0; yheight; y++)
    {
        srcy = (y * yscale) >> 16;
        for(x=0; xwidth; x++)   
        {
            Pixel(dst_image, x, y) = Pixel(src_image, xtable[x], srcy);
        }
    }
}
       ——Be loyal to dream. Be brave to try!    linux_xpj@opencores.org
阅读(3736) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~