一、图像旋转的原理
图像旋转的本质是向量的旋转。直接看图
向量的旋转很容易理解,在图像旋转中,图像中心到某一像素点就可视作一向量,对该向量进行关于中点的旋转即可对该像素点进行旋转,对所有像素点进行旋转就完成了图像的旋转。
方案一、正向直接旋转
设原像素点P对应向量为K1,旋转后像素点P’对应向量为K2,旋转矩阵R为:
则:可以得到
看下图,若相对整张图片P位置为p1,P’位置为p2,图像中点位置为c,则可以得到:
得到:
正向法的思路是将原图片中的每一个像素点做旋转变换求出其在新图片中的位置,再赋给新图片的对应位置。
中点坐标可以由图片宽度
和高度
得到。
MATLAB代码如下:
%读入图片
im=imread('fruit.png');
%旋转30°
%求出旋转矩阵
a=30/180*pi;
R=[cos(a),-sin(a);sin(a),cos(a)];%旋转矩阵
%求出图片大小
sz=size(im);
height=sz(1);%高度
width=sz(2);%宽度
channel=sz(3);%通道数
center=[height;width]/2;%求出图片中心位置
%构造旋转结果图像
im2=uint8(zeros(height,width,3));
for k = 1:channel
for i = 1:height
for j = 1:width
p=[i;j];%遍历每一个像素点
%round为四舍五入
pp=round(R*(p-center)+center);%旋转,求出结果坐标
%这里简单用了round函数来取整,因此旋转结果非常不理想
%排除不在画布内的像素
if(pp(1)>=1 && pp(1)<=height &&pp(2)>=1 && pp(2) <= width)
im2(pp(1),pp(2),k)=im(i,j,k);
end
end
end
end
figure;
imshow(im);
figure;
imshow(im2);
结果如下:
可以看出,按照方案一旋转后的图片有几个问题:
1、图片旋转后由一部分被切割了,无法正常显示
2、新图片某些像素无法显示
具体见下图
导致新图像显示不完全的原因是图像在旋转后需要的画布大小发生了变化
由上面这张图很容易可以得出:
而新图像部分像素点无法显示的原因是在求旋转后像素点坐标时使用round函数粗略地求出新坐标的整数值,而导致部分原像素计算后的新像素位置重叠,进而导致新图片中部分点像素缺失。并且从结果来看缺失像素点非常多。
解决这个问题有两种新方案:
方案二、反向查找法
与方案一正向法不同的是,方案二的思路正好相反,求出新图像每一个像素点旋转前在原图片中的位置,再将原图片中对应像素赋值给新图片。
并且需要重新计算新画布的大小和新画布的中点位置c2。
若旋转矩阵的逆矩阵为R’,则可以得出
换算成位置就是
得出:
MATLAB代码:
im=imread('fruit.png');
%旋转30°
%求出旋转矩阵
a=30/180*pi;
R=[cos(a),-sin(a);sin(a),cos(a)];%旋转矩阵
R=R';%求出旋转矩阵的逆矩阵
%求出图片大小
sz=size(im);
h=sz(1);
w=sz(2);
ch=sz(3);
c1=[h;w]/2;%原图中心
%计算显示完整图像需要的画布大小
hh=floor(width*sin(a)+height*cos(a))+1;
ww=floor(width*cos(a)+height*sin(a))+1;
c2=[hh,ww]/2;%求新画布中点
%初始化目标画布
im2=uint8(ones(hh,ww,3)*128);
for k = 1:ch
for i = 1:hh
for j = 1:ww
p=[i;j];%遍历新图像像素点
pp=round(R*(p-c2)+c1);%计算在原来图像中的位置
%这里仍然使用round函数,但结果会比方案一好得多
%逆向进行像素查找
if(pp(1)>=1&&pp(1)<=h&&pp(2)>=1&&pp(2)<=w)
im2(i,j,k)=im(pp(1),pp(2),k);
end
end
end
end
%显示图像
figure;
imshow(im);
figure;
imshow(im2);
运行结果:
可以看出这次的显示效果好得多了
已经不存在像素点缺失的问题了
实际上如果再进行双线性差值,图像的旋转效果会更好,我准备在下一篇和双线性差值在图像旋转中的应用一起展示,在这就不展示了。