计算给定两组点的相似变换矩阵?
Compute the similarity transformation matrix given two sets of points?
我知道在 OpenCV 中我们可以得到给定两组点的仿射变换getAffineTransform()
。
但是getRotationMatrix2D()
只支持预先计算的角度和比例。
如何计算给定两组点的相似变换矩阵?
有cv::estimateRigidTransform
。您可以在具有 6 个自由度(旋转、平移、缩放、剪切)的完全仿射变换或具有 5 个自由度的部分仿射变换(旋转、平移、均匀缩放)之间进行选择。
您可以使用 this answer:
中的代码计算两个 vector<Point>
p1 和 p2 的相似性变换
cv::Mat R = cv::estimateRigidTransform(p1,p2,false);
// extend rigid transformation to use perspectiveTransform:
cv::Mat H = cv::Mat(3,3,R.type());
H.at<double>(0,0) = R.at<double>(0,0);
H.at<double>(0,1) = R.at<double>(0,1);
H.at<double>(0,2) = R.at<double>(0,2);
H.at<double>(1,0) = R.at<double>(1,0);
H.at<double>(1,1) = R.at<double>(1,1);
H.at<double>(1,2) = R.at<double>(1,2);
H.at<double>(2,0) = 0.0;
H.at<double>(2,1) = 0.0;
H.at<double>(2,2) = 1.0;
// compute perspectiveTransform on p1
std::vector<cv::Point2f> result;
cv::perspectiveTransform(p1,result,H)
//warp image with transform
cv::Mat warped;
cv::warpPerspective(src,warped,H,src.size());
没试过,参考答案应该没问题。
不知何故,在我使用的 opencv 版本上使用 cv::estimateRigidTransform
时会出现一些问题,所以我编写了一个仅适用于两点的函数(这对我来说已经足够了,我相信它会更快)。
cv::Mat getSimilarityTransform(const cv::Point2f src[], const cv::Point2f dst[])
{
double src_d_y = src[0].y - src[1].y;
double src_d_x = src[0].x - src[1].x;
double src_dis = sqrt(pow(src_d_y, 2) + pow(src_d_x, 2));
double dst_d_y = dst[0].y - dst[1].y;
double dst_d_x = dst[0].x - dst[1].x;
double dst_dis = sqrt(pow(dst_d_y, 2) + pow(dst_d_x, 2));
double scale = dst_dis / src_dis;
// angle between two line segments
// ref:
double angle = atan2(src_d_y, src_d_x) - atan2(dst_d_y, dst_d_x);
double alpha = cos(angle)*scale;
double beta = sin(angle)*scale;
cv::Mat M(2, 3, CV_64F);
double* m = M.ptr<double>();
m[0] = alpha;
m[1] = beta;
// tx = x' -alpha*x -beta*y
// average of two points
m[2] = (dst[0].x - alpha*src[0].x - beta*src[0].y + dst[1].x - alpha*src[1].x - beta*src[1].y)/2;
m[3] = -beta;
m[4] = alpha;
// ty = y' +beta*x -alpha*y
// average of two points
m[5] = (dst[0].y + beta*src[0].x - alpha*src[0].y + dst[1].y + beta*src[1].x - alpha*src[1].y)/2;
return M;
}
部分结果(图片来自LFW数据集)
我知道在 OpenCV 中我们可以得到给定两组点的仿射变换getAffineTransform()
。
但是getRotationMatrix2D()
只支持预先计算的角度和比例。
如何计算给定两组点的相似变换矩阵?
有cv::estimateRigidTransform
。您可以在具有 6 个自由度(旋转、平移、缩放、剪切)的完全仿射变换或具有 5 个自由度的部分仿射变换(旋转、平移、均匀缩放)之间进行选择。
您可以使用 this answer:
中的代码计算两个vector<Point>
p1 和 p2 的相似性变换
cv::Mat R = cv::estimateRigidTransform(p1,p2,false);
// extend rigid transformation to use perspectiveTransform:
cv::Mat H = cv::Mat(3,3,R.type());
H.at<double>(0,0) = R.at<double>(0,0);
H.at<double>(0,1) = R.at<double>(0,1);
H.at<double>(0,2) = R.at<double>(0,2);
H.at<double>(1,0) = R.at<double>(1,0);
H.at<double>(1,1) = R.at<double>(1,1);
H.at<double>(1,2) = R.at<double>(1,2);
H.at<double>(2,0) = 0.0;
H.at<double>(2,1) = 0.0;
H.at<double>(2,2) = 1.0;
// compute perspectiveTransform on p1
std::vector<cv::Point2f> result;
cv::perspectiveTransform(p1,result,H)
//warp image with transform
cv::Mat warped;
cv::warpPerspective(src,warped,H,src.size());
没试过,参考答案应该没问题。
不知何故,在我使用的 opencv 版本上使用 cv::estimateRigidTransform
时会出现一些问题,所以我编写了一个仅适用于两点的函数(这对我来说已经足够了,我相信它会更快)。
cv::Mat getSimilarityTransform(const cv::Point2f src[], const cv::Point2f dst[])
{
double src_d_y = src[0].y - src[1].y;
double src_d_x = src[0].x - src[1].x;
double src_dis = sqrt(pow(src_d_y, 2) + pow(src_d_x, 2));
double dst_d_y = dst[0].y - dst[1].y;
double dst_d_x = dst[0].x - dst[1].x;
double dst_dis = sqrt(pow(dst_d_y, 2) + pow(dst_d_x, 2));
double scale = dst_dis / src_dis;
// angle between two line segments
// ref:
double angle = atan2(src_d_y, src_d_x) - atan2(dst_d_y, dst_d_x);
double alpha = cos(angle)*scale;
double beta = sin(angle)*scale;
cv::Mat M(2, 3, CV_64F);
double* m = M.ptr<double>();
m[0] = alpha;
m[1] = beta;
// tx = x' -alpha*x -beta*y
// average of two points
m[2] = (dst[0].x - alpha*src[0].x - beta*src[0].y + dst[1].x - alpha*src[1].x - beta*src[1].y)/2;
m[3] = -beta;
m[4] = alpha;
// ty = y' +beta*x -alpha*y
// average of two points
m[5] = (dst[0].y + beta*src[0].x - alpha*src[0].y + dst[1].y + beta*src[1].x - alpha*src[1].y)/2;
return M;
}
部分结果(图片来自LFW数据集)