Merge pull request #21677 from chacha21:rectangle_intersection

* better accuracy of _rotatedRectangleIntersection

instead of just migrating to double-precision (which would work), some computations are scaled by a factor that depends on the length of the smallest vectors.
There is a better accuracy even with floats, so this is certainly better for very sensitive cases

* Update intersection.cpp

use L2SQR norm to tune the numeric scale

* Update intersection.cpp

adapt samePointEps with L2 norm

* Update intersection.cpp

move comment

* Update intersection.cpp

fix wrong numericalScalingFactor usage

* added tests

* fixed warnings returned by buildbot

* modifications suggested by reviewer

renaming numericalScaleFctor to normalizationScale
refactor some computations
more "const"

* modifications as suggested by reviewer
This commit is contained in:
Pierre Chatelier
2022-03-16 15:46:11 +01:00
committed by GitHub
parent e0ffd3e8a5
commit ef6f421f89
2 changed files with 130 additions and 26 deletions
@@ -366,6 +366,84 @@ TEST(Imgproc_RotatedRectangleIntersection, regression_12221_2)
EXPECT_LE(intersections.size(), (size_t)8);
}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_21659)
{
float scaleFactor = 1000;//to challenge the normalizationScale in the algorithm
cv::RectanglesIntersectTypes intersectionResult = cv::RectanglesIntersectTypes::INTERSECT_NONE;
std::vector<cv::Point2f> intersection;
double intersectionArea = 0;
cv::RotatedRect r1 = cv::RotatedRect(cv::Point2f(.5f, .5f)*scaleFactor, cv::Size2f(1.f, 1.f)*scaleFactor, 0);
cv::RotatedRect r2;
r2 = cv::RotatedRect(cv::Point2f(-2.f, -2.f)*scaleFactor, cv::Size2f(1.f, 1.f)*scaleFactor, 0);
intersectionResult = (cv::RectanglesIntersectTypes) cv::rotatedRectangleIntersection(r1, r2, intersection);
intersectionArea = (intersection.size() <= 2) ? 0. : cv::contourArea(intersection);
ASSERT_EQ(cv::RectanglesIntersectTypes::INTERSECT_NONE, intersectionResult);
ASSERT_LE(std::abs(intersectionArea-0), 1e-1);
r2 = cv::RotatedRect(cv::Point2f(1.5f, .5f)*scaleFactor, cv::Size2f(1.f, 2.f)*scaleFactor, 0);
intersectionResult = (cv::RectanglesIntersectTypes) cv::rotatedRectangleIntersection(r1, r2, intersection);
intersectionArea = (intersection.size() <= 2) ? 0. : cv::contourArea(intersection);
ASSERT_EQ(cv::RectanglesIntersectTypes::INTERSECT_PARTIAL, intersectionResult);
ASSERT_LE(std::abs(intersectionArea-0), 1e-1);
r2 = cv::RotatedRect(cv::Point2f(1.5f, 1.5f)*scaleFactor, cv::Size2f(1.f, 1.f)*scaleFactor, 0);
intersectionResult = (cv::RectanglesIntersectTypes) cv::rotatedRectangleIntersection(r1, r2, intersection);
intersectionArea = (intersection.size() <= 2) ? 0. : cv::contourArea(intersection);
ASSERT_EQ(cv::RectanglesIntersectTypes::INTERSECT_PARTIAL, intersectionResult);
ASSERT_LE(std::abs(intersectionArea-0), 1e-1);
r2 = cv::RotatedRect(cv::Point2f(.5f, .5f)*scaleFactor, cv::Size2f(1.f, 1.f)*scaleFactor, 0);
intersectionResult = (cv::RectanglesIntersectTypes) cv::rotatedRectangleIntersection(r1, r2, intersection);
intersectionArea = (intersection.size() <= 2) ? 0. : cv::contourArea(intersection);
ASSERT_EQ(cv::RectanglesIntersectTypes::INTERSECT_FULL, intersectionResult);
ASSERT_LE(std::abs(intersectionArea-r2.size.area()), 1e-1);
r2 = cv::RotatedRect(cv::Point2f(.5f, .5f)*scaleFactor, cv::Size2f(.5f, .5f)*scaleFactor, 0);
intersectionResult = (cv::RectanglesIntersectTypes) cv::rotatedRectangleIntersection(r1, r2, intersection);
intersectionArea = (intersection.size() <= 2) ? 0. : cv::contourArea(intersection);
ASSERT_EQ(cv::RectanglesIntersectTypes::INTERSECT_FULL, intersectionResult);
ASSERT_LE(std::abs(intersectionArea-r2.size.area()), 1e-1);
r2 = cv::RotatedRect(cv::Point2f(.5f, .5f)*scaleFactor, cv::Size2f(2.f, .5f)*scaleFactor, 0);
intersectionResult = (cv::RectanglesIntersectTypes) cv::rotatedRectangleIntersection(r1, r2, intersection);
intersectionArea = (intersection.size() <= 2) ? 0. : cv::contourArea(intersection);
ASSERT_EQ(cv::RectanglesIntersectTypes::INTERSECT_PARTIAL, intersectionResult);
ASSERT_LE(std::abs(intersectionArea-500000), 1e-1);
r2 = cv::RotatedRect(cv::Point2f(.5f, .5f)*scaleFactor, cv::Size2f(1.f, 1.f)*scaleFactor, 45);
intersectionResult = (cv::RectanglesIntersectTypes) cv::rotatedRectangleIntersection(r1, r2, intersection);
intersectionArea = (intersection.size() <= 2) ? 0. : cv::contourArea(intersection);
ASSERT_EQ(cv::RectanglesIntersectTypes::INTERSECT_PARTIAL, intersectionResult);
ASSERT_LE(std::abs(intersectionArea-828427), 1e-1);
r2 = cv::RotatedRect(cv::Point2f(1.f, 1.f)*scaleFactor, cv::Size2f(1.f, 1.f)*scaleFactor, 45);
intersectionResult = (cv::RectanglesIntersectTypes) cv::rotatedRectangleIntersection(r1, r2, intersection);
intersectionArea = (intersection.size() <= 2) ? 0. : cv::contourArea(intersection);
ASSERT_EQ(cv::RectanglesIntersectTypes::INTERSECT_PARTIAL, intersectionResult);
ASSERT_LE(std::abs(intersectionArea-250000), 1e-1);
//see #21659
r1 = cv::RotatedRect(cv::Point2f(4.48589373f, 12.5545063f), cv::Size2f(4.0f, 4.0f), 0.0347290039f);
r2 = cv::RotatedRect(cv::Point2f(4.48589373f, 12.5545235f), cv::Size2f(4.0f, 4.0f), 0.0347290039f);
intersectionResult = (cv::RectanglesIntersectTypes) cv::rotatedRectangleIntersection(r1, r2, intersection);
intersectionArea = (intersection.size() <= 2) ? 0. : cv::contourArea(intersection);
ASSERT_EQ(cv::RectanglesIntersectTypes::INTERSECT_PARTIAL, intersectionResult);
ASSERT_LE(std::abs(intersectionArea-r1.size.area()), 1e-3);
r1 = cv::RotatedRect(cv::Point2f(4.48589373f, 12.5545063f + 0.01f), cv::Size2f(4.0f, 4.0f), 0.0347290039f);
r2 = cv::RotatedRect(cv::Point2f(4.48589373f, 12.5545235f), cv::Size2f(4.0f, 4.0f), 0.0347290039f);
intersectionResult = (cv::RectanglesIntersectTypes) cv::rotatedRectangleIntersection(r1, r2, intersection);
intersectionArea = (intersection.size() <= 2) ? 0. : cv::contourArea(intersection);
ASSERT_LE(std::abs(intersectionArea-r1.size.area()), 1e-1);
r1 = cv::RotatedRect(cv::Point2f(45.0715866f, 39.8825722f), cv::Size2f(3.0f, 3.0f), 0.10067749f);
r2 = cv::RotatedRect(cv::Point2f(45.0715866f, 39.8825874f), cv::Size2f(3.0f, 3.0f), 0.10067749f);
intersectionResult = (cv::RectanglesIntersectTypes) cv::rotatedRectangleIntersection(r1, r2, intersection);
intersectionArea = (intersection.size() <= 2) ? 0. : cv::contourArea(intersection);
ASSERT_LE(std::abs(intersectionArea-r1.size.area()), 1e-3);
}
TEST(Imgproc_RotatedRectangleIntersection, regression_18520)
{
RotatedRect rr_empty(