您的位置:首页 > 移动开发

《Computer Vision:Algorithms and Applications》学习笔记(一)——图像旋转算法与实现

2012-02-02 22:16 489 查看
昨天和今天学习了《Computer Vision:Algorithms and Applications》中第二章“Image formation”前半部分,主要是如何表示2D、3D图像中的点、线、面等,以及如何用公式推导出2D图形的几何变换,如位移、旋转、放缩、仿射变换、投射等,如下图所示:



一、图像旋转方法简介

其中的图像旋转是一种常用的数字图像处理技术。由于旋转后图像像素点坐标不再是整数,所以旋转后必须对新的像素点灰度值进行插值运算。目前常用的方法有最近邻插值法、线性插值法和样条插值法。文献介绍,最近邻法速度快,方法简单,但生成图像效果较差;样条插值法计算精度高,效果好,但计算复杂,速度较慢;线性插值法(E.g. 双线性插值法)效果较好,运行时间较短。另外,实现赋值的方法分为正向映射法和反向映射法:正向映射法是指,从原始图像坐标出发,计算出在旋转图像上坐标,然后将原始图像该坐标的灰度值赋给对应旋转图像该坐标点;反向映射法则反之。

本文将分别采用基于最近邻取值的正向映射法、基于最近邻取值的反向映射法、基于双线性插值的反向映射法实现图像旋转,并对比三种方法的效果。

二、本文方法

1. 基于最近邻取值的正向映射法

这种方法最简单,也最直观,先考虑图像旋转原理:

以顺时针旋转为例来堆到旋转变换公式。如下图所示。



旋转前:

x0=rcosb;y0=rsinb

旋转a角度后:

x1=rcos(b-a)=rcosbcosa+rsinbsina=x0cosa+y0sina

y1=rsin(b-a)=rsinbcosa-rcosbsina=-x0sina+y0cosa

正向映射即根据原图的坐标推导出旋转图像对应点坐标,然后直接将原图坐标灰度值赋给x1,y1

2.基于最近邻取值的反向映射法



旋转前:

x1=rcosc;y1=rsinc

旋转a角度后:

x0=rcos(c+a)=rcosccosa-rsincsina=x1cosa-y1sina

y0=rsin(c+a)=rsinccosa+rcoscsina=-x1sina+y1cosa

反向映射即已知旋转后图像坐标,通过公式推导出原始图像上对应坐标,将该坐标对应灰度值赋给旋转后坐标。因为计算得到的y0, x0非整数,最近邻方法即将与(Xo,Yo)距离最近的像素的灰度值作为(Xo,Yo)的灰度值赋给(X1,Y1)点。

3.基于双线性插值的反向映射法

在计算(Xo,Yo)的灰度值时,采用如下方法计算:





三、实验对比

三种实验结果的对比图如下:



可见,双线性插值法获得的旋转图像更平滑,接近真实图像。

三种方法的matlab代码如下

Image=imread('E:\1.jpg');

%X,Y为其行列数
angle=30;
%角度任意的一个数 表示30度
pai=3.1415929657;
Angle=pai*angle/180;
%转换一下角度的表示方法。
[Y,X,Z]=size(Image);
%原图显示
subplot(2,2,1);
imshow(Image);
title('原图像');

%
%计算四个角点的新坐标,确定旋转后的显示区域
LeftBottom(1,1)=(Y-1)*sin(Angle);
LeftBottom(1,2)=(Y-1)*cos(Angle);

LeftTop(1,1)=0;
LeftTop(1,2)=0;

RightBottom(1,1)=(X-1)*cos(Angle)+(Y-1)*sin(Angle);
RightBottom(1,2)=-(X-1)*sin(Angle)+(Y-1)*cos(Angle);

RightTop(1,1)=(X-1)*cos(Angle);
RightTop(1,2)=-(X-1)*sin(Angle);

%计算显示区域的行列数
Xnew=max([LeftTop(1,1),LeftBottom(1,1),RightTop(1,1),RightBottom(1,1)])-min([LeftTop(1,1),LeftBottom(1,1),RightTop(1,1),RightBottom(1,1)]);
Ynew=max([LeftTop(1,2),LeftBottom(1,2),RightTop(1,2),RightBottom(1,2)])-min([LeftTop(1,2),LeftBottom(1,2),RightTop(1,2),RightBottom(1,2)]);

% 分配新显示区域矩阵
ImageNewForward=zeros(round(Ynew),round(Xnew),3)+255;
ImageNewIntersection=zeros(round(Ynew),round(Xnew),3)+255;
ImageNew1nn=zeros(round(Ynew),round(Xnew),3)+255;

%计算原图像各像素的新坐标:正向映射法
for indexX=0:(X-1)
for indexY=0:(Y-1)
Yn=1+round(-indexX*sin(Angle)+indexY*cos(Angle))+round(abs(min([LeftTop(1,2),LeftBottom(1,2),RightTop(1,2),RightBottom(1,2)])));
Xn=round(indexX*cos(Angle)+indexY*sin(Angle))+round(abs(min([LeftTop(1,1),LeftBottom(1,1),RightTop(1,1),RightBottom(1,1)])))+1;
ImageNewForward(Yn,Xn,1)=Image(indexY+1,indexX+1,1);
ImageNewForward(Yn,Xn,2)=Image(indexY+1,indexX+1,2);
ImageNewForward(Yn,Xn,3)=Image(indexY+1,indexX+1,3);
end
end

%%反向映射法
for indexY=1:round(Ynew)
for indexX=1:round(Xnew)
Y1=indexY-round(abs(min([LeftTop(1,2),LeftBottom(1,2),RightTop(1,2),RightBottom(1,2)])));
X1=indexX-round(abs(min([LeftTop(1,1),LeftBottom(1,1),RightTop(1,1),RightBottom(1,1)])));
Yoo=X1*sin(Angle)+Y1*cos(Angle);
Xoo=X1*cos(Angle)-Y1*sin(Angle);
Yo=round(Yoo);
Xo=round(Xoo);
if 1<Xo&&Xo<X&&1<Yo&&Yo<Y
%最近邻法
ImageNew1nn(indexY,indexX,1)=Image(Yo,Xo,1);
ImageNew1nn(indexY,indexX,2)=Image(Yo,Xo,2);
ImageNew1nn(indexY,indexX,3)=Image(Yo,Xo,3);

%双线性插值法
left=floor(Xoo);
right=ceil(Xoo);
up=floor(Yoo);
down=ceil(Yoo);

upmid1=(1-Xoo+left)*Image(up,left,1)+(Xoo-left)*Image(up,right,1);
downmid1=(1-Xoo+left)*Image(down,left,1)+(Xoo-left)*Image(down,right,1);
upmid2=(1-Xoo+left)*Image(up,left,2)+(Xoo-left)*Image(up,right,2);
downmid2=(1-Xoo+left)*Image(down,left,2)+(Xoo-left)*Image(down,right,2);
upmid3=(1-Xoo+left)*Image(up,left,3)+(Xoo-left)*Image(up,right,3);
downmid3=(1-Xoo+left)*Image(down,left,3)+(Xoo-left)*Image(down,right,3);
central1=(1-Yoo+up)*upmid1+(Yoo-up)*downmid1;
central2=(1-Yoo+up)*upmid2+(Yoo-up)*downmid2;
central3=(1-Yoo+up)*upmid3+(Yoo-up)*downmid3;

ImageNew(indexY,indexX,1)=central1;
ImageNew(indexY,indexX,2)=central2;
ImageNew(indexY,indexX,3)=central3;

else
ImageNew(indexY,indexX,:)=255;
end
end
end

%显示
subplot(2,2,2);
ImageNewForward=uint8(ImageNewForward);
imshow(ImageNewForward);
promp=['旋转角度为:' int2str(angle) '度图像 正向映射法'];
title(promp);

subplot(2,2,3);
ImageNew1nn=uint8(ImageNew1nn);
imshow(ImageNew1nn);
promp=['旋转角度为:' int2str(angle) '度图像 最近邻插值法'];
title(promp);

subplot(2,2,4);
ImageNew=uint8(ImageNew);
imshow(ImageNew);
promp=['旋转角度为:' int2str(angle) '度图像 双线性插值法'];
title(promp);


参考文献:
1. 《Computer Vision:Algorithms and Applications》,pp30-40

2. 曹佃国, 陈浩杰,李鹏, "基于 Matlab 双线性插值算法图像旋转中应用".
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: