一. 设计一个程序,对一幅灰度图像的实现如下几何变换,1)放大为原图1.5倍;2)绕中心旋转30度(CW);3)采用偏移量插值实现一个透视变换.灰度差值用最近邻插值和双线性插值。
1.放大为原图的1.5倍:
(1) 最近邻插值法:
原理:输出图像像素的灰度值等于离它所映射到的位置最近的输入像素的灰度值。
具体实现代码:
编写图像缩放的函数myresize.m :
function myresize( I , d )
[M,N]=size(I);
I1=uint8(zeros(floor(M*d),floor(N*d)));
for i=2:floor(M*d)
for j=2:floor(N*d)
x=floor(i/d); y=floor(j/d);
if((x
Command窗口中输入:
I=imread('lena3.jpg')
myresize(I,1.5)
处理效果:
处理前256×256
处理后384×384
(2)双线性插值法:
原理:对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为 (i+u,j+v),其中i,j为非负整数,u,v为[0,1]区间的浮点数,则这个像素的值 f(i+u,j+v)可由原图像中的坐标为(i,j),(i+1,j),(i,j+1),(i+1,j+1)所对应的周围四个像素的值决定。
具体实现:clear,clc
I=imread('lena3.jpg');
[M,N]=size(I);
d=1.5;
I1=uint8(zeros(floor(M*d),floor(N*d)));
M1=floor(M*d); N1=floor(N*d);
for i=2:M1-1
for j=2:N1-1
x=i/d; a=floor(x); u=x-a;
y=j/d; b=floor(y); v=y-b;
%a、b为整数部分,u、v为小数部分I1(i,j)=(1-u)*(1-v)*I(a,b)+(1-u)*v*I(a,b+1)
+u*(1-v)*I(a+1,b)+u*v*I(a+1,b+1);
end
end
%处理四周边缘的点,采用线性插值法
I1(1,1)=I(1,1); I1(1,N1)=I(1,N);
I1(M1,1)=I(M,1); I1(M1,N1)=I(M,N);
for j=2:N1-1
y=j/d; b=floor(y); v=y-b;
I1(1,j)=(1-v)*I(1,b)+v*I(1,b+1);
I1(M1,j)=(1-v)*I(M,b)+v*I(M,b+1);
end
for i=2:M1-1
x=i/d; a=floor(x); u=x-a;
I1(i,1)=(1-u)*I(a,1)+u*I(a+1,1);
I1(i,N1)=(1-u)*I(a,N)+v*I(a+1,N);
end
figure;imshow(I);
figure;imshow(I1);
可以看出基本上还是吻合的。但进一步研究发现,自己所写的程序存在不足:对于
256×256的图片,最多只能放大到原图的2倍,当高于2倍时,a、b的值仍有可能取
到0,算法需要进一步的改进。可以选择不处理边缘的值,将边缘的值均置为0,此时
可以实现放大的倍数不受限制,并且代码简单,但此方法的处理后图像的边缘无法获得。
优化后代码如下:clear,clc
I=imread('lena3.jpg');
[M,N]=size(I);
d=1.5;
I1=uint8(zeros(floor(M*d),floor(N*d)));
for i=1:floor(M*d)
for j=1:floor(N*d)
x=i/d; a=floor(x); u=x-a;
y=j/d; b=floor(y); v=y-b;
if((a>0)&&(b>0)&&(a
处理效果:
处理前256×256:
处理后384×384:
2.图像绕中心旋转30度(CW):
(1)最近邻插值法:
原理:将平移变换和旋转变换组合起来,以产生围绕任一点(x0,y0)旋转:先将图像进行平移,从而使位置(x0,y0)成为原点,然后,旋转角度,再平移其原点。
图像以图像中心为中心点的旋转公式(逆时针):
x1=(y0-N/2)sin(a)+(x0-M/2)cos(a)+M/2;
y1=(y0-N/2)cos(a)-(x0-M/2)sin(a)+N/2;
其中,(x0,y0)为原图上的点,(x1,y1)为变换后的点,a为旋转的角度。
具体实现:
clear,clc
I=imread('lena4.jpg'); %原图为128×128
[M,N]=size(I);
ang=30;
I1=I;
for i=1:M
for j=1:N
x=floor((i-M/2)*cos(ang*pi/180)+(j-N/2)*sin(ang*pi/180)+0.5+M/2);
y=floor((j-N/2)*cos(ang*pi/180)-(i-M/2)*sin(ang*pi/180)+0.5
+N/2);
if((x0)&(y>0))
I1(i,j)=I(x,y);
else
I1(i,j)=0; %无映射及边缘处灰度值为0
end
end
end
subplot(1,2,1);imshow(I);
subplot(1,2,2);imshow(I1);
分析:采用上述的最近邻插值法,可以发现,图像的边缘处理不完善,并且图像有一点失真,另外,由于处理时,图像的画布没有扩大,导致图像的四角缺失。
(2) 双线性插值法:
采用系统旋转函数imrotate,其格式为B=imrotate(A,angle,method),
nearest: 最邻近线性插值(默认);
bilinear:双线性插值 ;
bicubic: 双三次插值;
具体实现:
clear,clc
I=imread('lena3.jpg');
I1=imrotate(I,30,'bilinear'); %双线性插值将图像逆时针旋转30度
subplot(1,2,1);imshow(I);
subplot(1,2,2);imshow(I1);
分析:调用imrotate进行双线性插值旋转,处理的效果明显比上最邻近插值法好,能够
很好地保持原图的完整性,并失真度较小,比较理想。
3. 采用偏移量插值实现一个透视变换:
原理:首先确定图片四个顶点的偏移量,从而计算出方程组的系数矩阵,此矩阵及变换系数,进一步确定a、b、c、d和e、f、g、h,最后根据x' = a*x + b*y + c*x*y +d 、y' = e*x + f*y + g*x*y +h确定出变换后的横坐标和纵坐标。
具体实现:
clear,clc
I= imread('lena3.jpg');
[M N]=size(I);
I1 = zeros(M,N);
R=[1,1,M/4-1,0
1,N,0,0
M,1,-M/5,N/5-1
M,N,0,-N/5];
%R表示原图中的点对应的偏移量
A1=[R(:,1) R(:,2) R(:,1).*R(:,2) ones(4,1)];
%方程组的系数矩阵
x1=A1\R(:,3); %a,b,c,d
x2=A1\R(:,4); %e,f,g,h
T=[x1';x2'];
for i = 1:M
for j = 1:N
a = T*[i;j;i*j;1]; a = int32(a);
s=i+a(1); t= j+a(2); % (i,j)->(s,t)
if((s>=1)&&( s <= M) &&( t >= 1) &&( t <= N))
I1(s,t)=I(i,j);
end
end
end
I1 = uint8(I1);
subplot(1,2,1);imshow(I);
subplot(1,2,2);imshow(I1);
分析:实现的是向前映射透视,如需实现向后透视,重新获取变换系数矩阵,并使变换
后的图像坐标向原图映射,即(s,t)->(i,j)的变换。
二. 绘制一幅灰度图像的梯度幅度图像(三点法求梯度),针对梯度幅度图像合理的选择一个阈值(通过试验即可)将其二值化,以获得图像边缘检测图像。
原理:三点法求梯度,图像的梯度之为水平方向相邻像素之差的绝对值和垂直方向相邻像素之差的绝对值中的最大值。最后选取一个合适的阈值,当大于该阈值时,其灰度值设置为255,小于该值时设置为0。
具体实现:
clc,clear
I=imread('lena3.jpg');
[M N]=size(I);
I1=[I(:,1),I(:,1:N-1)]; %矩阵向右移一位,第一列保持不变
I2=[I(1,:);I(1:M-1,:)]; %矩阵向下移一位,第一行保持不变
I3=I2-I; I4=I1-I;
X=max(I3(1:M,1:N),I4(1:M,1:N)); %获取梯度图像的矩阵
d=30; %选取合适的阈值进行二值化处理
for i=1:M
for j=1:N
if (X(i,j)>d)
X(i,j)=1;
else
X(i,j)=0;
end
end
end
figure;
subplot(1,2,1),imshow(I);
subplot(1,2,2),imshow(X);
处理效果: