opencv如何实现图像旋转_原理是什么

嵌入式设计应用

132人已加入

描述

  旋转一般是指将图像围绕某一指定点旋转一定的角度,图像旋转后会有一部分图像转出显示区域,可以截图那部分,也可以改变图像的尺寸使得图像显示完全。

  图像旋转原理

  所谓图像旋转是指图像以某一点为中心旋转一定的角度,形成一幅新的图像的过程。这个点通常就是图像的中心。

  由于是按照中心旋转,所以有这样一个属性:旋转前和旋转后的点离中心的位置不变。

  根据这个属性,可以得到旋转后的点的坐标与原坐标的对应关系。

  原图像的坐标一般是以左上角为原点的,我们先把坐标转换为以图像中心为原点。假设原图像的宽为w,高为h,(x0,y0)为原坐标内的一点,转换坐标后的点为(x1,y1)。可以得到:

  X0’ = x0 -w/2;

  y1’ =-y0 + h/2;

  在新的坐标系下,假设点(x0,y0)距离原点的距离为r,点与原点之间的连线与x轴的夹角为b,旋转的角度为a,旋转后的点为(x1,y1), 如下图所示。

 OpenCV

  那么有以下结论:

  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矩阵来表示仿射变换:

  OpenCV

  其中,T相当于变换前的原始图像,x,y为变换后的图像坐标。

  对于cv::getRotationMatrix2D函数的实现公式为:

  OpenCV

  其中scale为缩放因子(x、y方向保持一致),angle为旋转角度(弧长),centerx,centery为旋转中心。

  OpenCV

  1 旋转矩形

  这里以图像围绕任意点(center_x, center_y)旋转为例,但是图像的原点在左上角,在计算的时候首先需要将左上角的原点移到图像中心,并且Y轴需要翻转。

  而在旋转的过程一般使用旋转中心为坐标原点的笛卡尔坐标系,所以图像旋转的第一步就是坐标系的变换。(x’,y’)是笛卡尔坐标系的坐标,(x,y)是图像坐标系的坐标,经过坐标系变换后

 OpenCV

  坐标系变换到以旋转中心为原点后,接下来就要对图像的坐标进行变换。

  OpenCV

  逆变换是

  OpenCV

  由于在旋转的时候是以旋转中心为坐标原点的,旋转结束后还需要将坐标原点移到图像左上角,也就是还要进行一次变换。

  OpenCV

  上边两图,可以清晰的看到,旋转前后图像的左上角,也就是坐标原点发生了变换。

  在求图像旋转后左上角的坐标前,先来看看旋转后图像的宽和高。从上图可以看出,旋转后图像的宽和高与原图像的四个角旋转后的位置有关。

  我们将这个四个角点记为 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,则可得到下面的关系:

  OpenCV

  旋转完成后要将坐标系转换为以图像的左上角为坐标原点,可由下面变换关系得到:

  OpenCV

  逆变换

  OpenCV

  综合以上,也就是说原图像的像素坐标要经过三次的坐标变换:

  将坐标原点由图像的左上角变换到旋转中心

  以旋转中心为原点,图像旋转角度a

  旋转结束后,将坐标原点变换到旋转后图像的左上角

  可以得到下面的旋转公式:(x’,y’)旋转后的坐标,(x,y)原坐标,(x0,y0)旋转中心,a旋转的角度(顺时针)

  OpenCV

  这种由输入图像通过映射得到输出图像的坐标,是向前映射。常用的向后映射是其逆运算

OpenCV

  opencv实现图片旋转功能,非常简单,几行代码即可:

  #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;

  }

  

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分