mirror of
https://github.com/opencv/opencv.git
synced 2025-08-06 06:26:29 +08:00
Merge pull request #26926 from MaximSmolskiy:fix-getPerspectiveTransform-for-singular-case
Fix getPerspectiveTransform for singular case #26926 ### Pull Request Readiness Checklist Fix #26916 See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
parent
87cc1643f4
commit
dbd3ef9a6f
@ -3392,7 +3392,7 @@ cv::Matx23d cv::getRotationMatrix2D_(Point2f center, double angle, double scale)
|
||||
* vi = ---------------------
|
||||
* c20*xi + c21*yi + c22
|
||||
*
|
||||
* Coefficients are calculated by solving linear system:
|
||||
* Coefficients are calculated by solving one of 2 linear systems:
|
||||
* / x0 y0 1 0 0 0 -x0*u0 -y0*u0 \ /c00\ /u0\
|
||||
* | x1 y1 1 0 0 0 -x1*u1 -y1*u1 | |c01| |u1|
|
||||
* | x2 y2 1 0 0 0 -x2*u2 -y2*u2 | |c02| |u2|
|
||||
@ -3404,12 +3404,28 @@ cv::Matx23d cv::getRotationMatrix2D_(Point2f center, double angle, double scale)
|
||||
*
|
||||
* where:
|
||||
* cij - matrix coefficients, c22 = 1
|
||||
*
|
||||
* or
|
||||
*
|
||||
* / x0 y0 1 0 0 0 -x0*u0 -y0*u0 -u0 \ /c00\ /0\
|
||||
* | x1 y1 1 0 0 0 -x1*u1 -y1*u1 -u1 | |c01| |0|
|
||||
* | x2 y2 1 0 0 0 -x2*u2 -y2*u2 -u2 | |c02| |0|
|
||||
* | x3 y3 1 0 0 0 -x3*u3 -y3*u3 -u3 |.|c10|=|0|,
|
||||
* | 0 0 0 x0 y0 1 -x0*v0 -y0*v0 -v0 | |c11| |0|
|
||||
* | 0 0 0 x1 y1 1 -x1*v1 -y1*v1 -v1 | |c12| |0|
|
||||
* | 0 0 0 x2 y2 1 -x2*v2 -y2*v2 -v2 | |c20| |0|
|
||||
* \ 0 0 0 x3 y3 1 -x3*v3 -y3*v3 -v3 / |c21| \0/
|
||||
* \c22/
|
||||
*
|
||||
* where:
|
||||
* cij - matrix coefficients, c00^2 + c01^2 + c02^2 + c10^2 + c11^2 + c12^2 + c20^2 + c21^2 + c22^2 = 1
|
||||
*/
|
||||
cv::Mat cv::getPerspectiveTransform(const Point2f src[], const Point2f dst[], int solveMethod)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
Mat M(3, 3, CV_64F), X(8, 1, CV_64F, M.ptr());
|
||||
// try c22 = 1
|
||||
Mat M(3, 3, CV_64F), X8(8, 1, CV_64F, M.ptr());
|
||||
double a[8][8], b[8];
|
||||
Mat A(8, 8, CV_64F, a), B(8, 1, CV_64F, b);
|
||||
|
||||
@ -3428,8 +3444,24 @@ cv::Mat cv::getPerspectiveTransform(const Point2f src[], const Point2f dst[], in
|
||||
b[i+4] = dst[i].y;
|
||||
}
|
||||
|
||||
solve(A, B, X, solveMethod);
|
||||
M.ptr<double>()[8] = 1.;
|
||||
if (solve(A, B, X8, solveMethod) && norm(A * X8, B) < 1e-8)
|
||||
{
|
||||
M.ptr<double>()[8] = 1.;
|
||||
|
||||
return M;
|
||||
}
|
||||
|
||||
// c00^2 + c01^2 + c02^2 + c10^2 + c11^2 + c12^2 + c20^2 + c21^2 + c22^2 = 1
|
||||
hconcat(A, -B, A);
|
||||
|
||||
Mat AtA;
|
||||
mulTransposed(A, AtA, true);
|
||||
|
||||
Mat D, U;
|
||||
SVDecomp(AtA, D, U, noArray());
|
||||
|
||||
Mat X9(9, 1, CV_64F, M.ptr());
|
||||
U.col(8).copyTo(X9);
|
||||
|
||||
return M;
|
||||
}
|
||||
|
@ -1765,5 +1765,40 @@ TEST(Imgproc_Remap, issue_23562)
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Imgproc_getPerspectiveTransform, issue_26916)
|
||||
{
|
||||
double src_data[] = {320, 512, 960, 512, 0, 1024, 1280, 1024};
|
||||
const Mat src_points(4, 2, CV_64FC1, src_data);
|
||||
|
||||
double dst_data[] = {0, 0, 1280, 0, 0, 1024, 1280, 1024};
|
||||
const Mat dst_points(4, 2, CV_64FC1, dst_data);
|
||||
|
||||
Mat src_points_f;
|
||||
src_points.convertTo(src_points_f, CV_32FC1);
|
||||
|
||||
Mat dst_points_f;
|
||||
dst_points.convertTo(dst_points_f, CV_32FC1);
|
||||
|
||||
Mat perspective_transform = getPerspectiveTransform(src_points_f, dst_points_f);
|
||||
EXPECT_NEAR(perspective_transform.at<double>(2, 2), 0, 1e-16);
|
||||
EXPECT_NEAR(cv::norm(perspective_transform), 1, 1e-14);
|
||||
|
||||
const Mat ones = Mat::ones(4, 1, CV_64FC1);
|
||||
|
||||
Mat homogeneous_src_points;
|
||||
hconcat(src_points, ones, homogeneous_src_points);
|
||||
|
||||
Mat obtained_homogeneous_dst_points = (perspective_transform * homogeneous_src_points.t()).t();
|
||||
for (int row = 0; row < 4; ++row)
|
||||
{
|
||||
obtained_homogeneous_dst_points.row(row) /= obtained_homogeneous_dst_points.at<double>(row, 2);
|
||||
}
|
||||
|
||||
Mat expected_homogeneous_dst_points;
|
||||
hconcat(dst_points, ones, expected_homogeneous_dst_points);
|
||||
|
||||
EXPECT_MAT_NEAR(obtained_homogeneous_dst_points, expected_homogeneous_dst_points, 1e-10);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
/* End of file. */
|
||||
|
Loading…
Reference in New Issue
Block a user