我想扩展这个话题,提到用户Lars Schillingmann提出的这个问题和接受的答案:
Rotate an image without cropping in OpenCV in C++
我已经对添加两个"手册"的数学/几何学表示怀疑。偏移到矩阵"腐烂"这将在接受的答案(下面报告的答案代码)的评论中用作warpAffine(...)函数的输入:
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat src = cv::imread("im.png", CV_LOAD_IMAGE_UNCHANGED);
double angle = -45;
// get rotation matrix for rotating the image around its center
cv::Point2f center(src.cols/2.0, src.rows/2.0);
cv::Mat rot = cv::getRotationMatrix2D(center, angle, 1.0);
// determine bounding rectangle
cv::Rect bbox = cv::RotatedRect(center,src.size(), angle).boundingRect();
// adjust transformation matrix
rot.at<double>(0,2) += bbox.width/2.0 - center.x;
rot.at<double>(1,2) += bbox.height/2.0 - center.y;
cv::Mat dst;
cv::warpAffine(src, dst, rot, bbox.size());
cv::imwrite("rotated_im.png", dst);
return 0;
}
我对从cv :: getRotationMatrix2D(...)获得的rotationMatrix毫无疑问,这显然是正确的。
(开始参考其他人试图理解数学&#34;隐藏&#34;在此功能中,你可以跳过这个)
如果您分解opencv docs here中报告的结果矩阵的定义,您可以看到它是以下操作的结果:
1)通过Tx = -rotationCenter.x和Ty = -rotationCenter.y翻译原始图像(图像被翻译以获得给定的旋转中心到位置(0,0))(TransformationMatrix M1 - 仅翻译)
2)按照给定角度旋转已翻译的图像(并按给定因子缩放图像)(TransformationMatrix M2 - 仅旋转+缩放)
3)通过Tx = + rotationCenter.x和Ty = + rotationCenter.y将旋转后的图像平移,从而反转应用M1完成的平移。 (TransformationMatrix M3 - 仅翻译)
按给定的顺序乘以这3个矩阵(M1 * M2 * M3,你得到的是从getRotationMatrix2D得到的相同矩阵。
(其他人试图理解数学的最终参考资料&#34;隐藏&#34;在此函数内)
接受的答案然后找到rotateRect的boundingRect()以获得具有旋转的原始图像的正确尺寸的目标图像,然后在以下两行中手动添加两个偏移,这是我要求澄清的操作:
rot.at<double>(0,2) += bbox.width/2.0 - center.x;
rot.at<double>(1,2) += bbox.height/2.0 - center.y;
在向作者询问接受的答案后,我按照link(也在接受的答案中提到)来理解基础数学。该博客中给出的解释对我来说似乎没问题,但源代码(该博客文章中给出的Python示例,我需要C ++实现)似乎与接受的答案中的C ++代码有所不同。
首先计算目标图像尺寸并将目标图像中心的getRotationMatrix2d(...)作为旋转中心点,然后手动将两个偏移添加到生成的rot_mat中,但偏移量以不同的方式计算。
我将Python函数移植到C ++(下面列出的代码,我的函数也计算反转矩阵以供将来使用,忽略该部分)并在执行时获得一致的结果。我也测试了上面的代码,它似乎也给出了一个连贯的结果。
Mat rotate_about_center(Mat src, float angle, float scale, Mat& invertMat) {
// math behind this transformation is explained here:
// http://john.freml.in/opencv-rotation (with python code example)
int w = src.cols;
int h = src.rows;
float rangle = angle * CV_PI/180.0;
// now calculate new image width and height
int nw = (abs(sin(rangle)*h) + abs(cos(rangle)*w))*scale;
int nh = (abs(cos(rangle)*h) + abs(sin(rangle)*w))*scale;
// ask OpenCV for the rotation matrix
Mat rot_mat = getRotationMatrix2D(Point(nw*0.5, nh*0.5), angle, scale);
cout <<"rot_mat:\n"<< rot_mat <<endl;
// calculate the move from the old center to the new center combined
// with the rotation
Mat m = Mat(Size(3,1), CV_64FC1);
m.at<double>(0,0)=(nw-w)*0.5;
m.at<double>(0,1)=(nh-h)*0.5;
m.at<double>(0,2)=0.0;
transpose(m,m);
cout <<"m:\n"<< m <<endl;
Mat rot_move = rot_mat * m;
// the move only affects the translation, so update the translation
// part of the transform
rot_mat.at<double>(0,2) += rot_move.at<double>(0,0);
rot_mat.at<double>(1,2) += rot_move.at<double>(0,1);
Mat dst;
warpAffine(src, dst , rot_mat, Size(nw, nh));
invertAffineTransform(rot_mat, invertMat);
return dst;
}
如果这两个代码段相同,有人可以解释一下吗?如果它们是等价的,你能否解释为什么是等价的?