一幅图中的目标各种角度不一,想将这些小目标都摆到水平。那么就要知道旋转矩阵,然后求逆矩阵变换回去就可以。比如A旋转成了图B,求得旋转矩阵H,求H的逆矩阵M就可以由B变回A。
但是往往现实中不知道A是什么样,只给出了B,求A是什么样。以为这是很简单的问题,写完了才知道不是我以为那样。
结果类似这样,将其中一些目标放到右边这样水平,大致就是这意思。
/rotate back//
typedef struct
{
int width;
int height;
float m[6];
}sRotateSzie;
/*
* objgray----小目标的灰度图或二值图
* origin_box-小目标的最小外接矩形
* dstimg-----旋转回水平后的结果
* */
int rotateBackImgs(Mat &objgray,RotatedRect &origin_box,Mat &dstimg)
{
float angle=90 + origin_box.angle;
if (origin_box.size.width > origin_box.size.height)
angle = origin_box.angle;
sRotateSzie cs = GetImageSize(objgray, angle);
Mat M(2, 3, CV_32F, cs.m);
Mat Rotatedback;
warpAffine(objgray,Rotatedback, M, cv::Size(cs.width,cs.height), INTER_LINEAR + WARP_FILL_OUTLIERS,BORDER_CONSTANT,Scalar(0));//);//
//原来的4个顶点旋转以后的位置 存图看
imwrite("Rotatedback.jpg",Rotatedback);
int circle_length=3;
Mat tmpzero(Rotatedback.size().height+2*circle_length,Rotatedback.size().width+2*circle_length,CV_8UC1,Scalar(0));
Point originpt(0,0);
Point tmppt;
tmppt.x=cs.m[0]*originpt.x+cs.m[1]*originpt.y+cs.m[2];
tmppt.y=cs.m[3]*originpt.x+cs.m[4]*originpt.y+cs.m[5];
cv::circle(tmpzero,tmppt,circle_length,Scalar(255),-1);
// imwrite("Rotatedback_upleft.jpg",tmpzero);
originpt.x=objgray.cols-1;
originpt.y=0;
tmppt.x=cs.m[0]*originpt.x+cs.m[1]*originpt.y+cs.m[2];
tmppt.y=cs.m[3]*originpt.x+cs.m[4]*originpt.y+cs.m[5];
cv::circle(tmpzero,tmppt,circle_length,Scalar(255),-1);
// imwrite("Rotatedback_upright.jpg",tmpzero);
originpt.y=objgray.rows-1;
originpt.x=objgray.cols-1;
tmppt.x=cs.m[0]*originpt.x+cs.m[1]*originpt.y+cs.m[2];
tmppt.y=cs.m[3]*originpt.x+cs.m[4]*originpt.y+cs.m[5];
cv::circle(tmpzero,tmppt,circle_length,Scalar(255),-1);
// imwrite("Rotatedback_downright.jpg",tmpzero);
originpt.x=0;
originpt.y=objgray.rows-1;
tmppt.x=cs.m[0]*originpt.x+cs.m[1]*originpt.y+cs.m[2];
tmppt.y=cs.m[3]*originpt.x+cs.m[4]*originpt.y+cs.m[5];
cv::circle(tmpzero,tmppt,circle_length,Scalar(255),-1);
// imwrite("Rotatedback_downleft.jpg",tmpzero);
int rowmin=Rotatedback.rows,rowmax=0,colmin=Rotatedback.cols,colmax=0;
for(int r=0;r!=Rotatedback.rows;r++)
{
if(rowmin != Rotatedback.rows && rowmax!=0)
break;
for(int c=0;c!=Rotatedback.cols;c++)
{
if(rowmin != Rotatedback.rows && rowmax!=0)
break;
if(rowmin==Rotatedback.rows && Rotatedback.at<uchar>(r,c)!=0)
{
rowmin=r;
}
if(rowmax==0 && Rotatedback.at<uchar>(Rotatedback.rows-1-r,c)!=0)
{
rowmax=Rotatedback.rows-1-r;
}
}
}
for(int c=0;c!=Rotatedback.cols;c++)
{
if(colmin != Rotatedback.cols && colmax!=0)
break;
for(int r=0;r!=Rotatedback.rows;r++)
{
if(colmin != Rotatedback.cols && colmax!=0)
break;
if(colmin==Rotatedback.cols && Rotatedback.at<uchar>(r,c)!=0)
{
colmin=c;
}
if(colmax==0 && Rotatedback.at<uchar>(r,Rotatedback.cols-1-c)!=0)
{
colmax=Rotatedback.cols-1-c;
}
}
}
imwrite("Rotatedback_2.jpg",Rotatedback(Rect(colmin,rowmin,colmax-colmin,rowmax-rowmin)));
Rotatedback(Rect(colmin,rowmin,colmax-colmin,rowmax-rowmin)).copyTo(dstimg);
return 0;
}
void _bound(int x, int y, float ca, float sa, int *xmin, int *xmax, int *ymin, int *ymax)
{
int rx, ry;
rx = (int)floor(ca*(float)x + sa*(float)y);
ry = (int)floor(-sa*(float)x + ca*(float)y);
if (rx<*xmin)
{*xmin = rx;}
if (rx>*xmax)
{*xmax = rx;}
if (ry<*ymin)
{*ymin = ry;}
if (ry>*ymax)
{*ymax = ry;}
}
//rotate image
sRotateSzie GetImageSize(Mat src, float &angle)
{
sRotateSzie cs; //鍖呭惈浜嗘棆杞煩闃电殑鍥惧儚
int nx, ny;
float ca, sa;
int xmin=0, xmax=0, ymin=0, ymax=0, sx, sy;
ca = (float)cos((double)(angle)*CV_PI / 180.0);
sa = (float)sin((double)(angle)*CV_PI / 180.0);
nx = src.size().width;
ny = src.size().height;
//xmin = xmax = ymin = ymax = 0;
_bound(nx - 1, 0, ca, sa, &xmin, &xmax, &ymin, &ymax);
_bound(0, ny - 1, ca, sa, &xmin, &xmax, &ymin, &ymax);
_bound(nx - 1, ny - 1, ca, sa, &xmin, &xmax, &ymin, &ymax);
sx = xmax - xmin + 1;
sy = ymax - ymin + 1;
cs.width = sx;
cs.height = sy;
cs.m[0] = ca; //鏃嬭浆瑙掑害鐨勪綑寮﹀��
cs.m[1] = sa; //鏃嬭浆瑙掑害鐨勬寮﹀��
cs.m[2] = -(float)xmin; //鏃嬭浆涓績鐨剎鍧愭爣
cs.m[3] = -cs.m[1];
cs.m[4] = cs.m[0];
cs.m[5] = -(float)ymin; //鏃嬭浆涓績鐨剏鍧愭爣
return cs;
}
//旋转恢复,即恢复旋转之前的状态
/*
input:box-------------小目标的最小外接矩形
boxlongside-----box的长边
boxshortside----box的短边
output:standardobj----用来存放恢复旋转的图片
*/
int cnnAlgae::ratateDebugImgs(RotatedRect &box,float &boxlongside,float &boxshortside,vector<Mat> &standardobj)
{
//想要的最终的结果 长宽
double Angle;
if(box.size.width>box.size.height)
{
Angle =-1*box.angle;
}
else
{
Angle =90-1*box.angle;
}
Point2f center22(boxlongside/2.0, boxshortside/2.0);
Mat rot = getRotationMatrix2D(center22, Angle, 1.0);
//得到第一次旋转后的矩形
//竟然可能超出边界
Rect therect=box.boundingRect();
int rmax=therect.y+therect.height;
int cmax=therect.x+therect.width;
//超出边界的要补充图像长/宽 后续补充
//第一次旋转后的结果 长宽变了 中心点调整
//轮廓最小外接矩形的正矩形才是旋转过后的大小,注意不是轮廓的正矩形
rot.at<double>(0, 2) += (therect.width/ 2.0 - center22.x);
rot.at<double>(1, 2) += (therect.height/ 2.0 - center22.y);
//solution 3:by self
double costheta=rot.ptr<double>(0)[0];
double sintheta=rot.ptr<double>(1)[0];
double tx=rot.ptr<double>(0)[2];
double ty=rot.ptr<double>(1)[2];
double txaffine=-1*tx*costheta-ty*sintheta;
double tyaffine=-1*ty*costheta+tx*sintheta;
Mat affinematrix(2,3,CV_64FC1);
affinematrix.ptr<double>(0)[0]=costheta;
affinematrix.ptr<double>(0)[1]=sintheta;
affinematrix.ptr<double>(0)[2]=txaffine;
affinematrix.ptr<double>(1)[0]=-1*sintheta;
affinematrix.ptr<double>(1)[1]=costheta;
affinematrix.ptr<double>(1)[2]=tyaffine;
for(int j=0;j!=srcgrayimgs.size();j++)
{
Mat objgray(therect.height,therect.width,CV_8UC1,Scalar(0));
for(int r=therect.y;r!=rmax;r++)
{
for(int c=therect.x;c!=cmax;c++)
{
if(r<0 || c<0 || r>2047 || c>2447)
{
continue;
}
objgray.ptr<uchar>(r-therect.y)[c-therect.x]=(srcgrayimgs[j]).ptr<uchar>(r)[c];
}
}
Mat Rotatedback;//恢复旋转后的图片
//imwrite("problem.jpg",objgray);
warpAffine(objgray, Rotatedback, affinematrix, Size(boxlongside, boxshortside));
//imwrite("problemrotate.jpg",Rotatedback);
standardobj.push_back(Rotatedback);
}
return 0;
}
完毕。亲测OK。