最近数字图像处理的实验课,老师让我们实现对图像进行双线性(bilinear)插值缩放,以下是原理和代码。
一、双线性插值缩放
1、图像几何变换的一般流程:
①确定变换后新图像的大小
②对新图像的每一个像素,确定其在旧图像坐标中的对应位置(逆变换)
③确定旧图像中该位置的像素值(nearest,bilinear,bicubic,...)
④将确定的像素值作为新图像的像素值
由于该方法在水平、垂直两个方向上分别进行线性插值来得到最终结果,故称之为双线性插值法
总结:
二、不用 imresize , 利用循环自行编程将Lena图像以bilinear方式缩放p倍并显示。p是任一大于0的实数
% Step1导入图像
img=imread('Lena.bmp');%导入lena图像
p=input('请输入缩放倍数(大于0的任意正实数):');
% Step2 通过原始图像和缩放因子得到新图像的大小,并创建新图像
[H,W,D]=size(img);%把二维矩阵当作第三维为D的三维矩阵。H是行数 W是列数
new_height=round(H*p);%算出缩放后的图像高度,最近取整
new_width=round(W*p);%算出缩放后的图像宽度,最近取整
new_img=zeros(new_height,new_width,D);%缩放之后新的矩阵大小
% Step3 扩展原始图像矩阵的边缘
img_scale=zeros(H+2,W+2,D);%将输入图像上下左右各加一列(行),这一步为了后面边缘像素的插值操作% 为扩展而来的各边赋值。为解决边界溢出问题,扩大原图像的四边边缘,将原矩形赋值给新的矩形
img_scale(2:H+1, 2:W+1, :)=img;% 为四周各添加的一行或列做值的初始化
img_scale(1, 2:W+1, :)=img(1,:,:);%矩形上边界(行)
img_scale(H+2, 2:W+1,:)=img(H,:,:);%矩形下边界,从第二列,到W+1列,长度W
img_scale(2:H+1,1,:)=img(:,1,:);%矩形左边界(列),从第二行,到H+1行,长度H
img_scale(2:H+1,W+2,:)=img(:,W,:);%矩形右边界(列),从第二行,到H+1行,长度H% 用原图的4个顶点为扩展而来的4个顶点赋值
img_scale(1,1,:)=img(1,1,:);
img_scale(1,W+2,:)=img(1,W,:);
img_scale(H+2,1,:)=img(H,1,:);
img_scale(H+2,W+2,:)=img(H,W,:);
%step4 新图的某个像素(i j)映射到原图(ox oy)上,并双线性插值算出新图该矩阵的灰度值
for j=1:new_heightfor i=1:new_widthox=(i-1)/p; oy=(j-1)/p;%用新的大图映射到小图的位置上x=floor(ox); y=floor(oy);% 原图坐标(ox,oy)不一定是整数,所以向下取整得到整数x,y%接下来带入公式即可u=ox-x;% 得到在原图中坐标的小数部分v=oy-y;x=x+1; y=y+1; %因为img_scale中多加了一行一列%这个是公式,可以在书上找到new_img(i,j,:)=u*v*img_scale(x+1,y+1,:)+v*(1-u)*img_scale(x,y+1,:)+(1-v)*u*img_scale(x+1,y,:)+(1-u)*(1-v)*img_scale(x,y,:);end
endnew_img = uint8(new_img);
%输出原图和更改后的图
figure;imshow(img);
axis on %恢复对坐标轴的一切设置
title(['原图像(大小: ',num2str(H),'X',num2str(W),'X',num2str(D),')']);%num2str:将数字转换为字符数组
figure;imshow(new_img);
axis on
title(['缩放后的图像(大小: ',num2str(new_height),'X',num2str(new_width),'X',num2str(D),')']);
效果图:
三、不用 imresize , 修改上述代码,编程将将任一灰度图像以bilinear方式行缩放p倍,列缩放q倍。p、q是任一大于0的实数
image_2 = input('请输入缩放图像名字(例如:Lena.bmp):','s');%导入图片的路径
%输入的数目必须是2的整数倍
p= input('请输入行缩放倍数(大于0的任意正实数):');
q= input('请输入列缩放倍数(大于0的任意正实数):');
image_original= imread(image_2);
% Step2 通过原始图像和缩放因子得到新图像的大小,并创建新图像
[H,W,D]=size(image_original);%算出图像的大小,返回 image_original 的查询维度的长度。
new_height=round(H*p);%算出缩放后的图像高度,最近取整
new_width=round(W*q);%算出缩放后的图像宽度,最近取整
new_image2=zeros(new_height,new_width,D);%缩放之后新的矩阵大小
% 为扩展而来的各边赋值
img_scale(2:H+1, 2:W+1, :)=image_original;
img_scale(1, 2:W+1, :)=image_original(1,:,:);
img_scale(H+2, 2:W+1,:)=image_original(H,:,:);
img_scale(2:H+1,1,:)=image_original(:,1,:);
img_scale(2:H+1,W+2,:)=image_original(:,W,:);
% 用原图的4个顶点为扩展而来的4个顶点赋值
img_scale(1,1,:)=image_original(1,1,:);
img_scale(1,W+2,:)=image_original(1,W,:);
img_scale(H+2,1,:)=image_original(H,1,:);
img_scale(H+2,W+2,:)=image_original(H,W,:);
%step4 新图的某个像素(i j)映射到原图(ox oy)上,并双线性插值算出新图该矩阵的灰度
for j=1:new_heightfor i=1:new_widthox=(i-1)/p; oy=(j-1)/q;%用新的大图映射到小图的位置上x=floor(ox); y=floor(oy);% 原图坐标(ox,oy)不一定是整数,所以向下取整得到整数x,y%接下来带入公式即可u=ox-x;% 得到在原图中坐标的小数部分v=oy-y;x=x+1; y=y+1; %因为img_scale中多加了一行一列new_image2(i,j,:)=u*v*img_scale(x+1,y+1,:)+v*(1-u)*img_scale(x,y+1,:)+(1-v)*u*img_scale(x+1,y,:)+(1-u)*(1-v)*img_scale(x,y,:);end
endnew_image2 = uint8(new_image2);%输出原图和更改后的图
figure;imshow(image_original);
axis on %恢复对坐标轴的一切设置
title(['原图像(大小: ',num2str(H),'X',num2str(W),'X',num2str(D),')']);%num2str:将数字转换为字符数组
figure;imshow(new_image2);
axis on
title(['缩放后的图像(大小: ',num2str(new_height),'X',num2str(new_width),'X',num2str(D),')']);
要在command window里面根据提示:输入缩放图像名字,行、列缩放倍数
例如我输入的是Lena.bmp,2 ,2
效果图:
如果有错误的话,欢迎纠正