(实验二) --- 图像旋转变换---matlab实现



=摘要=
图像处理老师的课很"抽像",很会"跳"....刚讲了一点"RBG转灰度图",就马上进军图像的几何变换了,同时也带来了一个新的实验(作業):<图像的旋转>.
要求:旋转弧度: 0<radian<pi/2 (顺时针旋转).


对于我这个"好学生"来说...当然掩盖不了心中的好奇心----图像旋转是怎么实现的?于是经过一定的探索(主要是matlab的用法)...终于实现了这个"旋转":)
本文就是关于这个"探索"过程的一点文字记录啦.


=预览一下=
matlab有一个图像处理工具(IPT),里面已经有一个图像旋转算法的实现了...函数名:imrotate(源图像,旋转角度)...这里将给出:源图像,IPT版本处理过的旋转后图像,我自己的算法处理过的旋转图像:

==原图像==

(实验二) --- 图像旋转变换---matlab实现_第1张图片

==IPT(imrotate)实现旋转==

(实验二) --- 图像旋转变换---matlab实现_第2张图片

==我自己的旋转函数結果==
(实验二) --- 图像旋转变换---matlab实现_第3张图片

==说明==

上面的旋转对于玩过图像处理PS的人来说是不是太简单了?在PS里面或者其他图像处理工具里面对于图像的旋转是"极"简单的...一点就是了:)
上面的"旋转"在生活中经常看到...你把一张生活照旋转一下就感觉到了哈.


=什么是图像的旋转=
图像的旋转是图像几何变换的一种...看到上面预览的图就能知道...旋转前后的图像的像素的RGB都是没有改变的,改变的只是每一个像素的所在位置....这个就是旋转的本质:
把原图像像素从原点(x,y)放到目标位置点上(x',y')..这个(x,y)到(x',y')的转换是经过旋转计算而来的...那么这个图像处理就是旋转处理(几何变换).


再看看上面的图,还真的发现只是图像的像素点的位置改变了,图像本身的彩色信息并没有改动什么.


=怎么SHOW旋转后的图像=
=图像是怎么显示的=
图像的显示都是基于矩阵像素来显示的...上面每一张图像的图像信息其实是一个RGB矩阵来的.所以必须把旋转后的图像放到一个像素矩阵中才能显示这个旋转后的图像.
设一张图像的大小是col*row的.那么以这个图像对角线为直径的圆就能够包含这个图像经旋转后的图像..在这里因为图像的显示是矩阵式的,所以这里以图像对角线为边长构造一个正方形来保存旋转后的图像.从上面旋转后的图像可以看出效果啦,旋转后的图像就包含在这个正方形的矩阵中.

=计算旋转图像所需要的正方形=
因为图像是col*row的,所以这个正方形的边长 new_img_size = (col^2+row^2)^0.5;
这样使用matlab就可以生成一个存储最终图像的rgb矩阵了:

		img_rotated = uint8(zeros(new_img_size , new_img_size , 3);	//%一个像素由RGB三个分量表现.


=怎么旋转?=
现在来到正题了,上面已经把旋转的原理给讲清楚了...本质就是找到原点(x,y)的新位置(x',y'),然后把原点的像素复制到目标点上就行了...上面也提到了一点:旧坐标到新坐的变的是"旋转"而来的...下面来体现一下旋转的原因:
设一个原点P,P的坐标是:(x,y),这里的x是列分量,y是行分量.
那么P点离图像左上角的距离是:r=(x^2+y^2)^0.5; 同时p到(1,1)点的连线与列方向有一个夹角:a
此时r,x,y的关系可以进一步表示成:
		x =  r*cos(a);
		y =  r*sin(a);
到了这里可以知道(x,y)本身与"旋转"角度有一定的关系了,....下面就将p点绕(1,1)这点顺时针旋转b角度...得到p的新位置(x',y')..由r,x,y的关系可以得到r,x',y'的关系如下:
		x' = r*cos(a+b);
		y' = r*sin(a+b);	
进一步化简:
		x' = r*cos(a)*cos(b) - r*sin(a)*sin(b);
		y' = r*sin(a)*cos(b) + r*cos(a)*sin(b);
然后再结合r,x,y的关系得到x,y,x',y'的关系如下:
		x' = x*cos(b) - y*sin(b);
		y' = y*cos(b) + x*sin(b);		

于是上面提到的点旋转位置关系就出来了....即(x,y)经过顺时针旋转b角度后可以得到(x',y')..这个转换公式就是上面的线性方程..写成matlab的方式就是如下啦:
	[x',y'] = [cos(b) -sin(b);sin(b) cos(b)]*[x,y];  //%这里的x'不是x的转置哦.

好了,到此为止,我们有了旋转公式了...下面就可以利用这个公式对原图的每一个像素点(x,y)计算其旋转后的位置(x',y')了,然后就是复制图像的像素点了(简单不?)...


=怎么复制像素点=
由上面两节可以看出,图像旋转后的像素应该保存在img_rotated当中. 同时每一个像素的坐标都是正的,即没有(-10,-10)坐标位置的像素点..而从上面(x,y)到(x',y')的计算过程可以看出....x'或者y'都可能出现是负值的问题...于是不能够在计算出x',y'后就直接把x,y处的像素复制到x',y'...因为x',y'可能是一个非法的位置.
从上面的图来看,这个问题还是可以解决了..要不然上面我就不能做出那么像样的旋转了呵呵.


为了让x',y'合法,让我们来看看原图像顺时针旋转后,原图上哪些点会导致对应的x',y'不合法... 经过分析.不难看出只有x'这个变量会出现负值,而x'为负值时x的值就分布在图像的左下角处....
而且x'达到最小负数的绝对值是row*sin(b).注意y'永远是一个正的...因为题目的要求可以知道..而且矩阵的左上角是(1,1).即采用计算机的坐标系统.


好了,找到了x'不合法的原因了...这个时候就可以找找解决方法了....联想到图像旋转后是存储在img_rotated当中的...而且原图的左下角像素显示在img_rotated的左边界上面...所以解决方法就是计算完成x',y'后,再将x',y'右移一段距离,以让x'始终是正值...很明显,这右移的距离大小就是row*sin(b),注意这里y'是不需要调整的.
所以最终x,y得到的目标位置x'',y''就由如下公式计算了.
		x'' = x*cos(b) - y*sin(b) + row*sin(b);
		y'' = y*cos(b) + x*sin(b);		


(可以看出与上面x',y'的计算没有差多少,只是图像右移了下呵呵)


得到了x'',y''的同时,我们也知道原图像素(x,y)的目标位置就是img_rotated(x'',y'')


哈哈,终于写到这里了...这里也标记着我的这个旋转算法的尾声了....正个算法就是找到(x,y)在img_rotated的显示位置(x'',y'')..


经过上面的算法处理后,我是能够看到图像"旋转"了...但是也能明显发现:图像的质量很差...因为img_rotated当中也许多有规律性的背景点没有得到原图像的像素来填充...

=存在像素空洞的图像=
下图是直接运用上面算法进行的旋转处理后的图像:




=解决空洞像素问题=
仔细看看有空洞像素的图像可以看出,没有像素填充的点都是有规律的....再想想上面的计算都是基于三角函数的,而且三角函数的值都是小数...于是原因就可以猜出来了.:原点(x,y)到(x'',y'')的计算不是连续的,因为x'',y''是有取整操作的....这个就是造成空洞的原因了...
哈哈,知道原因了...查找解决方案就有方向了...
由上面可以知道是x'',y''有取整操作...造成部分点没有达到其对应的点上去...
所以我在计算x'',y''的时候故意加上了+0.5,-0.5分量到x''或者y''分量上去..目的是把x'',y''周围不可能由x,y达到的点用x,y像素点去填充...这个思想也是今天老师在课堂说的"插值"问题(老师也向我们演示这个问题,他的解决方法是x'',y''周围8个没有填充的像素点用x'',y''点去填充)
经过上面的x'',y''调整...图像旋转后的的空洞点就没有了,表面上看起来就是我们想要的旋转后的图像了.呵呵...
            

                没有考虑到像素空洞的图像:

(实验二) --- 图像旋转变换---matlab实现_第4张图片

=图像边界齿距=
我个人感觉我的这个算法还是有问题的,于是与IPT工具里面的旋转图像算法相比...結果是我旋转后的图像不仅在尺寸要比imrotate的输出图像要大一点点,而且边界上面的齿距也没有imrotate的输出图像那么完美.(这点我用老师的算法比较也是一样.)
于是我想应该是因为上面x'',y''调整问题了...把边界某些点复制多出来了....于是一个一个调整算法(-0.5,+0.5)..最终调试成功了....四个边界的齿距都与IPT的imrotate的输出图像99%一致了(但是右下角的一个点有点不一样呵呵)
                下面是一张显示齿距的图像块:

(实验二) --- 图像旋转变换---matlab实现_第5张图片

=算法复杂度=
上面提到了就是对图像每一个点的坐标进行计算,然后把点上的像素数据复制到目标坐标上...所以对于一个col*row大小的图像,我这个图像处理算法的时间复杂度是:O(N^2);
=小结=
呼呼...写到这里也不容易的(写了1小时多一丁点),特别是对于我这种没杂写过文字的人.

上面討論了我是怎么实现这个图像旋转算法,同时也考虑了一些图像像素点空洞,边界齿距问题...


如果还是有点不明白的,那直接可以结合我的m文件源代码看看,源代码我放到csdn.download里面咯...核心代码量是20行吧.


=源代码=
地址:
http://download.csdn.net/detail/abee23/4176587

上面是我刚接触图像处理的第二个实验笔记,其中一定有很多不够专业的说法...在这里原谅小弟啦...:)


最后:欢迎拍砖:)





   

你可能感兴趣的:(算法,生活,matlab,工具,图像处理)