OpenCV 图像仿射变换之旋转
一、知识点
1、void warpAffine(InputArray src,
OutputArray dst,
InputArray M,
Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar & borderValue = Scalar());
(1)、对图像应用仿射变换(旋转、平移、缩放)。
(2)、参数说明:
src: 输入图像。
dst: 输出图像,大小为dsize,数据类型与src相同。
M: 2 * 3转换矩阵(两行三列)。
dsize: 输出图像的大小。
flags: 插值方法,InterpolationFlags枚举值。可和WARP_INVERSE_MAP组合,意味着M是逆变换(dst-->src)。
borderMode: 边界模式,像素外推方法,BorderTypes枚举值。
borderValue: 边界值。 当borderMode为BORDER_CONSTANT时,borderValue为边界的像素颜色。
(3)、仿射变换公式:
dst(x,y) = src(M11x + M12y + M13, M21x + M22y + M23)| M11 M12 M13 | | x || | * | y || M21 M22 M23 | | 1 |
2、在OpenCV中,旋转矩阵M为:
| cosθ sinθ 0 || || -sinθ cosθ 0 |
3、在OpenCV中,平移矩阵M为:
| 1 0 dx || || 0 1 dy |
4、但是2、3的矩阵只相对于原点变换,实际工作中,经常是2、3的结合。
对于绕任意点的旋转矩阵,OpenCV中提供getRotationMatrix2D()获取。
5、Mat getRotationMatrix2D(Point2f center, double angle, double scale);
(1)、计算2D旋转的仿射矩阵,可以用来对图像进行旋转。
(2)、参数说明:
center: 源图像的旋转中心点,即源图像要围绕此点旋转。
angle: 旋转的角度,以度为单位,正值逆时针旋转,负值顺时针旋转。
scale: 缩放因子。 1.0不改变大小,0.5缩小一半,2.0放大一倍。
(3)、原点在源图像的左上角。
6、旋转后新的图像大小计算:
nw = w * cosθ + h * sinθ;nh = h * cosθ + w * sinθ;
二、示例代码
#include <iostream>
#include <opencv2/opencv.hpp>int main()
{//1.获取源图像cv::Mat src = cv::imread("../images/9.png");if (src.empty()){std::cout << "load src image error..." << std::endl;return -1;}cv::imshow("源图像", src);//2.获取源图像宽、高int w = src.cols;int h = src.rows;//3.获取围绕源图像中心点,逆时针旋转45度,不缩放的矩阵cv::Mat M = cv::getRotationMatrix2D(cv::Point2f(w / 2, h / 2), 45, 1.0);//4.仿射变换,但是旋转后图像四角被截断,并且有黑色背景cv::Mat dst1;cv::warpAffine(src, dst1, M, cv::Size(w, h));cv::imshow("绕中心点逆时针旋转45度", dst1);//5.改变旋转后图像大小,源图像四角不被截断double cosTheta = cv::abs(M.at<double>(0, 0));double sinTheta = cv::abs(M.at<double>(0, 1));int nw = w * cosTheta + h * sinTheta;int nh = h * cosTheta + w * sinTheta;M.at<double>(0, 2) += (nw / 2.0 - w / 2.0);M.at<double>(1, 2) += (nh / 2.0 - h / 2.0);cv::Mat dst2;cv::warpAffine(src, dst2, M, cv::Size(nw, nh));cv::imshow("改变大小,源图像四角不被截断", dst2);//6.填充背景cv::Scalar backColor(src.at<cv::Vec3b>(0, 0)[0], src.at<cv::Vec3b>(0, 0)[1], src.at<cv::Vec3b>(0, 0)[2]);cv::Mat dst3;cv::warpAffine(src, dst3, M, cv::Size(nw, nh), cv::INTER_LINEAR, 0, backColor);cv::imshow("填充背景", dst3);cv::waitKey(0);return 0;
}
输出结果: