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即爲變換之後圖像的實際區域(去除掉黑邊)

    

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