一、实验目的
1、熟悉并掌握MATLAB工具的使用;
2、实现图像的读取、显示、存储、放大、缩小及旋转操作;
3、掌握常用的插值方法,并了解其优缺点。
二、实验环境
Matlab
三、实验内容
(一)、题目
1、读入一幅RGB图像,变换为灰度图像和二值图像,并在同一个窗口内分别显示RGB图像和灰度图像,注上文字标题,并将结果以文件形式存到磁盘上。
2、对图像执行放大、缩小及旋转操作,分别采用最近邻插值、双线性插值及双三次插值方法实现,要求根据算法自己编写代码实现,并分析三种方法的优缺点。
(二)、相关知识
1、图像分类
(1)彩色图像:由彩色像素构成,每个彩色像素含R、G、B三种成分。
(2)灰度图像:每一个像素灰度都介于黑和白之间的一个灰度颜色,可以有不同灰度级的图像。
(3)二值图像:只有黑白两种灰度等级的图像。
2、图像几何变换
(1)、图像放缩:沿x和y方向放大或缩小,设沿x方向放缩d1倍,沿y方向放缩d2倍,则 x=d1x0,y=d2y0。
(2)、图像旋转:指在一平面内绕某一中心旋转一定角度,旋转后图像的大小可能会发生改变。
旋转时应先将屏幕坐标系变为旋转坐标系,之后将对应点旋转对应角度,最后将旋转坐标系变回屏幕坐标系。
原图像的一点( X 0 , Y 0 )经过如下公式可以变换到旋转后的( X 3 , Y 3 )
3、三种插值法
(1)最近邻插值法
找到未知像素点相邻的4个已知像素点,然后判断哪一个像素离着未知像素点近,就让那个点同化未知像素点,赋予未知点同样的像素值。
使用目标图的坐标乘以两图的长宽比例得到原图的坐标,当然这个坐标可能会是小数,就直接四舍五入了,即根据 srcWidth/dstWidth = srcX/dstY,最后再对srcX取整,这样就得到了两个图像中坐标的对应关系,使它们具备同样的像素值即可。
(2)双线性插值法
双线性插值就是在x,y两个方向上进行了3次单线性插值。要求某点的像素值,就先在X方向上进行两次单线性插值求得R1和R2的值,然后在Y方向上进行一次单线性插值,把上面三次插值处理的式子结合起来,就得到了我们要求的点的像素值。
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)
其中i,j 为浮点坐标的整数部分,u,v为浮点坐标的小数部分。
(3)双三次插值法
插值点 (x, y) 的像素灰度值 f(x, y) 通过矩形网格中 最近的十六个采样点的加权平均 得到,而 各采样点的权重由该点到待求插值点的距离确定,此距离包括 水平和竖直 两个方向上的距离。
待求插值点 (i+u, j+v) 的灰度值 f(i+u, j+v) 将通过如下计算得到:
其中各项由向量或矩阵表示为:
插值权重核 w(·) 为:
(三)、代码
放缩的源文件amplify.m
clear;
close all;
clc;
CONST=50;
img=imread('tree.jpg');
%resize_img=[];
[srcWidth ,srcHeight,Color]=size(img);
%
% % 最近邻
% % 思想是根据 srcWidth/dstWidth = srcX/dstY,最后再对srcX取整
% % 缺点是精度不够,严重失真
%
% dstWidth=srcWidth+CONST*2;%放大加,缩小减
% dstHeight=srcHeight+CONST*2;
% %dstWidth=srcWidth-CONST*2;
% %dstHeight=srcHeight-CONST*2;
% resize_img=zeros(dstWidth,dstHeight,Color,class(img));
%
% % 像素变化公式计算公式
% for i=1:dstWidth
% for j=1:dstHeight
% for n = 1:Color
% src_i=i*(srcWidth/dstWidth);
% src_j=j*(srcHeight/dstHeight);
% resize_img(i,j,n)=img(round(src_i),round(src_j),n); % round四舍五入
% end
% end
% end
%
% figure;
% imshow(img);
% title("原图像");
% figure;
% imshow(resize_img)
% title("最近邻插值法放大图像");
% %title("最近邻插值法缩小图像");
%
%
% % 双线性内插值算法
% % 聪明的方法
% % 最近邻法中根据 srcWidth/dstWidth = srcX/dstY,可以倒退出一个srcX的坐标值,但是这个值是浮点数,
% % 这个浮点数提供了一些信息,它离它在原始图像四周的像素值的关系,根据这个关系,计算一个更接近的dstX,
% % 然后再填充目标图像
% % 公式:
% % 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)
% % i,j 为浮点坐标的整数部分; u,v为浮点坐标的小数部分
% % 优点:缩放后图像质量高
% % 缺点: 计算量大,双线性插值具有低通滤波器的性质,使高频分量受损,图像轮廓在一定程度上变模糊
%
% %dstWidth=srcWidth+CONST*2;%放大是加,缩小是减
% %dstHeight=srcHeight+CONST*2;
%
% dstWidth=srcWidth-CONST*2;
% dstHeight=srcHeight-CONST*2;
%
% resize_img=zeros(dstWidth,dstHeight,Color,class(img));
%
% % 像素变化公式计算公式
% for i=1:dstWidth-1
% for j=1:dstHeight-1
% for n = 1:Color
% src_i=i*(srcWidth/dstWidth);
% src_j=j*(srcHeight/dstHeight);
% src_ii=fix(src_i);
% src_iu=src_i - src_ii; % none fix part
% src_jj=fix(src_j);
% src_jv=src_j - src_jj;
% if src_ii == 0
% src_ii=src_ii+1;
% end
% if src_jj ==0
% src_jj=src_jj+1;
% end
% resize_img(i,j,n)=(1-src_iu)*(1-src_jv)*img(src_ii,src_jj,n)+(1-src_iu)*src_jv*img(src_ii,src_jj+1,n)+src_iu*(1-src_jv)*img(src_ii+1,src_jj,n)...
% +src_iu*src_jv*img(src_ii+1,src_jj+1,n);
% end
% end
% end
%
% figure;
% imshow(img);
% title("原图像");
% figure;
% imshow(resize_img)
% %title("双线性插值法放大图像");
% title("双线性插值法缩小图像");
% 三次卷积法
% 三次卷积法计算精度高,但计算亮大,思路是根据一个浮点坐标(i+u,j+v)周围的16个邻点,由下列公式得出目的像素值f(i+u,j+v):
%
% f(i+u,j+v) = [A] * [B] * [C]
%
% [A]=[ S(u + 1) S(u + 0) S(u - 1) S(u - 2) ]
%
% ┏ f(i-1, j-1) f(i-1, j+0) f(i-1, j+1) f(i-1, j+2) ┓
% [B]=┃ f(i+0, j-1) f(i+0, j+0) f(i+0, j+1) f(i+0, j+2) ┃
% ┃ f(i+1, j-1) f(i+1, j+0) f(i+1, j+1) f(i+1, j+2) ┃
% ┗ f(i+2, j-1) f(i+2, j+0) f(i+2, j+1) f(i+2, j+2) ┛
%
% ┏ S(v + 1) ┓
% [C]=┃ S(v + 0) ┃
% ┃ S(v - 1) ┃
% ┗ S(v - 2) ┛
%
% ┏ 1-2*Abs(x)^2+Abs(x)^3 , 0<=Abs(x)<1
% S(x)={ 4-8*Abs(x)+5*Abs(x)^2-Abs(x)^3 , 1<=Abs(x)<2
% ┗ 0 , Abs(x)>=2
% 有人说,S(x)是对 Sin(x*Pi)/x
% 的逼近(Pi是圆周率——π),通过极限计算,可以知道Sin(x*Pi)/x的范围在0~pi之间,无法理解为什么要这样设置S(x)
% 但上述求A、B、C的公式还是可以理解,根据双线性插值的思想,也就是根据浮点数在原始坐标中与邻近像素的距离远近来决定原始坐标在目的坐标中所占的比重
img=double(img);%imread读入源图像为三维,所以不能进行D=A*X*A'。必须对读取的图像转换成double类型
dstWidth=srcWidth+CONST*2;
dstHeight=srcHeight+CONST*2;
%dstWidth=srcWidth-CONST*2;
%dstHeight=srcHeight-CONST*2;
% resize_img=zeros(dstWidth,dstHeight,Color,class(img));
resize_img=zeros(dstWidth,dstHeight);
%A=[];B=[];C=[];
%
% 像素变化公式计算公式
for i=3:dstWidth-2
for j=3:dstHeight-2
% for n = 1:Color
src_i=i*(srcWidth/dstWidth);
src_j=j*(srcHeight/dstHeight);
src_ii=fix(src_i); % 整数部分
src_iu=src_i - src_ii; % 小数部分
src_jj=fix(src_j);
src_jv=src_j - src_jj;
A=[ cubic_factor(src_iu+1),cubic_factor(src_iu) ,cubic_factor(src_iu-1) ,cubic_factor(src_iu-2) ];
C=[ cubic_factor(src_jv+1), cubic_factor(src_jv), cubic_factor(src_jv-1), cubic_factor(src_jv-2) ];
B=[ img(src_ii-1,src_jj-1), img(src_ii-1,src_jj), img(src_ii-1,src_jj+1), img(src_ii-1,src_jj+2);
img(src_ii,src_jj-1) , img(src_ii,src_jj) , img(src_ii,src_jj+1) , img(src_ii,src_jj+2);
img(src_ii+1,src_jj-1), img(src_ii+1,src_jj) ,img(src_ii+1,src_jj+1), img(src_ii+1,src_jj+2);
img(src_ii+2,src_jj-1), img(src_ii+2,src_jj) ,img(src_ii+2,src_jj+1), img(src_ii+2,src_jj+2) ];
% B=[ img(src_ii-1,src_jj-1,n) img(src_ii-1,src_jj,n) img(src_ii-1,src_jj+1,n) img(src_ii-1,src_jj+2,n);
% img(src_ii,src_jj-1,n) img(src_ii,src_jj,n) img(src_ii,src_jj+1,n) img(src_ii,src_jj+2,n);
% img(src_ii+1,src_jj-1,n) img(src_ii+1,src_jj,n) img(src_ii+1,src_jj+1,n) img(src_ii+1,src_jj+2,n);
% img(src_ii+2,src_jj-1,n) img(src_ii+2,src_jj,n) img(src_ii+2,src_jj+1,n) img(src_ii+2,src_jj+2,n) ];
%
resize_img(i,j)=A*B*C';
% end
end
end
figure;
imshow(uint8(img));
title("原图像");
figure;
imshow(resize_img,[]);
title("双三次插值法放大图像");
%title("双三次插值法缩小图像");
旋转的源文件包括rotate.m和cubic_factor.m(旋转中要用到的一个函数)
cubic_factor.m
% 距离系数计算公式---旋转中会用到
% ┏ 1-2*Abs(x)^2+Abs(x)^3 , 0<=Abs(x)<1
% S(x)={ 4-8*Abs(x)+5*Abs(x)^2-Abs(x)^3 , 1<=Abs(x)<2
% ┗ 0 , Abs(x)>=2
function S=cubic_factor(x)
if 0<=abs(x)<1
S=1-2.*abs(x).^2+abs(x).^3;
elseif 1<=abs(x)<2
S=4-8.*abs(x)+5.*abs(x).^2-abs(x).^3;
else
S=0;
end
end
rotate.m
clear;
img=imread('tree.jpg');
img=double(img);
[srcHeight,srcWidth,Color]=size(img);
angle=pi/6; %逆时针旋转的角度
dstWidth=srcWidth*cos(angle)+srcHeight*sin(angle); %新图像的高width
dstHeight=srcWidth*sin(angle)+srcHeight*cos(angle); %新图像的宽heighth
dstHeight=ceil(dstHeight); %取整
dstWidth=ceil(dstWidth);
u0=srcWidth*sin(angle); %平移量
T=[cos(angle),sin(angle);-sin(angle),cos(angle)]; %变换矩阵
Imgnew1=zeros(dstWidth,dstHeight,Color,class(img));
Imgnew2=zeros(dstWidth,dstHeight,Color,class(img));
Imgnew3=zeros(dstWidth,dstHeight,Color,class(img));
for u=1:dstWidth %u和v是新图像坐标,变换到原图像坐标x和y中。
for v=1:dstHeight
for n=1:Color
tem=T*([u;v]-[u0;0]);
x=tem(1);
y=tem(2);
if x>=1 & x<=srcHeight & y>=1 & y<=srcWidth %若变换出的x和y在原图像范围内
x_low=floor(x);
x_up=ceil(x);
y_low=floor(y);
y_up=ceil(y);
if (x-x_low)<=(x_up-x) %采用最近点法,选取距离最近点的像素赋给新图像
x=x_low;
else
x=x_up;
end
if (y-y_low)<=(y_up-y)
y=y_low;
else
y=y_up;
end
p1=img(x_low,y_low,n); %双线性插值,p1到p4是(x,y)周围的四个点
p2=img(x_up,y_low,n);
p3=img(x_low,y_low,n);
p4=img(x_up,y_up,n);
s=x-x_low;
t=y-y_low;
Imgnew1(u,v,n)=img(x,y,n);
Imgnew2(u,v,n)=(1-s)*(1-t)*p1+(1-s)*t*p3+(1-t)*s*p2+s*t*p4;
end
if x>=2 & x<=srcHeight-2 & y>=2 & y<=srcWidth-2 %若变换出的x和y在原图像范围内
x_1=floor(x)-1;
x_2=floor(x);
x_3=floor(x)+1;
x_4=floor(x)+2;
y_1=floor(y)-1;
y_2=floor(y);
y_3=floor(y)+1;
y_4=floor(y)+2;
A=[cubic_factor(1+x-x_2),cubic_factor(x-x_2),cubic_factor(1-(x-x_2)),cubic_factor(2-(x-x_2))];
C=[cubic_factor(1+y-y_2),cubic_factor(y-y_2),cubic_factor(1-(y-y_2)),cubic_factor(2-(y-y_2))];
B=[ img(x_1,y_1,n),img(x_1,y_2,n),img(x_1,y_3,n),img(x_1,y_4,n);
img(x_2,y_1,n),img(x_2,y_2,n),img(x_2,y_3,n),img(x_2,y_4,n);
img(x_3,y_1,n),img(x_3,y_2,n),img(x_3,y_3,n),img(x_3,y_4,n);
img(x_4,y_1,n),img(x_4,y_2,n),img(x_4,y_3,n),img(x_4,y_4,n)];
% B=[ img(x_1,y_1),img(x_1,y_2),img(x_1,y_3),img(x_1,y_4);
% img(x_2,y_1),img(x_2,y_2),img(x_2,y_3),img(x_2,y_4);
% img(x_3,y_1),img(x_3,y_2,n),img(x_3,y_3),img(x_3,y_4);
% img(x_4,y_1),img(x_4,y_2),img(x_4,y_3),img(x_4,y_4)];
Imgnew3(u,v,n)=A*B*C';
end
end
end
end
subplot(2,2,1);
%figure;
imshow(uint8(img)),title('原图'); %imshow()显示图像时对double型是认为在0~1范围内,即大于1时都是显示为白色,而imshow显示uint8型时是0~255范围。所以对double类型的图像显示的时,归一化到0~1之间或将double类型的0~255数据转为uint8类型。
subplot(2,2,2);
%figure;
imshow(uint8(Imgnew1)),title('最近邻插值法');
subplot(2,2,3);
%figure;
imshow(Imgnew2/255),title('双线性插值法');
subplot(2,2,4);
%figure;
imshow(Imgnew3,[]),title('双三次插值法');
(四)、实验结果
1、读入一幅RGB图像,变换为灰度图像和二值图像,并在同一个窗口内分别显示RGB图像和灰度图像,注上文字标题,并将结果以文件形式存到磁盘上。(图1)
图1
2、最近邻插值法放缩图片
图2 最近邻插值法放大图片
图3 最近邻插值法缩小图片
2、双线性插值法放缩图片
图4 双线性插值法放大图片
图5 双线性插值法缩小图片
3、双三次插值法放缩图片
图6 双三次插值法放大图片
图7 双三次插值法缩小图片
5、旋转图像
图8 旋转图像
四、总结
1、三种插值法优缺点分析
(1)、最近邻插值法
优点:计算量很小,算法也简单,因此运算速度较快。
缺点:仅使用离待测采样点最近的像素的灰度值作为该采样点的灰度值,而没考虑其他相邻像素点的影响,因而重新采样后灰度值有明显的不连续性,图像质量损失较大,精度不够,严重失真,会产生明显的马赛克和锯齿现象。
(2)、双线性插值法:
优点:效果要好于最近邻插值,但缩放后图像质量高,基本克服了最近邻插值灰度值不连续的特点,因为它考虑了待测采样点周围四个直接邻点对该采样点的相关性影响。
缺点:相较于最近邻插值法计算量稍大一些,算法复杂些,程序运行时间也稍长些,此方法仅考虑待测样点周围四个直接邻点灰度值的影响, 而未考虑到各邻点间灰度值变化率的影响, 因此具有低通滤波器的性质, 从而导致缩放后图像的高频分量受到损失, 图像边缘在一定程度上变得较为模糊。用此方法缩放后的输出图像与输入图像相比, 仍然存在由于插值函数设计考虑不周而产生的图像质量受损与计算精度不高的问题。
(4)、双三次插值法
优点:立方卷积插值不仅考虑到周围四个直接相邻像素点灰度值的影响,还考虑到它们灰度值变化率的影响。因此克服了前两种方法的不足之处,能够产生比双线性插值更为平滑的边缘,计算精度很高,处理后的图像像质损失最少,效果是最佳的。
缺点:计算量最大,算法最为复杂。