本博客将介绍如何使用OpenCV对图像进行任意角度的旋转,实现所有角度的旋转,具有一定的参考价值。有需要的朋友就跟着下面的边肖学习吧。
目录
-旋转角度坐标的计算-旋转任意角度的步骤3的实现
一 旋转角度坐标的计算
1.若以O点为圆心,P点绕O点旋转一个弧度后,P点坐标转换为Q点的计算公式为:
q . x=p . x * cos(redian)-p . y * sin(redian)
q . y=p . x * sin(redian)p . y * cos(redian)
Redian代表弧度。
弧度和角度之间的转换公式为:
redian=pi * 180/角度
2.如果O点不是圆心,P点绕O点旋转一个半径弧度后,P点到Q点的坐标变换计算公式如下:
q . x=(p . x-o . x)* cos(redian)-(p . y-o . y)* sin(redian)o . x
q . y=(p . x-o . x)* sin(redian)(p . y-o . y)* cos(redian)o . y
二 旋转任意角度的步骤
1.首先,图像默认旋转45度时,展开的图像最大,即长度或宽度的最大值为根号的两倍,图像填充到可能的最大值。
使用getRotationMatrix2D函数获取旋转矩阵,使用warpAffine函数旋转矩阵。
3找到包含旋转后图像的最大矩形。
4删除多余的黑色边框。
三 实现
#包括iostream
# includeopenv2/opencv . HPP
使用名称空间cv;
void rotate _ arbitrary _ angle(Mat src,Mat dst,float angle)
{
浮动弧度=(float)(角度/180.0 * CV _ PI);
//填充图像
int max border=(int)(max(src . cols,src . rows)* 1.414);//是sqrt(2)*max。
int dx=(max border-src . cols)/2;
int dy=(max border-src . rows)/2;
copyMakeBorder(src,dst,dy,dy,dx,dx,BORDER _ CONSTANT);
//旋转
point 2f center((float)(dst . cols/2),(float)(dst . rows/2));
mat affine _ matrix=getrotationmatrix 2d(中心,角度,1.0);//找到旋转矩阵
warpAffine(dst,dst,affine_matrix,dst . size());
//计算图像旋转后包含图像的最大矩形
float sinVal=abs(sin(弧度));
float cosVal=abs(cos(弧度));
size targetSize((int)(src . cols * cos val src . rows * sinVal),
(int)(src . cols * sin val src . rows * cos val));
//剪掉多余的边框
int x=(dst . cols-targetsize . width)/2;
int y=(dst . rows-targetsize . height)/2;
Rect rect(x,y,targetSize.width,targetsize . height);
dst=Mat(dst,rect);
}
int main() {
cv:Mat src=cv:imread(./3 . png’);
cv:Mat dst;
rotate _ arbitrary _ angle(src,dst,30);
cv:imshow(src ,src);
cv:imshow(dst ,dst);
cv:wait key(0);
返回0;
}
原图
围绕中心点旋转30度的结果
需要注意的是,这种方法只适用于将水平图像旋转成角度图像。至于可以随意旋转角度的方法,现在不知道怎么做,以后还会再做。
上述方法的最大缺点是旋转后像素大小发生变化。如果要在像素上操作,会有很多问题。下一个代码会固定像素,但也是针对旋转到一定角度再回到水平位置的代码。它有很大的局限性,所以我们会在研究了解后更新其他情况。
cv:Mat rotate _ arbitrary _ angle 1(cv:Mat matSrc,float angle,bool direction,int height,int width) {
float theta=角度* CV _ PI/180.0;
int nRowsSrc=mat src . rows;
int nColsSrc=mat src . cols;//如果顺时针旋转
如果(!方向)theta=2 * CV _ PI-theta;//都是逆时针旋转计算的
//逆时针旋转矩阵
浮动矩阵[3][3]{ {
STD:cos(),-STD:sin(),0},
{ STD:sin(),STD:cos(),0 },
{0, 0, 1} };
浮动点[3][2]{
{ 0,nRowsSrc },
{nColsSrc,nRowsSrc},
{nColsSrc,0 } };
for(int I=0;i3;i ) {
float x=pt[I][0]* matRotate[0][0]pt[I][1]* matRotate[1][0];
float y=pt[I][0]* matRotate[0][1]pt[I][1]* matRotate[1][1];
pt[I][0]=x;pt[I][1]=y;
}
//计算旋转后图像的极值点和大小。
float fMin _ x=STD:min(STD:min(STD:min(pt[0][0],pt[1][0]),pt[2][0]),(float)0.0);
float fMin _ y=STD:min(STD:min(STD:min(pt[0][1],pt[1][1]),pt[2][1]),(float)0.0);
float fMax _ x=STD:max(STD:max(STD:max(pt[0][0],pt[1][0]),pt[2][0]),(float)0.0);
float fMax _ y=STD:max(STD:max(STD:max(pt[0][1],pt[1][1]),pt[2][1]),(float)0.0);
int nRows=cv round(fMax _ y-fMin _ y 0.5)1;
int nCols=cv round(fMax _ x-fMin _ x 0.5)1;
int nMin _ x=cv round(fMin _ x 0.5);
int nMin _ y=cv round(fMin _ y 0.5);
//复制输出图像
cv:Mat matRet(nRows,nCols,matSrc.type(),cv:Scalar(0));
for(int j=0;j nRowsj ) {
for(int I=0;i nColsi ) {
//计算输出图像对应点在原始图像中的坐标,然后复制坐标的灰度值。
//因为是逆时针转换,所以在这里映射到原图的时候可以视为输出图。
//对原图进行顺时针旋转,顺时针旋转矩阵只是逆时针旋转矩阵的转置。
//也可以考虑将旋转后的图像左上角移动到坐标原点。
int x=(I nMin _ x)* matRotate[0][0](j nMin _ y)* matRotate[0][1];
int y=(I nMin _ x)* matRotate[1][0](j nMin _ y)* matRotate[1][1];
if (x=0 x nColsSrc y=0 y nRowsSrc) {
matRet.atuchar(j,i)=matSrc.atuchar(y,x);
}
}
}
If(direction==false){//当需要顺时针旋转回到水平位置时
int x=(matret . cols-width)/2;
int y=(matret . rows-height)/2;
//width和height是图像在水平条件下的宽度和高度。
cv:Rect rect(x,y,width,height);
matRet=cv:Mat(matRet,rect);
}
返回matRet
}
关于opencv图像任意角度旋转的实现示例,本文到此结束。有关opencv图像任意角度旋转的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望大家以后能多多支持我们!