opencv 仿射变换

仿射变换的两种方式:

    1、利用变换前后的三个座标点达到变换目的。

    2、使用旋转角度和缩放倍数来变换。

 

    在实际的使用中,采用1的方式比较方便,但是有一个问题:变换之后的矩阵大小该如何正确设置,如果设置大小不合适,会导致图的实际区域超出边界。所以在此记录一下解决办法。

 

    思路:由于已知了变换前后的三个座标点,可以先求得变换的旋转角度,缩放倍数则看实际的项目需求。之后使用方法2来求个仿射变换矩阵。

//求得旋转角度

cv::Point po1;//变换前座标点1
cv::Point po2;//变换前座标点2
cv::Point po3;//变换后坐标点1
cv::Point po4;//变换后坐标点2

int x1 = po2.x - po1.x;
int y1 = po2.y - po1.y;
int x2 = po4.x - po3.x;
int y2 = po4.y - po3.y;
double d1 = atan2((double)x1, (double)y1) * (180.0 / CV_PI);
double d2 = atan2((double)x2, (double)y2) * (180.0 / CV_PI);
double angle = d1 - d2;
if (angle < 0.0)
{
	angle += 360.0;
}

//开始变换
cv::Point2f center(image.cols / 2, image.rows / 2);
double scale = 1.0;
cv::Mat warp = getRotationMatrix2D(center, angle, 1.0);

//找出变换之后图像的实际区域
int rotated_width = ceil(image.rows * fabs(sin(angle * CV_PI / 180)) + image.cols * fabs(cos(angle * CV_PI / 180)));
int rotated_height = ceil(image.cols * fabs(sin(angle * CV_PI / 180)) + image.rows * fabs(cos(angle * CV_PI / 180)));
//修改变换中心
warp.at<double>(0, 2) += (rotated_width - image.cols) / 2;
warp.at<double>(1, 2) += (rotated_height - image.rows) / 2;

cv::Mat dstImage;
warpAffine(image, dstImage, warp, cv::Size(rotated_width,rotated_height));
cv::Point top, buttom, left, right;
//搜边取出实际区域
for (int i = 0; i < dstImage.rows; i++)
{
	int flag = 0;
	for (int j = 0; j < dstImage.cols; ++j)
	{
		cv::Vec3b rgb = dstImage.at<cv::Vec3b>(i, j);
		if (rgb[0] > 0 || rgb[1] > 0 || rgb[2] > 0)
		{
			top.x = j; top.y = i;
			flag = 1;
			break;
		}
	}
	if (flag == 1)
		break;
}
for (int i = dstImage.rows - 1; i >= 0; i--)
{
	int flag = 0;
	for (int j = 0; j < dstImage.cols; j++)
	{
		cv::Vec3b rgb = dstImage.at<cv::Vec3b>(i, j);
		if (rgb[0] > 0 || rgb[1] > 0 || rgb[2] > 0)
		{
			buttom.x = j; buttom.y = i;
			flag = 1;
			break;
		}
	}
	if (flag == 1)
		break;
}
for (int i = 0; i < dstImage.cols; i++)
{
	int flag = 0;
	for (int j = 0; j < dstImage.rows; j++)
	{
		cv::Vec3b rgb = dstImage.at<cv::Vec3b>(j, i);
		if (rgb[0] > 0 || rgb[1] > 0 || rgb[2] > 0)
		{
			left.x = i; left.y = j;
			flag = 1;
			break;
		}
	}
	if (flag == 1)
		break;
}
for (int i = dstImage.cols - 1; i >= 0; i--)
{
	int flag = 0;
	for (int j = 0; j < dstImage.rows; j++)
	{
		cv::Vec3b rgb = dstImage.at<cv::Vec3b>(j, i);
		if (rgb[0] > 0 || rgb[1] > 0 || rgb[2] > 0)
		{
			right.x = i; right.y = j;
			flag = 1;
			break;
		}
	}
	if (flag == 1)
		break;
}

cv::Rect rect;
rect.x = left.x;
rect.y = top.y;
rect.width = right.x - left.x;
rect.height = buttom.y - top.y;
cv::Mat del = dstImage(rect);

//del即为变换之后图像的实际区域(去除掉黑边)

    

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章