嵌入式设计应用
旋转一般是指将图像围绕某一指定点旋转一定的角度,图像旋转后会有一部分图像转出显示区域,可以截图那部分,也可以改变图像的尺寸使得图像显示完全。
所谓图像旋转是指图像以某一点为中心旋转一定的角度,形成一幅新的图像的过程。这个点通常就是图像的中心。
由于是按照中心旋转,所以有这样一个属性:旋转前和旋转后的点离中心的位置不变。
根据这个属性,可以得到旋转后的点的坐标与原坐标的对应关系。
原图像的坐标一般是以左上角为原点的,我们先把坐标转换为以图像中心为原点。假设原图像的宽为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为旋转中心。
这里以图像围绕任意点(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;
}
全部0条评论
快来发表一下你的评论吧 !