From 96f92c6705037a2dd3b84947bf4a62d84f889e4d Mon Sep 17 00:00:00 2001 From: Bahram Dahi Date: Wed, 15 Aug 2018 10:47:54 -0700 Subject: [PATCH 1/3] imgproc(tests): intersetion calculation of RotatedRect --- modules/imgproc/test/test_intersection.cpp | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/modules/imgproc/test/test_intersection.cpp b/modules/imgproc/test/test_intersection.cpp index 249950afea..e8ea21c47b 100644 --- a/modules/imgproc/test/test_intersection.cpp +++ b/modules/imgproc/test/test_intersection.cpp @@ -71,6 +71,8 @@ private: void test12(); void test13(); void test14(); + void test15(); + void test16(); }; static void compare(const std::vector& test, const std::vector& target) @@ -116,6 +118,8 @@ void CV_RotatedRectangleIntersectionTest::run(int) test12(); test13(); test14(); + test15(); + test16(); } void CV_RotatedRectangleIntersectionTest::test1() @@ -376,6 +380,40 @@ void CV_RotatedRectangleIntersectionTest::test14() } } +void CV_RotatedRectangleIntersectionTest::test15() +{ + RotatedRect r1( + Point2f(259.65081787109375, 51.58895492553711), + Size2f(5487.8779296875, 233.8921661376953), + -29.488616943359375); + RotatedRect r2( + Point2f(293.70465087890625, 112.10154724121094), + Size2f(5487.8896484375, 234.87368774414062), + -31.27001953125); + + std::vector intersections; + int interType = cv::rotatedRectangleIntersection(r1, r2, intersections); + EXPECT_TRUE(interType == INTERSECT_PARTIAL); + EXPECT_TRUE(intersections.size() == 8); +} + +void CV_RotatedRectangleIntersectionTest::test16() +{ + RotatedRect r1( + Point2f(239.78500366210938, 515.72021484375), + Size2f(70.23420715332031, 39.74684524536133), + -42.86162567138672); + RotatedRect r2( + Point2f(242.4205322265625, 510.1195373535156), + Size2f(66.85948944091797, 61.46455383300781), + -9.840961456298828); + + std::vector intersections; + int interType = cv::rotatedRectangleIntersection(r1, r2, intersections); + EXPECT_TRUE(interType == INTERSECT_PARTIAL); + EXPECT_TRUE(intersections.size() == 8); +} + TEST (Imgproc_RotatedRectangleIntersection, accuracy) { CV_RotatedRectangleIntersectionTest test; test.safe_run(); } }} // namespace From f89defad5d3976521a77dea2500b24438d7a7cbe Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 16 Aug 2018 14:31:29 +0300 Subject: [PATCH 2/3] imgproc: fix rotatedRectangleIntersection() --- modules/imgproc/src/intersection.cpp | 94 +++++++++++++++------- modules/imgproc/test/test_intersection.cpp | 14 ++-- 2 files changed, 73 insertions(+), 35 deletions(-) diff --git a/modules/imgproc/src/intersection.cpp b/modules/imgproc/src/intersection.cpp index 3e4a266b30..36e2073195 100644 --- a/modules/imgproc/src/intersection.cpp +++ b/modules/imgproc/src/intersection.cpp @@ -51,12 +51,13 @@ int rotatedRectangleIntersection( const RotatedRect& rect1, const RotatedRect& r { CV_INSTRUMENT_REGION() - const float samePointEps = 0.00001f; // used to test if two points are the same + // L2 metric + const float samePointEps = std::max(1e-16f, 1e-6f * (float)std::max(rect1.size.area(), rect2.size.area())); Point2f vec1[4], vec2[4]; Point2f pts1[4], pts2[4]; - std::vector intersection; + std::vector intersection; intersection.reserve(24); rect1.points(pts1); rect2.points(pts2); @@ -219,41 +220,80 @@ int rotatedRectangleIntersection( const RotatedRect& rect1, const RotatedRect& r } } - // Get rid of dupes and order points. - for( int i = 0; i < (int)intersection.size()-1; i++ ) + int N = (int)intersection.size(); + if (N == 0) { - float dx1 = intersection[i + 1].x - intersection[i].x; - float dy1 = intersection[i + 1].y - intersection[i].y; - for( size_t j = i+1; j < intersection.size(); j++ ) - { - float dx = intersection[j].x - intersection[i].x; - float dy = intersection[j].y - intersection[i].y; - double d2 = dx*dx + dy*dy; // can be a really small number, need double here + return INTERSECT_NONE; + } - if( d2 < samePointEps*samePointEps ) + // Get rid of duplicated points + int Nstride = N; + cv::AutoBuffer distPt(N * N); + cv::AutoBuffer ptDistRemap(N); + for (int i = 0; i < N; ++i) + { + const Point2f pt0 = intersection[i]; + ptDistRemap[i] = i; + for (int j = i + 1; j < N; ) + { + const Point2f pt1 = intersection[j]; + float d2 = normL2Sqr(pt1 - pt0); + if(d2 <= samePointEps) { - // Found a dupe, remove it - std::swap(intersection[j], intersection.back()); - intersection.pop_back(); - j--; // restart check + if (j < N - 1) + intersection[j] = intersection[N - 1]; + N--; + continue; } - else if (dx1 * dy - dy1 * dx < 0) + distPt[i*Nstride + j] = d2; + ++j; + } + } + while (N > 8) // we still have duplicate points after samePointEps threshold (eliminate closest points) + { + int minI = 0; + int minJ = 1; + float minD = distPt[1]; + for (int i = 0; i < N - 1; ++i) + { + float* pDist = distPt.data() + Nstride * ptDistRemap[i]; + for (int j = i + 1; j < N; ++j) + { + float d = pDist[ptDistRemap[j]]; + if (d < minD) + { + minD = d; + minI = i; + minJ = j; + } + } + } + CV_Assert(fabs(normL2Sqr(intersection[minI] - intersection[minJ]) - minD) < 1e-6); // ptDistRemap is not corrupted + // drop minJ point + if (minJ < N - 1) + { + intersection[minJ] = intersection[N - 1]; + ptDistRemap[minJ] = ptDistRemap[N - 1]; + } + N--; + } + + // order points + for (int i = 0; i < N - 1; ++i) + { + Point2f diffI = intersection[i + 1] - intersection[i]; + for (int j = i + 2; j < N; ++j) + { + Point2f diffJ = intersection[j] - intersection[i]; + if (diffI.cross(diffJ) < 0) { std::swap(intersection[i + 1], intersection[j]); - dx1 = dx; - dy1 = dy; + diffI = diffJ; } } } - if( intersection.empty() ) - { - return INTERSECT_NONE ; - } - - // If this check fails then it means we're getting dupes, increase samePointEps - CV_Assert( intersection.size() <= 8 ); - + intersection.resize(N); Mat(intersection).copyTo(intersectingRegion); return ret; diff --git a/modules/imgproc/test/test_intersection.cpp b/modules/imgproc/test/test_intersection.cpp index e8ea21c47b..0bb9b6ebf9 100644 --- a/modules/imgproc/test/test_intersection.cpp +++ b/modules/imgproc/test/test_intersection.cpp @@ -118,8 +118,6 @@ void CV_RotatedRectangleIntersectionTest::run(int) test12(); test13(); test14(); - test15(); - test16(); } void CV_RotatedRectangleIntersectionTest::test1() @@ -380,7 +378,7 @@ void CV_RotatedRectangleIntersectionTest::test14() } } -void CV_RotatedRectangleIntersectionTest::test15() +TEST(Imgproc_RotatedRectangleIntersection, regression_12221_1) { RotatedRect r1( Point2f(259.65081787109375, 51.58895492553711), @@ -393,11 +391,11 @@ void CV_RotatedRectangleIntersectionTest::test15() std::vector intersections; int interType = cv::rotatedRectangleIntersection(r1, r2, intersections); - EXPECT_TRUE(interType == INTERSECT_PARTIAL); - EXPECT_TRUE(intersections.size() == 8); + EXPECT_EQ(INTERSECT_PARTIAL, interType); + EXPECT_LE(intersections.size(), (size_t)8); } -void CV_RotatedRectangleIntersectionTest::test16() +TEST(Imgproc_RotatedRectangleIntersection, regression_12221_2) { RotatedRect r1( Point2f(239.78500366210938, 515.72021484375), @@ -410,8 +408,8 @@ void CV_RotatedRectangleIntersectionTest::test16() std::vector intersections; int interType = cv::rotatedRectangleIntersection(r1, r2, intersections); - EXPECT_TRUE(interType == INTERSECT_PARTIAL); - EXPECT_TRUE(intersections.size() == 8); + EXPECT_EQ(INTERSECT_PARTIAL, interType); + EXPECT_LE(intersections.size(), (size_t)8); } TEST (Imgproc_RotatedRectangleIntersection, accuracy) { CV_RotatedRectangleIntersectionTest test; test.safe_run(); } From 98c5ce9347566c25bf6ba9857b8c6513622283cd Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 16 Aug 2018 15:06:29 +0300 Subject: [PATCH 3/3] imgproc(test): refactor test_intersection.cpp don't use legacy test API --- modules/imgproc/test/test_intersection.cpp | 100 ++++++--------------- 1 file changed, 26 insertions(+), 74 deletions(-) diff --git a/modules/imgproc/test/test_intersection.cpp b/modules/imgproc/test/test_intersection.cpp index 0bb9b6ebf9..0e419c4702 100644 --- a/modules/imgproc/test/test_intersection.cpp +++ b/modules/imgproc/test/test_intersection.cpp @@ -49,31 +49,18 @@ namespace opencv_test { namespace { #define ACCURACY 0.00001 -class CV_RotatedRectangleIntersectionTest: public cvtest::ArrayTest -{ -public: +// See pics/intersection.png for the scenarios we are testing -protected: - void run (int); - -private: - void test1(); - void test2(); - void test3(); - void test4(); - void test5(); - void test6(); - void test7(); - void test8(); - void test9(); - void test10(); - void test11(); - void test12(); - void test13(); - void test14(); - void test15(); - void test16(); -}; +// Test the following scenarios: +// 1 - no intersection +// 2 - partial intersection, rectangle translated +// 3 - partial intersection, rectangle rotated 45 degree on the corner, forms a triangle intersection +// 4 - full intersection, rectangles of same size directly on top of each other +// 5 - partial intersection, rectangle on top rotated 45 degrees +// 6 - partial intersection, rectangle on top of different size +// 7 - full intersection, rectangle fully enclosed in the other +// 8 - partial intersection, rectangle corner just touching. point contact +// 9 - partial intersetion. rectangle side by side, line contact static void compare(const std::vector& test, const std::vector& target) { @@ -82,45 +69,12 @@ static void compare(const std::vector& test, const std::vector ASSERT_TRUE(target.size() < 4 || isContourConvex(target)); for( size_t i = 0; i < test.size(); i++ ) { - double dx = test[i].x - target[i].x; - double dy = test[i].y - target[i].y; - double r = sqrt(dx*dx + dy*dy); + double r = sqrt(normL2Sqr(test[i] - target[i])); ASSERT_LT(r, ACCURACY); } } -void CV_RotatedRectangleIntersectionTest::run(int) -{ - // See pics/intersection.png for the scenarios we are testing - - // Test the following scenarios: - // 1 - no intersection - // 2 - partial intersection, rectangle translated - // 3 - partial intersection, rectangle rotated 45 degree on the corner, forms a triangle intersection - // 4 - full intersection, rectangles of same size directly on top of each other - // 5 - partial intersection, rectangle on top rotated 45 degrees - // 6 - partial intersection, rectangle on top of different size - // 7 - full intersection, rectangle fully enclosed in the other - // 8 - partial intersection, rectangle corner just touching. point contact - // 9 - partial intersetion. rectangle side by side, line contact - - test1(); - test2(); - test3(); - test4(); - test5(); - test6(); - test7(); - test8(); - test9(); - test10(); - test11(); - test12(); - test13(); - test14(); -} - -void CV_RotatedRectangleIntersectionTest::test1() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_1) { // no intersection RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 12.0f); @@ -133,7 +87,7 @@ void CV_RotatedRectangleIntersectionTest::test1() CV_Assert(vertices.empty()); } -void CV_RotatedRectangleIntersectionTest::test2() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_2) { // partial intersection, rectangles translated RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); @@ -152,7 +106,7 @@ void CV_RotatedRectangleIntersectionTest::test2() compare(vertices, targetVertices); } -void CV_RotatedRectangleIntersectionTest::test3() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_3) { // partial intersection, rectangles rotated 45 degree on the corner, forms a triangle intersection RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); @@ -170,7 +124,7 @@ void CV_RotatedRectangleIntersectionTest::test3() compare(vertices, targetVertices); } -void CV_RotatedRectangleIntersectionTest::test4() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_4) { // full intersection, rectangles of same size directly on top of each other RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); @@ -189,7 +143,7 @@ void CV_RotatedRectangleIntersectionTest::test4() compare(vertices, targetVertices); } -void CV_RotatedRectangleIntersectionTest::test5() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_5) { // partial intersection, rectangle on top rotated 45 degrees RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); @@ -212,7 +166,7 @@ void CV_RotatedRectangleIntersectionTest::test5() compare(vertices, targetVertices); } -void CV_RotatedRectangleIntersectionTest::test6() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_6) { // 6 - partial intersection, rectangle on top of different size RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); @@ -231,7 +185,7 @@ void CV_RotatedRectangleIntersectionTest::test6() compare(vertices, targetVertices); } -void CV_RotatedRectangleIntersectionTest::test7() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_7) { // full intersection, rectangle fully enclosed in the other RotatedRect rect1(Point2f(0, 0), Size2f(12.34f, 56.78f), 0.0f); @@ -250,7 +204,7 @@ void CV_RotatedRectangleIntersectionTest::test7() compare(vertices, targetVertices); } -void CV_RotatedRectangleIntersectionTest::test8() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_8) { // intersection by a single vertex RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); @@ -263,7 +217,7 @@ void CV_RotatedRectangleIntersectionTest::test8() compare(vertices, vector(1, Point2f(1.0f, 1.0f))); } -void CV_RotatedRectangleIntersectionTest::test9() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_9) { // full intersection, rectangle fully enclosed in the other RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); @@ -280,7 +234,7 @@ void CV_RotatedRectangleIntersectionTest::test9() compare(vertices, targetVertices); } -void CV_RotatedRectangleIntersectionTest::test10() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_10) { // three points of rect2 are inside rect1. RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); @@ -300,7 +254,7 @@ void CV_RotatedRectangleIntersectionTest::test10() compare(vertices, targetVertices); } -void CV_RotatedRectangleIntersectionTest::test11() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_11) { RotatedRect rect1(Point2f(0, 0), Size2f(4, 2), 0.0f); RotatedRect rect2(Point2f(0, 0), Size2f(2, 2), -45.0f); @@ -320,7 +274,7 @@ void CV_RotatedRectangleIntersectionTest::test11() compare(vertices, targetVertices); } -void CV_RotatedRectangleIntersectionTest::test12() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_12) { RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); RotatedRect rect2(Point2f(0, 1), Size2f(1, 1), 0.0f); @@ -338,7 +292,7 @@ void CV_RotatedRectangleIntersectionTest::test12() compare(vertices, targetVertices); } -void CV_RotatedRectangleIntersectionTest::test13() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_13) { RotatedRect rect1(Point2f(0, 0), Size2f(1, 3), 0.0f); RotatedRect rect2(Point2f(0, 1), Size2f(3, 1), 0.0f); @@ -356,7 +310,7 @@ void CV_RotatedRectangleIntersectionTest::test13() compare(vertices, targetVertices); } -void CV_RotatedRectangleIntersectionTest::test14() +TEST(Imgproc_RotatedRectangleIntersection, accuracy_14) { const int kNumTests = 100; const float kWidth = 5; @@ -412,6 +366,4 @@ TEST(Imgproc_RotatedRectangleIntersection, regression_12221_2) EXPECT_LE(intersections.size(), (size_t)8); } -TEST (Imgproc_RotatedRectangleIntersection, accuracy) { CV_RotatedRectangleIntersectionTest test; test.safe_run(); } - }} // namespace