给出两组点,计算相似变换矩阵?

时间:2016-09-26 13:24:15

标签: c++ opencv graphics transformation

我知道在OpenCV中我们可以通过getAffineTransform()得到两组点来进行仿射变换。

getRotationMatrix2D()仅支持预先计算的天使和比例。

如何在给定两组点的情况下计算相似性变换矩阵?

2 个答案:

答案 0 :(得分:2)

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());

我没有尝试过,但是参考答案它应该可以正常工作。

答案 1 :(得分:2)

在某种程度上,使用我使用的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: http://stackoverflow.com/questions/3365171/calculating-the-angle-between-two-lines-without-having-to-calculate-the-slope
    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数据集的图片)
enter image description here enter image description here enter image description here enter image description here