一、实验名称
图像的几何变换
二、实验目的
1.熟悉MATLAB软件的使用。
2.掌握图像几何变换的原理及数学运算。
3.于MATLAB环境下编程实现对图片不同的几何变换。
三、实验内容
1.将图像绕图像中心顺时针旋转30度,旋转之后的图像尺寸保持为原图像的尺寸。
2.将原图像放大2倍
3.得到该图像的水平镜像图片
4.得到该图像的垂直错切图像
四、实验仪器与设备
Win10 64位电脑
MATLAB2017a
五、实验原理
图像旋转
所谓图像的旋转无非就是将图像中的所有像素整体旋转,即本质就是对每个像素进行旋转。对一个像素进行旋转,可以看出向量的旋转,利用向量旋转公式,得到旋转矩阵。当然,旋转之后,虽然图像的大小的不会变化的,但是便于我们坐标的选取,我们会计算出一个新的坐标系,所以这里两个过程,两个坐标系中坐标的相互转换,得到两个转换矩阵,这样一来,对于一个像素点,只需要对它进行相应的矩阵操作即可得到旋转之后的点坐标。当然,对于一些得到的映射点不是整数的情况下,我们可以按照要求进行取整或者插值操作即可。
图像的放大
图像的放大收缩,这里拿放大举例,就是拿更多的像素去表达原来的图像,但是图像整体不变,通俗一点就是,原来一个特征点,需要10个像素表示,放大就是现在我们用20个或者更多来表示这个特征点,这里填值的方法有很多,邻值插值,线性插值等。
图像的水平镜像
对像素矩阵进行水平转置即可。
图像的垂直错切
对垂直方向进行线性变换即可。
六、实验过程及代码
图像旋转
function [newimage]=rotate(img,degree)
%获取图片信息 注意三通道获取完 即定义三个变量
[m,n,dep]=size(img);
%计算出旋转之后,形成一个大矩形的长宽 可以看效果图
rm=round(m*abs(cosd(degree))+n*abs(sind(degree)));
rn=round(m*abs(sind(degree))+n*abs(cosd(degree)));
%定义一个新矩阵,三通道的,存储新图片的信息
newimage=zeros(rm,rn,dep);
%坐标变换 分三步
m1=[1,0,0;0,1,0;-0.5*rm,-0.5*rn,1];
m2=[cosd(degree),sind(degree),0;-sind(degree),cosd(degree),0;0,0,1];
m3=[1,0,0;0,1,0;0.5*m,0.5*n,1];
%利用循环,对每一个像素点进行变换
for i=1:rm
for j=1:rn
tem=[i j 1];
tem=tem*m1*m2*m3;
x=tem(1,1);
y=tem(1,2);
x=round(x);
y=round(y);
if(x>0&&x<=m)&&(y>0&&y<=n)
newimage(i,j,:)=img(x,y,:);
end
end
end
end
主函数
t=imread('a1.jpg');
t1=rotate(t,30);
subplot(1,2,1),imshow(uint8(t)),title('原图');
subplot(1,2,2),imshow(uint8(t1)),title('旋转30度后');
图像放大2倍
t=imread('a1.jpg');
[m,n,dep]=size(t);
%自定义长 宽
rm=1400;
rn=822;
%构造新矩阵 存储收缩后的图片
rt=zeros(rm,rn,dep);
for i=1:rm
for j=1:rn
%坐标转换
x=i*m/rm;
y=j*n/rn;
%求出偏移量
u=x-floor(x);
v=y-floor(y);
%边缘处理
if x<1
x=1;
end
if y<1
y=1;
end
%双线性插值
rt(i,j,:)=t(floor(x),floor(y),:)*(1-u)*(1-v)+t(floor(x),ceil(y),:)*(1-u)*v+t(ceil(x),ceil(y),:)*(u)*(1-v)+t(ceil(x),ceil(y),:)*u*v;
end
end
imshow(t);title('原图');
figure;imshow(uint8(rt));title('加倍后的图片');
图像的水平镜像
t=imread('a1.jpg');
[m,n,z]=size(t);
rt=t;
for i=1:m
for j=1:n
rt(i,j,:)=t(i,n-j+1,:);
end
end
subplot(1,2,1),imshow(t),title('原图')
subplot(1,2,2),imshow(rt),title('水平镜像')
垂直方向错切:
t=imread('a1.jpg');
[m,n,z]=size(t);
rt=zeros(m+n,n,z);
for i=1:m
for j=1:n
rt(i+j,j,:)=t(i,j,:);
end
end
subplot(1,2,1),imshow(t),title('原图')
subplot(1,2,2),imshow(uint8(rt)),title('垂直错切')
七、实验结果与分析
图 1图像顺时针旋转30度
图 2图像放大2倍
图 3图像的水平镜像
图 4垂直错切
实验结果分析
1、图像的旋转,其原理知识就是数学中向量的旋转,在确定好旋转角度后,计算出旋转后图片的大小,然后进行坐标转换,再向量旋转,最后在逆坐标转换即可。
2、图像的放大与收缩,放大时,利用插值法填充空白像素点,这里可以用线性插值、双线性插值等方法;收缩时,这时我们就需要考虑舍弃一些不必要的像素点,尽可能多的保持原图像的完整性
3、图像的水平镜像,实质是图像像素矩阵的水平逆转
4、图像的错切,本质就是对原有坐标单方向进行函数变换
八、实验总结及心得体会
通过这次实验,自己学会了几种图像变换的方法:图像的放大、收缩、水平镜像、错切等,在进行放大的时候,接触到了插值法,有线性插值、双线性插值等,好多的原理知识都需要一定的高数知识,基础还是有点不扎实啊。在图形的放大时,在m、n两个变量搞混,其实也就是坐标轴建立处理差错。
附:图像收缩原理验证
定义
图像的收缩通俗一点就是我们常说的放大、缩写,在数字图像处理中,就是指像素的增加与减少。比如22的图像,有4个像素,放大两倍,那么就有44=16个像素。
那么怎么对图像进行收缩呢?
这里拿放大举例:放大二倍的图像就是图片的width、height都扩大为原来的两倍,也就是像素总数为原来的四倍。那么怎么在保证图片内容不变的情况下增加像素呢?这个也简单,举个例子,比如一个红色的圆原来是4个像素(4个相同的像素)来表示,二倍后的圆那么就是用16个像素(也是相同的)来表示,通俗来说,就是用更多的像素来表示同一种图形。原来需要4个,那么现在就需要16个。
当然,随机图像上面一个片段是由多个不同的像素表示,那么怎么增加像素个数,同时图形还不变化呢?这个就要用插值来计算了。举个例子,一段上坡路,现在要把它增长(在中间增长),那么肯定是在中间填入和两侧差不多的高度,使得原来的坡面同样也是连续的,保持原来的连续性。所以插值的目的是:通过填充像素,保持原图像的一致,和高数上变化后保持连续性相似。下图是插值法的说明:
该算法的伪代码:
我的理解:
比如原图的大小为300400,放大两倍,变成600800;原图上(1,2)的点在放大图的点为(2,4)。这个应该比较好理解。
编程的时候,我们是先构造出放大图像的空矩阵,再依次填值。这就要求我们要能够在已知知道放大图像中的一个点坐标,计算出原图的坐标,然后把原图的坐标赋值给新点。
这里运用比例思想,比如x轴上,放大图为2,它占总长600的2/600,那么原图的x坐标同样也占x轴的2/600,计算出来为1.
假设(x1,y1)为放大图像的值,(x0,y0)为原图的值,m,n为原图的横纵长度,rm,rn为放大图的横纵长度。
有以下关系:
x1/rm=x0/m y1/rn=y0/n
可以推导出:
x0=x1m/rm y0=y1n/rn**
最后再利用双线性插值法插值即可。
这里代码是(其实就是先分别求出周围4个点,利用不同的取值函数就行,再计算):
rt(i,j,:)=t(floor(x),floor(y),:)*(1-u)*(1-v)+t(floor(x),ceil(y),:)*(1-u)*v+t(ceil(x),ceil(y),:)*(u)*(1-v)+t(ceil(x),ceil(y),:)*u*v;