opencv如何实现图像旋转 | 您所在的位置:网站首页 › 墨盒如何添加墨水视频教程 › opencv如何实现图像旋转 |
旋转一般是指将图像围绕某一指定点旋转一定的角度,图像旋转后会有一部分图像转出显示区域,可以截图那部分,也可以改变图像的尺寸使得图像显示完全。 图像旋转原理所谓图像旋转是指图像以某一点为中心旋转一定的角度,形成一幅新的图像的过程。这个点通常就是图像的中心。 由于是按照中心旋转,所以有这样一个属性:旋转前和旋转后的点离中心的位置不变。 根据这个属性,可以得到旋转后的点的坐标与原坐标的对应关系。 原图像的坐标一般是以左上角为原点的,我们先把坐标转换为以图像中心为原点。假设原图像的宽为w,高为h,(x0,y0)为原坐标内的一点,转换坐标后的点为(x1,y1)。可以得到: X0’ = x0 -w/2; y1’ =-y0 + h/2; 在新的坐标系下,假设点(x0,y0)距离原点的距离为r,点与原点之间的连线与x轴的夹角为b,旋转的角度为a,旋转后的点为(x1,y1), 如下图所示。
那么有以下结论: x0=r*cosb;y0=r*sinb x1 = r*cos(b-a)= r*cosb*cosa+r*sinb*sina=x0*cosa+y0*sina; y1=r*sin(b-a)=r*sinb*cosa-r*cosb*sina=-x0*sina+y0*cosa; 得到了转换后的坐标,我们只需要把这些坐标再转换为原坐标系即可。 x1’ = x1+w/2= x0*cosa+y0*sina+w/2 y1’=-y1+h/2=-(-x0*sina+y0*cosa)+h/2=x0*sina-y0*cosa+h/2 此处的x0/y0是新的坐标系中的值,转换为原坐标系为: x1’ = x0*cosa+y0*sina+w/2=(x00-w/2)*consa+(-y00+h/2)*sina+w/2 y1’= x0*sina-y0*cosa+h/2=(x00-w/2)*sina-(-y00+h/2)*cosa+h/2 =(y00-h/2)*cosa+( x00-w/2)*sina+h/2 在OpenCV中,目前并没有现成的函数直接用来实现图像旋转,它是用仿射变换函数cv::warpAffine来实现的,此函数目前支持4种插值算法,最近邻、双线性、双三次、兰索斯插值,如果传进去的参数为基于像素区域关系插值算法(INTER_AREA),则按双线性插值。 通常使用2*3矩阵来表示仿射变换:
其中,T相当于变换前的原始图像,x,y为变换后的图像坐标。 对于cv::getRotaTIonMatrix2D函数的实现公式为:
其中scale为缩放因子(x、y方向保持一致),angle为旋转角度(弧长),centerx,centery为旋转中心。
1 旋转矩形 这里以图像围绕任意点(center_x, center_y)旋转为例,但是图像的原点在左上角,在计算的时候首先需要将左上角的原点移到图像中心,并且Y轴需要翻转。 而在旋转的过程一般使用旋转中心为坐标原点的笛卡尔坐标系,所以图像旋转的第一步就是坐标系的变换。(x’,y’)是笛卡尔坐标系的坐标,(x,y)是图像坐标系的坐标,经过坐标系变换后
坐标系变换到以旋转中心为原点后,接下来就要对图像的坐标进行变换。
逆变换是
由于在旋转的时候是以旋转中心为坐标原点的,旋转结束后还需要将坐标原点移到图像左上角,也就是还要进行一次变换。
上边两图,可以清晰的看到,旋转前后图像的左上角,也就是坐标原点发生了变换。 在求图像旋转后左上角的坐标前,先来看看旋转后图像的宽和高。从上图可以看出,旋转后图像的宽和高与原图像的四个角旋转后的位置有关。 我们将这个四个角点记为 transLeftTop, transRightTop, transLeftBottom, transRightBottom 设top为旋转后最高点的纵坐标 top = min({ transLeftTop.y, transRightTop.y, transLeftBottom.y, transRightBottom.y }); down为旋转后最低点的纵坐标 down = max({ transLeftTop.y, transRightTop.y, transLeftBottom.y, transRightBottom.y }); left为旋转后最左边点的横坐标 left = min({ transLeftTop.x, transRightTop.x, transLeftBottom.x, transRightBottom.x }); right为旋转后最右边点的横坐标 right = max({ transLeftTop.x, transRightTop.x, transLeftBottom.x, transRightBottom.x }); 旋转后的宽和高为newWidth,newHeight,则可得到下面的关系:
旋转完成后要将坐标系转换为以图像的左上角为坐标原点,可由下面变换关系得到:
逆变换
综合以上,也就是说原图像的像素坐标要经过三次的坐标变换: 将坐标原点由图像的左上角变换到旋转中心 以旋转中心为原点,图像旋转角度a 旋转结束后,将坐标原点变换到旋转后图像的左上角 可以得到下面的旋转公式:(x’,y’)旋转后的坐标,(x,y)原坐标,(x0,y0)旋转中心,a旋转的角度(顺时针)
这种由输入图像通过映射得到输出图像的坐标,是向前映射。常用的向后映射是其逆运算
#include《iostream》 #include《TIme.h》 #include《opencv2/opencv.hpp》 using namespace std; using namespace cv; inline double cpu_TIme(){ return clock()*1000/CLOCKS_PER_SEC; } //图片旋转操作 void imrotate(Mat& img, Mat& newIm, double angle){ int len = max(img.cols, img.rows); Point2f pt(len/2.,len/2.); Mat r = getRotaTIonMatrix2D(pt,angle,1.0); warpAffine(img,newIm,r,Size(len,len)); //better performance : //Point2f pt(img.cols/2.,img.rows/2.); //Mat r = getRotationMatrix2D(pt,angle,1.0); //warpAffine(img,newIm,r,img.size()); } int main(){ Mat img = imread(“1.jpg”); //resize(img,img,Size(256,256)); Mat newIm; double t1,t2; t1 = cpu_time(); //调用旋转方法,模仿matlab,取名为imrotate imrotate(img,newIm,15); t2 = cpu_time(); c out《《“Rotate one image cost: ”《《t2-t1《《“ ms”《《endl; namedWindow(“Rotate”); imshow(“Rotate”,newIm); waitKey(10000); const string save_name = “rotate.jpg”; imwrite(save_name,newIm); return 0; }
|
今日新闻 |
推荐新闻 |
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 |