旋转后的图像恢复水平

一幅图中的目标各种角度不一,想将这些小目标都摆到水平。那么就要知道旋转矩阵,然后求逆矩阵变换回去就可以。比如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。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

元气少女缘结神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值