双线性插值算法详解并用matlab实现

参考:
https://blog.csdn.net/huang1024rui/article/details/46545329
数字图像处理

双线性插值算法

介绍

双线性插值法又称为二次线性插值法。在传统的插值算法中,它的插值效果比nearest插值法要好的多,但是速度上也必然会慢很多,比bicubic(二次立方法)效果要差, 但速度上要优于bicubic。
它主要思想就是利用某像素点周围的4个像素来计算出浮点坐标像素值。
举个例子,假设我们现在需要获得坐标为(6.6,4)的像素值T,该坐标离(6,4)和(7,4)这2个像素点最近。设(6,4)像素值为T_64,(7,4)像素值为T_74,直观地表现在图上就是:
这里写图片描述
按照距离越近混合的比例越大的原则可以得到:
这里写图片描述
其中u,v分别表示浮点坐标距离(6,4)和(7,4)这2个像素点的距离。此时就使用了一次线性插值得到了(6.6,4)的像素值。
通过上面一个简短的例子,我们知道了如何使用2个邻点来计算出坐标分量有一个为小数的情况,那么如果我们坐标分量2个都为小数呢,该如何插值?双线性插值通过多次线性插值就解决了这样的问题。
如图:
这里写图片描述
上图的求解思路用语言表述就是:先用一次线性插值分别求出f1、f2的像素值,然后再对f1、f2利用一次线性插值得到f的像素值。这就是双线性插值的原理。
用公式来展示一下求解的过程:
先求出2个红点的像素值,然后根据这2个像素值做一次线性插值得到目标点f的像素值。
这里写图片描述
这里写图片描述
这里写图片描述

伪代码

输入:
Img:原始图像
zmf:为缩放因子
输出:
new_img:输出图像
step1:求出原图像Img的大小,记为height×width×channel,接着生成大小为(zmf×height)×(zmf×width)×channel的全0矩阵new_img;
step2 :把Img边界扩展一圈得到IT,大小为(height+2)×(width+2)×channel;
step3 :对于缩放后的新图new_img中某像素位置(zi,zj)映射回(zi/zmf,zj/zmf)原图Img中得到(x,y),由于(x,y)不一定为整数,故向下取整得到(i,j),其中x = i+u,y = j+v,且u,v[0,1)为小数部分;
step4 :根据下式进行双线性插值计算f(zi,zj)的值,也就是其对应的像素值。
f(zi,zj)=f(x,y)=(1-u)×(1-v)×f(i,j)+(1-u)×v×f(i,j+1)+u×(1-v)×f(i+1,j)+u×v×f(i+1,j+1);
其中f(zi,zj)表示新图(zi,zj)处的像素值,f(x,y)表示新图(zi,zj)对应在原图中的位置(x,y)处的像素值;
step5:重复3-4,直至将矩阵new_img

2 matlab代码

2.1 主程序代码

clear;
close all;
clc;
img = imread('image/my_gray_512.jpg');
[ori,img_new] = imblizoom(img,0.5);
% [ori,img_new] = imblizoom('image/my_gray_512.jpg',0.5);
img_show(ori,img_new);

2.2 核心代码

function [ original,new_img ] = imblizoom( original,zmf )
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
%-----------------双线性插值法缩放矩阵或图像---------------------
% Input:
%       original:原始图像图像文件名或矩阵(整数值(0~255))
%       zmf:缩放因子,即缩放的倍数
% Output:
%       original: 原始图像矩阵
%       new_img:  缩放后的图像矩阵 
% Usage:
%       [original,new_img] = imblizoom('ImageFileName',zmf)
%       对图像I进行zmf倍的缩放
%    Or:
%       [original,new_img] = imblizoom(I,zmf)
%       对矩阵I进行zmf倍的缩放
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % 
%% Step1 对数据进行预处理
if ~exist('original','var') || isempty(original)
    error('输入图像 I未定义或为空!');
end
if ~exist('zmf','var') || isempty(zmf) || numel(zmf) ~= 1
     error('位移矢量 zmf未定义或为空或 zmf中的元素超过2!');
end
if isstr(original)
    [original,M] = imread(original);
end
if zmf <= 0
     error('缩放倍数 zmf的值应该大于0!');
end
%% Step2 通过原始图像和缩放因子得到新图像的大小,并创建新图像
[height,width,channel] = size(original);
new_height = round(height*zmf); % 计算缩放后的图像高度,最近取整
new_width = round(width*zmf); % 计算缩放后的图像宽度,最近取整
new_img = zeros(new_height,new_width,channel); % 创建新图像

%% Step3 扩展原始矩阵I边缘
img_scale = zeros(height+2,width+2,channel); % 为了边界点考虑的
img_scale(2:height+1,2:width+1,:) = original;
% % ========================================================
%  为4周各添加的一行或列做值的初始化
% % ========================================================= 
% 为扩展而来的各边赋值
img_scale(1,2:width+1,:) = original(1,:,:);
img_scale(height+2,2:width+1,:) = original(height,:,:);
img_scale(2:height+1,1,:) = original(:,1,:);
img_scale(2:height+1,width+2,:) = original(:,width,:);
% 用原图的4个顶点为扩展而来的4个顶点赋值
img_scale(1,1,:) = original(1,1,:);
img_scale(1,width+2,:) = original(1,width,:);
img_scale(height+2,1,:) = original(height,1,:);
img_scale(height+2,width+2,:) = original(height,width,:);
%% ============================================================
% Step4 由新图像的某个像素(zi,zj)映射到原始图像(ii,jj)处, 并在原始
% 图像的(ii,jj)位置利用其周围4个像素点进行插值得到(ii,jj)处的像素值
% % ====================================================================
for zj = 1:new_width         % 对图像进行按列逐元素扫描
    for zi = 1:new_height
        % (zi,zj)表示在新图中的坐标,(ii,jj)表示在原图中的坐标
        % 注意:(ii,jj)不一定是整数
        ii = (zi-1)/zmf; jj = (zj-1)/zmf;
        i = floor(ii); j = floor(jj); % 向下取整得到在原图中坐标的整数部分
        u = ii - i; v = jj - j;       % 得到在原图中坐标的小数部分
        i = i + 1; j = j + 1;
        new_img(zi,zj,:) = (1-u)*(1-v)*img_scale(i,j,:) + u*(1-v)*img_scale(i,j+1,:)...
                    + (1-u)*v*img_scale(i+1,j,:) + u*v*img_scale(i+1,j+1,:);
    end
end
new_img = uint8(new_img);

end  

2.3 用于显示的代码

function img_show(original,new_img)
[height,width,channel] = size(original);
figure;imshow(original);
axis on
title(['原图像(大小: ',num2str(height),'*',num2str(width),'*',num2str(channel),')']);
[new_height,new_width,~] =size(new_img); 
figure;imshow(new_img);
axis on
title(['缩放后的图像(大小: ',num2str(new_height),'*',num2str(new_width),'*',num2str(channel)',')']);
end

猜你喜欢

转载自blog.csdn.net/chaolei3/article/details/80402523