OpenCV使用warpAffine实现图像旋转(防止切边)

原理

使用warpAffine()进行图像旋转,是基于仿射变换的原理,通常2 × \times × 3矩阵进行仿射变换:
对于二维矩阵:
X = [ x y ] X = \begin{bmatrix} x \\ y \\ \end{bmatrix} X=[xy]
进行如下变换:
T = A ⋅ [ x y ] + B T =A\cdot\begin{bmatrix} x \\ y \\ \end{bmatrix} +B T=A[xy]+B
等价于:
T = M ⋅ [ x y 1 ] T = M\cdot\begin{bmatrix} x \\ y \\ 1 \end{bmatrix} T=Mxy1
其中:

在已知 X X X T T T的情况下,还需要使用如下函数获取变换矩阵 M M M

//scale为缩放因子,angle为旋转角度(正:逆时针),(centerx,centery)为旋转中心
	getRotationMatrix2D(Point2f center, double angle, double scale)

矩阵 M M M定义:

OpenCV使用warpAffine实现图像旋转(防止切边)_第1张图片
防止切边
  • 为防止原图在旋转之后被切边,需要对getRotationMatrix2D得到的仿射变换矩阵 M M M进行一定的修改,具体是通过修改 M M M矩阵中的平移部分: b 00 b_{00} b00 b 01 b_{01} b01完成;
  • 思路:先计算out_img的图像尺寸(rotated_width和rotated_height),然后将旋转之后的图像中心由center平移至out_img中心。
  • 方法:见如下代码
// 防止切边,对平移矩阵B进行修改
rotate_matrix.at<double>(0, 2) += (rotated_width - src.cols) / 2;     
rotate_matrix.at<double>(1, 2) += (rotated_height - src.rows) / 2;  
完整代码
#include 
#include 
#include 
#include 

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
	Mat src = imread("pic.jpg");
	if (src.empty())
	{
		cout << "The image is empty, please check it!" << endl;
		return 0;
	}
	Mat out_img;

	// 旋转角度
	double angle = 45.0;

	// 计算旋转后输出图形的尺寸
	int rotated_width = ceil(src.rows * fabs(sin(angle * CV_PI / 180)) + src.cols * fabs(cos(angle * CV_PI / 180)));
	int rotated_height = ceil(src.cols * fabs(sin(angle * CV_PI / 180)) + src.rows * fabs(cos(angle * CV_PI / 180)));
	
	// 计算仿射变换矩阵
	Point2f center(src.cols / 2, src.rows / 2);
	Mat rotate_matrix = getRotationMatrix2D(center, angle, 1.0);

	// 防止切边,对平移矩阵B进行修改
	rotate_matrix.at<double>(0, 2) += (rotated_width - src.cols) / 2; 
	rotate_matrix.at<double>(1, 2) += (rotated_height - src.rows) / 2; 

	// 应用仿射变换
	warpAffine(src, out_img, rotate_matrix, Size(rotated_width, rotated_height), INTER_LINEAR, 0, Scalar(255, 255, 255));
	imshow("result", out_img);

	waitKey();
	return 0;
}

结果:

OpenCV使用warpAffine实现图像旋转(防止切边)_第2张图片

参考链接:仿射变换

你可能感兴趣的:(图像处理&OpenCV)