zoukankan      html  css  js  c++  java
  • 使用双线性插值法放大图像(matlab实现)

    双线性插值的概念及公式可以参考百度,这里仅对算法原理进行简单的说明:

    双线性插值计算公式:

    f(i+u,j+v) = (1-u)(1-v)f(i,j)+u(1-v)f(i+1,j)+(1-u)vf(i,j+1)+ uvf(i+1,j+1)  

    这个公式表明了如何利用矩阵中的四个像素值计算新的像素值,这些新的像素值就组成了放大后的图像。

    下图是如何将3x3的图像放大为4x4的图像:

    原图像表示为3x3的矩阵(像素值处在黑线的交叉点上),如何计算4x4矩阵的值呢?(像素值处在红色虚线交叉点及红线与黑线的交点上)

    比如新图像B的第一列与原图像A的第一列的对应关系是:

    B(1,1) = A(1,1)

    B(1,2) = A(1,1.66667)

    B(1,3) = A(1,2.33334)

    B(1,4) = A(1,3.00001)

    应用上面的公式,实际上就是用A的含有小数点的位置的像素值来计算B的像素值,但含有小数点位的像素是不存在的,这里称为虚拟位置。

    用原图像A的值就能计算出放大后B的值,是不是很神奇?

    实际上可以这样认为:双线性插值就是把放大后的图像再压缩到原来图像的尺寸大小,计算原图像中虚拟的像素值,等同于计算放大后图像的像素值,

    对于本例来说,B图像的步长相当于A图像步长的(3-1)/(4-1)=0.66667倍。下面我们就可以利用这个比率来对应B中像素位置与A中虚拟像素位置的关系。

    B(1,1) = A(1,1)                    (1-1)*0.66667+1=1

    B(1,2) = A(1,1.66667)         (2-1)*0.66667+1=1.66667

    B(1,3) = A(1,2.33334)         (3-1)*0.66667+1=2.33334

    B(1,4) = A(1,3.00001)         (4-1)*0.66667+1=3.00001

    根据上面的对应关系,我们就可以用代码实现了。

    现在还有一个问题:

    我们计算虚拟像素值是需要周围四个原像素值,比如上列中的(下图中红圈圈住的部分)

    A(1,3) = (1-0)(1-0)A(1,3) + (1-0)0A(1,4) + 0(1-0)A(2,3) + 00A(2,4)

    显然这里的A(1,4)和A(2,4)是无法索引到得,因为原图像是3x3的矩阵。

    为了解决这个问题,在A的最后一行,与最后一列分别加上0,这样A就变成了4x4的矩阵。

    图示中扩展的0行0列的元素位置用红色的坐标标示,红色斜箭头把需要用到扩展A矩阵的虚拟像素点位置都标了出来。

    实验结果:

    原图像:

    放大四倍后的图像:


     

    代码实现:

    主程序代码:

    clear ; close all; clc
    image = imread('bird.png');  %载入图像的值
    r = image(:,:,1);     %由于真彩图是红蓝绿三个像素的叠加
    g = image(:,:,2);     %这里把r,g,b分离出来单独调用函数计算
    b = image(:,:,3);     %计算完成后再进行组装
    %这里需要手动设置放大的倍数
    w = 4;   %w放大的是竖直方向
    l = 4;   %l放大的是水平方向
    
    r = extenRGB(r,w,l);  %调用函数计算放大后的r值
    g = extenRGB(g,w,l);  %调用函数计算放大后的g值
    b = extenRGB(b,w,l);  %调用函数计算放大后的b值
    %下面把计算完成后的rgb再组装起来
    outRGB(:,:,1) = r;
    outRGB(:,:,2) = g; 
    outRGB(:,:,3) = b;
    
    outRGB = uint8(outRGB);%格式转换,否则无法显示
    
    imshow(outRGB);        %显示放大后的图像
     
     

     主程序调用的函数:

    %像素放大计算函数 extenRGB()
    function Output = extenRGB(A,w,l)
    
    % A矩阵分别代表r,g,b矩阵
    [m,n] = size(A);      %读取A的行和列 
    A = [A;zeros(1,n)];   %在A的最后一行加入两行0
    A = [A zeros(m+1,1)]; %在A的最后一列加入两列0
    %这样A就变成(m+1)x(n+1)的矩阵,这是为了解决索引A矩阵时的边界溢出问题
    
    ini_u = (m-1)/(w*m-1); %步长比,如果把原来的一步A(1,1)到A(2,1)看做1,那么计算放大后的
    ini_v = (n-1)/(l*n-1); %图像B(2,1)相当于计算A(1+ini_u,1),即每步加ini_u
             
    
    Output = zeros(w*m,l*n);            %初始化输出矩阵
    for j = 1:l*n;                      %左边两个语句的功能是:z_u,z_v向左取整,u,v取小数,原理如下
        z_v = floor((j-1)*ini_v+1);     %比如A为3x3的矩阵,要放大为Output是4x4大小,即放大了4/3倍, 
          v = (j-1)*ini_v+1 - z_v;      %新的一步的距离相当于原来的(3-1)/(4-1)=0.66667
        for i = 1:w*m;                  %Output(1,1) = A(1,1)       %(1-1)*0.66667+1=1
            z_u = floor((i-1)*ini_u+1); %Output(1,2) = A(1,1.66667) %(2-1)*0.66667+1=1.66667
              u = (i-1)*ini_u+1 - z_u;  %Output(1,3) = A(1,2.33334) %(3-1)*0.66667+1=2.33334
                                        %Output(1,4) = A(1,3.00001) %(4-1)*0.66667+1=3.00001
                                        
                                       
    
    %===================下面是双线性插值的代码实现================================   
            Output(i,j) = (1 - u)*(1 - v)*A(z_u,     z_v    ) + ...
                          (1 - u)* v     *A(z_u,     z_v + 1) + ...
                           u     *(1 - v)*A(z_u + 1, z_v    ) + ...
                           u     * v     *A(z_u + 1, z_v + 1);
        end
    end
           
  • 相关阅读:
    HDU3336 Count the string —— KMP next数组
    CodeForces
    51Nod 1627 瞬间移动 —— 组合数学
    51Nod 1158 全是1的最大子矩阵 —— 预处理 + 暴力枚举 or 单调栈
    51Nod 1225 余数之和 —— 分区枚举
    51Nod 1084 矩阵取数问题 V2 —— 最小费用最大流 or 多线程DP
    51Nod 机器人走方格 V3 —— 卡特兰数、Lucas定理
    51Nod XOR key —— 区间最大异或值 可持久化字典树
    HDU4825 Xor Sum —— Trie树
    51Nod 1515 明辨是非 —— 并查集 + 启发式合并
  • 原文地址:https://www.cnblogs.com/bigpo/p/4126806.html
Copyright © 2011-2022 走看看