图像缩放——双线性插值算法

  在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。如果选择一个坐标系统使得  的四个已知点坐标分别为 (0, 0)、(0, 1)、(1, 0) 和 (1, 1),那么插值公式就可以化简为:

用矩阵运算来表示的话就是:

  图像的空间变换,也称几何变换或几何运算,包括图像的平移、旋转、镜像变换、转置、缩放等。空间变换可如下表示:设(u,v)为源图像上的点,(x,y)为目标图像上的点,则空间变换就是将源图像上(u,v)处的颜色值与目标图像上(x,y)处的颜色对应起来。

计算机所处理的图像都是指点阵图,也就是用一个像素矩阵来描述一副图像。举个简单的图像:3X3 的256级灰度图,也就是高为3个象素,宽也是3个象素的图像,每个象素的取值可以是 0-255,代表该像素的亮度,255代表最亮,也就是白色,0代表最暗,即黑色 。

  假如图像的象素矩阵如下所示:(这个矩阵中,图象处理中最常用的坐标系是:x从左到右,从0开始,y从上到下,也是从0开始)
    234   38    22
    67     44    12
    89     65    63

  如果想把这副图放大为 4X4大小的图像,那么第一步肯定想到的是先把4X4的矩阵先画出来再说,好了矩阵画出来了,如下所示,当然,矩阵的每个像素都是未知数,等待着我们去填充:

    ?        ?        ?       ?
    ?        ?        ?       ?
    ?        ?        ?       ?
    ?        ?        ?       ?        
  然后要往这个空的矩阵里面填值了,要填的值从哪里来来呢?是从源图中来,好,先填写目标图最左上角的象素,坐标为(0,0),那么该坐标对应源图中的坐标可以由如下公式得出:                                      
    srcX = dstX * (srcWidth / dstWidth) , srcY = dstY * (srcHeight / dstHeight)
  套用公式,就可以找到对应的原图的坐标了(0*(3/4),0*(3/4))=>(0*0.75,0*0.75)=>(0,0)
  找到了源图的对应坐标,就可以把源图中坐标为(0,0)处的234象素值填进去目标图的(0,0)这个位置了。

  接下来,如法炮制,寻找目标图中坐标为(1,0)的象素对应源图中的坐标,套用公式:
    (1*0.75,0*0.75)=>(0.75,0)
  结果发现,得到的坐标里面竟然有小数,这可怎么办?计算机里的图像可是数字图像,象素就是最小单位了,象素的坐标都是整数,从来没有小数坐标。这时候采用的一种策略就是采用四舍五入的方法(也可以采用直接舍掉小数位的方法),把非整数坐标转换成整数,好,那么按照四舍五入的方法就得到坐标(1,0),完整的运算过程就是这样的:
    (1*0.75,0*0.75)=>(0.75,0)=>(1,0)
  那么就可以再填一个象素到目标矩阵中了,同样是把源图中坐标为(1,0)处的像素值38填入目标图中的坐标。      
  依次填完每个象素,一幅放大后的图像就诞生了,像素矩阵如下所示:
    234    38     22     22  
    67      44     12     12  
    89      65     63     63  
    89      65     63     63

  这种放大图像的方法叫做最临近插值算法,这是一种最基本、最简单的图像缩放算法,效果也是最不好的,放大后的图像有很严重的马赛克,缩小后的图像有很严重的失真;效果不好的根源就是其简单的最临近插值方法引入了严重的图像失真,比如,当由目标图的坐标反推得到的源图的的坐标是一个浮点数的时候,采用了四舍五入的方法,直接采用了和这个浮点数最接近的象素的值,这种方法是很不科学的,当推得坐标值为 0.75的时候,不应该就简单的取为1,既然是0.75,比1要小0.25 ,比0要大0.75 ,那么目标象素值其实应该根据这个源图中虚拟的点四周的四个真实的点来按照一定的规律计算出来的,这样才能达到更好的缩放效果。

双线型内插值算法就是一种比较好的图像缩放算法,它充分的利用了源图中虚拟点四周的四个真实存在的像素值来共同决定目标图中的一个像素值,因此缩放效果比简单的最邻近插值要好很多,计算量比零阶插值大,但缩放后图像质量高,不会出现像素值不连续的情况。

双线性内插值算法描述如下:
  对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为(i+u,j+v) (其中i、j均为浮点坐标的整数部分,u、v为浮点坐标的小数部分,是取值[0,1)区间的浮点数),则这个像素得值 f(i+u,j+v) 可由原图像中坐标为 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所对应的周围四个像素的值决定,即:
    f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)          
其中f(i,j)表示源图像(i,j)处的的像素值,以此类推。

  假如目标图的象素坐标为(1,1),那么反推得到的对应于源图的坐标是(0.75 , 0.75), 这其实只是一个概念上的虚拟象素,实际在源图中并不存在这样一个象素,那么目标图的象素(1,1)的取值不能够由这个虚拟象素来决定,而只能由源图的这四个象素共同决定:(0,0)(0,1)(1,0)(1,1),而由于(0.75,0.75)离(1,1)要更近一些,那么(1,1)所起的决定作用更大一些,这从公式1中的系数uv=0.75×0.75就可以体现出来,而(0.75,0.75)离(0,0)最远,所以(0,0)所起的决定作用就要小一些,公式中系数为(1-u)(1-v)=0.25×0.25也体现出了这一特点;

算法步骤详述:

  假设原始图像大小为size=m×n,其中m与n分别是原始图像的行数与列数。若图像的缩放因子是t(t>0),则目标图像的大小size=t×m×t×n。对于目标图像的某个像素点P(x,y)通过P*1/t可得到对应的原始图像坐标P’( x1,y1),其中x1=x/t,y1=y/t,由于x1,y1都不是整数所以并不存在这样的点,这样可以找出与它相邻的四个点的灰度f1、f2、f3、f4,使用双线性插值算法就可以得到这个像素点P’(x1,y1)的灰度,也就是像素点P(x,y)的灰度。

一个完整的双线性插值算法可描述如下:

(1)通过原始图像和比例因子得到新图像的大小,并创建新图像。

(2)由新图像的某个像素(x,y)映射到原始图像(x’,y’)处。

(3)对x’,y’取整得到(xx,yy)并得到(xx,yy)、(xx+1,yy)、(xx,yy+1)和(xx+1,yy+1)的值。

(4)利用双线性插值得到像素点(x,y)的值并写回新图像。

(5)重复步骤(2)直到新图像的所有像素写完。

核心部分代码如下:

  1. //函数名Bilinear

  2.  

    //参数float k

  3.  

    //返回值无

  4.  

    //作用利用双线性插值来实现图像缩放

  5.  

    void CChildView::Bilinear(float k)

  6.  

    {

  7.  

    int nBpp=m_imPicture .GetBPP ();

  8.  

    int widthNew,heightNew;//新图像的宽度和高度

  9.  

    float widthScale=(float)(1.0/k),heightScale=(float)(1.0/k);

  10.  

    float xx,yy;

  11.  

    int a,b;

  12.  

    int rr,gg,bb;//保存R、G、B分量

  13.  

    //得到新图像的宽度和高度

  14.  

    widthNew=(int)(m_imPicture .GetWidth ()*k);

  15.  

    heightNew =(int)(m_imPicture .GetHeight ()*k);

  16.  

    //利用新图像的宽度和高度来创建新图像

  17.  

    m_imNewPicture .Destroy ();

  18.  

    m_imNewPicture .Create (widthNew ,heightNew ,nBpp);

  19.  

    //得到新、老图像的每行的字节数

  20.  

    int nPitch=m_imPicture .GetPitch ();

  21.  

    int nPitchNew=m_imNewPicture .GetPitch ();

  22.  

    //得到新、老图像的数据指针

  23.  

  24.  

    LPBYTE pBitsNew=(LPBYTE)m_imNewPicture .GetBits ();

  25.  

  26.  

    LPBYTE pBits=(LPBYTE)m_imPicture .GetBits ();

  27.  

  28.  

    if(m_imPicture.GetBPP ()!=24){

  29.  

  30.  

    MessageBox ("必须是24位图像或8位图像");

  31.  

  32.  

    m_imNewPicture .Destroy ();

  33.  

  34.  

    Invalidate();

  35.  

  36.  

    return ;

  37.  

    }

  38.  

  39.  

    for(int x=(int)k;x<widthNew -k;x++){

  40.  

  41.  

    for(int y=(int)k;y<heightNew -k;y++){

  42.  

  43.  

    xx=x*widthScale ;

  44.  

  45.  

    yy=y*heightScale ;

  46.  

  47.  

    if(xx<=1e-8){

  48.  

  49.  

    xx=0;

  50.  

    }

  51.  

  52.  

    if(xx>m_imPicture .GetWidth ()-2)

  53.  

  54.  

    xx=(float)(m_imPicture .GetWidth ()-2);

  55.  

  56.  

    if(yy<=1e-8)

  57.  

  58.  

    yy=0;

  59.  

  60.  

    if(yy>m_imPicture .GetHeight ()-2)

  61.  

  62.  

    yy=(float)(m_imPicture .GetHeight ()-2);

  63.  

  64.  

    a=(int)xx;

  65.  

  66.  

    b=(int)yy;

  67.  

  68.  

    //分别得到对应像素的R、G、B值并用双线性插值得到新像素的R、G、B值

  69.  

  70.  

    int r11,r12,r21,r22;

  71.  

  72.  

    r11=*(pBits+b*nPitch+3*a+2);

  73.  

  74.  

    r12=*(pBits+b*nPitch+3*(a+1)+2);

  75.  

  76.  

    r21=*(pBits+(b+1)*nPitch+3*a+2);

  77.  

  78.  

    r22=*(pBits+(b+1)*nPitch+3*(a+1)+2);

  79.  

  80.  

    rr=(int)(r11*(a+1-xx)*(b+1-yy)+r12*(a+1-xx)*(yy-b)

  81.  

  82.  

    +r21*(xx-a)*(b+1-yy)+r22*(xx-a)*(yy-b));

  83.  

  84.  

    int g11,g12,g21,g22;

  85.  

  86.  

    g11=*(pBits+b*nPitch+3*a+1);

  87.  

  88.  

    g12=*(pBits+b*nPitch+3*(a+1)+1);

  89.  

  90.  

    g21=*(pBits+(b+1)*nPitch+3*a+1);

  91.  

  92.  

    g22=*(pBits+(b+1)*nPitch+3*(a+1)+1);

  93.  

  94.  

    gg=(int)(g11*(a+1-xx)*(b+1-yy)+g12*(a+1-xx)*(yy-b)

  95.  

  96.  

    +g21*(xx-a)*(b+1-yy)+g22*(xx-a)*(yy-b));

  97.  

  98.  

    int b11,b12,b21,b22;

  99.  

  100.  

    b11=*(pBits+b*nPitch+3*a);

  101.  

  102.  

    b12=*(pBits+b*nPitch+3*(a+1));

  103.  

  104.  

    b21=*(pBits+(b+1)*nPitch+3*a);

  105.  

  106.  

    b22=*(pBits+(b+1)*nPitch+3*(a+1));

  107.  

  108.  

    bb=(int)(b11*(a+1-xx)*(b+1-yy)+b12*(a+1-xx)*(yy-b)

  109.  

  110.  

    +b21*(xx-a)*(b+1-yy)+b22*(xx-a)*(yy-b));

  111.  

  112.  

    //将得到的新R、G、B值写到新图像中

  113.  

  114.  

    *(pBitsNew +y*nPitchNew +x*3)=min(255,bb);

  115.  

  116.  

    *(pBitsNew +y*nPitchNew +x*3+1)=min(255,gg);

  117.  

  118.  

    *(pBitsNew +y*nPitchNew +x*3+2)=min(255,rr);

  119.  

    }

  120.  

    }

  121.  

    m_imPicture .Destroy ();

  122.  

    Invalidate ();

  123.  

    }

参考博客资料:http://blog.csdn.net/qiqi5521/article/details/2207562

维基百科 http://zh.wikipedia.org/wiki/%E5%8F%8C%E7%BA%BF%E6%80%A7%E6%8F%92%E5%80%BC

原文地址:https://www.cnblogs.com/snow826520/p/9267837.html

时间: 2024-08-28 15:44:32

图像缩放——双线性插值算法的相关文章

视频图像处理基础知识0(双线性插值算法进行图像缩放)

双线性插值(说的很明白) 来自:http://www.cnblogs.com/linkr/p/3630902.html http://www.cnblogs.com/linkr/p/3630902.html 双线性插值,这个名字咋一听很高大上的样纸,再在维基百科上一查(见文末,我去,一堆的公式吓死人),像俺这种半文盲,看到公式脑子就懵的类型,真心给跪.虽然看着好复杂,但仔细一看道理再简单不过了,所以还是自己梳理一下好. 双线性插值,顾名思义就是两个方向的线性插值加起来(这解释过于简单粗暴,哈哈)

[转载]双线性插值算法进行图像缩放及性能效果优化

原文地址:双线性插值算法进行图像缩放及性能效果优化 一)转自http://handspeaker.iteye.com/blog/1545126 最近在编程时用到了双线性插值算法,对图像进行缩放.网上有很多这方面的资料,介绍的也算明白.但是,这些文章只介绍了算法,并没有具体说怎么实现以及怎么实现最好,举个例子,你可以按照网上文章的算法自己写一个双线性插值程序,用它对一张图片进行处理,然后再用matlab或者openCV的resize函数对同一张图片进行处理,得到的结果是不一样的,如果源图片较小,效

图像处理之基础---图像缩放中的一些 灰度插值算法

在图像缩放,旋转等一些图像处理中,对图像进行插值是不可缺少的一个步骤,下面对一些常用的插值算法进行介绍: 1.最近邻插值 这种插值方法是最简单的一种插值算法,图像输出的像素值的大小直接设为与其最邻近的点的大小即可,这个算法最简单,不需要多说,可以表示为 f(x,y) = g(  round(x)  ,   round(y)  ) 原图                                                                                  

图像缩放算法

图像缩放算法较多,下面仅以最邻近插值算法和双线性插值算法作介绍. 如下图1所示,表示原始图像和缩放以后的图像. 图1 图像缩放(原始图像à缩放图像) 图像缩放就是将原始图像中的点经过某一算法映射到目标图像的点的行为,即要找到目标图像中的点p1对应在原始图像中点p0,简单而言就是找点p0. 假设: 原始图像src的分辨率为(srcW * srcH): 目标图像dst的分辨率为(dstW * dstH). 那么: 原始图像宽与目标图像宽的比例 原始图像高与目标图像高的比例 由 所以,原始图像中的点p

双线性插值算法及需要注意事项

原文博客地址:http://handspeaker.iteye.com/blog/1545126 最近在编程时用到了双线性插值算法,对图像进行缩放.网上有很多这方面的资料,介绍的也算明白.但是,这些文章只介绍了算法,并没有具体说怎么实现以及怎么实现最好,举个例子,你可以按照网上文章的算法自己写一个双线性插值程序,用它对一张图片进行处理,然后再用matlab或者openCV的resize函数对同一张图片进行处理,得到的结果是不一样的,如果源图片较小,效果差距就更大.以下是对于双线性插值的讲解以及上

图像缩放算法【转】

转自:http://blog.csdn.net/qq_21792169/article/details/51020005 版权声明:本文为Linux_Google原创文章,转载请加上原创链接. 转载别人的,但是这篇文章写得确实太好了,所以想分享出来,可是原创文章地址找不到了 ,很可惜. 图像缩放算法 摘要:首先给出一个基本的图像缩放算法,然后一步一步的优化其速度和缩放质量: 高质量的快速的图像缩放 全文 分为:      上篇 近邻取样插值和其速度优化      中篇 二次线性插值和三次卷积插值

双线性插值算法的详细总结

       最近在做视频拼接的项目,里面用到了图像的单应性矩阵变换,在最后的图像重映射,由于目标图像的坐标是非整数的,所以需要用到插值的方法,用的就是双线性插值,下面的博文主要是查看了前辈的博客对双线性插值算法原理进行了一个总结,在这里也感谢一些大牛的博文. http://www.cnblogs.com/linkr/p/3630902.html http://www.cnblogs.com/funny-world/p/3162003.html 双线性插值 假设源图像大小为mxn,目标图像为ax

11、图像缩放算法

正文: 为了便于讨论,这里只处理32bit的ARGB颜色:  代码使用C++;涉及到汇编优化的时候假定为x86平台;使用的编译器为vc2005;  为了代码的可读性,没有加入异常处理代码;  测试使用的CPU为AMD64x2 4200+(2.37G)  和 Intel Core2 4400(2.00G); 速度测试说明:  只测试内存数据到内存数据的缩放  测试图片都是800*600缩放到1024*768; fps表示每秒钟的帧数,值越大表示函数越快 //////////////////////

双线性插值的图像缩放问题

初次开始写博客,想记录下自己在公司实习所做过的事情以及学习到的东西,虽然还是有很多东西不了解也还没做出来,但是也希望这是一种体验. 我于2018.9.3入职进行实习,到现在也快过去两个月了,我在公司进行了轮岗,在大部分岗位都待了几周,现在回到了我应该待的部门-数字IP设计部.其中很多心路感受等有空的时候再一一补上.现在我的任务就是学习图像缩放,一方面我需要一个写论文的方向,另一方面公司说年底会开发这方面的芯片,让我提前做好知识储备.今天就记录一下自己在最近学习中的心得吧. 我所学习的图像缩放采用