diff --git a/modules/imgproc/test/test_convhull.cpp b/modules/imgproc/test/test_convhull.cpp index 49456c6cc..7e1f02bb1 100644 --- a/modules/imgproc/test/test_convhull.cpp +++ b/modules/imgproc/test/test_convhull.cpp @@ -161,6 +161,22 @@ cvTsPointPolygonTest( CvPoint2D32f pt, const CvPoint2D32f* vv, int n, int* _idx= return result; } +static cv::Point2f +cvTsMiddlePoint(const cv::Point2f &a, const cv::Point2f &b) +{ + return cv::Point2f((a.x + b.x) / 2, (a.y + b.y) / 2); +} + +static bool +cvTsIsPointOnLineSegment(const cv::Point2f &x, const cv::Point2f &a, const cv::Point2f &b) +{ + double d1 = cvTsDist(CvPoint2D32f(x.x, x.y), CvPoint2D32f(a.x, a.y)); + double d2 = cvTsDist(CvPoint2D32f(x.x, x.y), CvPoint2D32f(b.x, b.y)); + double d3 = cvTsDist(CvPoint2D32f(a.x, a.y), CvPoint2D32f(b.x, b.y)); + + return (abs(d1 + d2 - d3) <= (1E-5)); +} + /****************************************************************************************\ * Base class for shape descriptor tests * @@ -769,6 +785,146 @@ _exit_: } +/****************************************************************************************\ +* MinEnclosingTriangle Test * +\****************************************************************************************/ + +class CV_MinTriangleTest : public CV_BaseShapeDescrTest +{ +public: + CV_MinTriangleTest(); + +protected: + void run_func(void); + int validate_test_results( int test_case_idx ); + std::vector getTriangleMiddlePoints(); + + std::vector convexPolygon; + std::vector triangle; + double area; +}; + + +CV_MinTriangleTest::CV_MinTriangleTest() +{ +} + +std::vector CV_MinTriangleTest::getTriangleMiddlePoints() +{ + std::vector triangleMiddlePoints; + + for (int i = 0; i < 3; i++) { + triangleMiddlePoints.push_back(cvTsMiddlePoint(triangle[i], triangle[(i + 1) % 3])); + } + + return triangleMiddlePoints; +} + + +void CV_MinTriangleTest::run_func() +{ + std::vector pointsAsVector; + + cv::cvarrToMat(points).convertTo(pointsAsVector, CV_32F); + + cv::minEnclosingTriangle(pointsAsVector, triangle, area); + cv::convexHull(pointsAsVector, convexPolygon, true, true); +} + + +int CV_MinTriangleTest::validate_test_results( int test_case_idx ) +{ + bool errorEnclosed = false, errorMiddlePoints = false, errorFlush = true; + double eps = 1e-4; + int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx ); + +#if 0 + { + int n = 3; + double a = 8, c = 8, b = 100, d = 150; + CvPoint bp[4], *bpp = bp; + cvNamedWindow( "test", 1 ); + IplImage* img = cvCreateImage( cvSize(500,500), 8, 3 ); + cvZero(img); + for( i = 0; i < point_count; i++ ) + cvCircle(img,cvPoint(cvRound(p[i].x*a+b),cvRound(p[i].y*c+d)), 3, CV_RGB(0,255,0), -1 ); + for( i = 0; i < n; i++ ) + bp[i] = cvPoint(cvRound(triangle[i].x*a+b),cvRound(triangle[i].y*c+d)); + cvPolyLine( img, &bpp, &n, 1, 1, CV_RGB(255,255,0), 1, CV_AA, 0 ); + cvShowImage( "test", img ); + cvWaitKey(); + cvReleaseImage(&img); + } +#endif + + int polygonVertices = (int) convexPolygon.size(); + + if (polygonVertices > 2) { + // Check if all points are enclosed by the triangle + for (int i = 0; (i < polygonVertices) && (!errorEnclosed); i++) + { + if (cv::pointPolygonTest(triangle, cv::Point2f(convexPolygon[i].x, convexPolygon[i].y), true) < (-eps)) + errorEnclosed = true; + } + + // Check if triangle edges middle points touch the polygon + std::vector middlePoints = getTriangleMiddlePoints(); + + for (int i = 0; (i < 3) && (!errorMiddlePoints); i++) + { + bool isTouching = false; + + for (int j = 0; (j < polygonVertices) && (!isTouching); j++) + { + if (cvTsIsPointOnLineSegment(middlePoints[i], convexPolygon[j], + convexPolygon[(j + 1) % polygonVertices])) + isTouching = true; + } + + errorMiddlePoints = (isTouching) ? false : true; + } + + // Check if at least one of the edges is flush + for (int i = 0; (i < 3) && (errorFlush); i++) + { + for (int j = 0; (j < polygonVertices) && (errorFlush); j++) + { + if ((cvTsIsPointOnLineSegment(convexPolygon[j], triangle[i], + triangle[(i + 1) % 3])) && + (cvTsIsPointOnLineSegment(convexPolygon[(j + 1) % polygonVertices], triangle[i], + triangle[(i + 1) % 3]))) + errorFlush = false; + } + } + + // Report any found errors + if (errorEnclosed) + { + ts->printf( cvtest::TS::LOG, + "All points should be enclosed by the triangle.\n" ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + } + else if (errorMiddlePoints) + { + ts->printf( cvtest::TS::LOG, + "All triangle edges middle points should touch the convex hull of the points.\n" ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + } + else if (errorFlush) + { + ts->printf( cvtest::TS::LOG, + "At least one edge of the enclosing triangle should be flush with one edge of the polygon.\n" ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + } + } + + if ( code < 0 ) + ts->set_failed_test_info( code ); + + return code; +} + + /****************************************************************************************\ * MinEnclosingCircle Test * \****************************************************************************************/ @@ -1691,6 +1847,7 @@ void CV_PerimeterAreaSliceTest::run( int ) TEST(Imgproc_ConvexHull, accuracy) { CV_ConvHullTest test; test.safe_run(); } TEST(Imgproc_MinAreaRect, accuracy) { CV_MinAreaRectTest test; test.safe_run(); } +TEST(Imgproc_MinTriangle, accuracy) { CV_MinTriangleTest test; test.safe_run(); } TEST(Imgproc_MinCircle, accuracy) { CV_MinCircleTest test; test.safe_run(); } TEST(Imgproc_ContourPerimeter, accuracy) { CV_PerimeterTest test; test.safe_run(); } TEST(Imgproc_FitEllipse, accuracy) { CV_FitEllipseTest test; test.safe_run(); }