From 93a882d2e2b7acd9f00555851b5f5e7acc59e5c9 Mon Sep 17 00:00:00 2001 From: inayd <121136285+inayd@users.noreply.github.com> Date: Tue, 1 Oct 2024 21:17:42 +0200 Subject: [PATCH] Fix fillPoly drawing over boundaries --- modules/imgproc/src/drawing.cpp | 27 ++++------- modules/imgproc/test/test_drawing.cpp | 69 +++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 18 deletions(-) diff --git a/modules/imgproc/src/drawing.cpp b/modules/imgproc/src/drawing.cpp index 394a6d6059..c6efd4f21a 100644 --- a/modules/imgproc/src/drawing.cpp +++ b/modules/imgproc/src/drawing.cpp @@ -64,7 +64,7 @@ CollectPolyEdges( Mat& img, const Point2l* v, int npts, int shift, Point offset=Point() ); static void -FillEdgeCollection( Mat& img, std::vector& edges, const void* color, int line_type); +FillEdgeCollection( Mat& img, std::vector& edges, const void* color ); static void PolyLine( Mat& img, const Point2l* v, int npts, bool closed, @@ -1051,7 +1051,7 @@ EllipseEx( Mat& img, Point2l center, Size2l axes, v.push_back(center); std::vector edges; CollectPolyEdges( img, &v[0], (int)v.size(), edges, color, line_type, XY_SHIFT ); - FillEdgeCollection( img, edges, color, line_type ); + FillEdgeCollection( img, edges, color ); } } @@ -1299,15 +1299,11 @@ CollectPolyEdges( Mat& img, const Point2l* v, int count, std::vector& if (t0.y != t1.y) { pt0c.y = t0.y; pt1c.y = t1.y; - pt0c.x = (int64)(t0.x) << XY_SHIFT; - pt1c.x = (int64)(t1.x) << XY_SHIFT; } } - else - { - pt0c.x += XY_ONE >> 1; - pt1c.x += XY_ONE >> 1; - } + + pt0c.x = (int64)(t0.x) << XY_SHIFT; + pt1c.x = (int64)(t1.x) << XY_SHIFT; } else { @@ -1349,7 +1345,7 @@ struct CmpEdges /**************** helper macros and functions for sequence/contour processing ***********/ static void -FillEdgeCollection( Mat& img, std::vector& edges, const void* color, int line_type) +FillEdgeCollection( Mat& img, std::vector& edges, const void* color ) { PolyEdge tmp; int i, y, total = (int)edges.size(); @@ -1358,12 +1354,7 @@ FillEdgeCollection( Mat& img, std::vector& edges, const void* color, i int y_max = INT_MIN, y_min = INT_MAX; int64 x_max = 0xFFFFFFFFFFFFFFFF, x_min = 0x7FFFFFFFFFFFFFFF; int pix_size = (int)img.elemSize(); - int delta; - - if (line_type < cv::LINE_AA) - delta = 0; - else - delta = XY_ONE - 1; + int delta = XY_ONE - 1; if( total < 2 ) return; @@ -2051,7 +2042,7 @@ void fillPoly( InputOutputArray _img, const Point** pts, const int* npts, int nc } } - FillEdgeCollection(img, edges, buf, line_type); + FillEdgeCollection(img, edges, buf); } void polylines( InputOutputArray _img, const Point* const* pts, const int* npts, int ncontours, bool isClosed, @@ -2690,7 +2681,7 @@ cvDrawContours( void* _img, CvSeq* contour, } if( thickness < 0 ) - cv::FillEdgeCollection( img, edges, ext_buf, line_type); + cv::FillEdgeCollection( img, edges, ext_buf ); if( h_next && contour0 ) contour0->h_next = h_next; diff --git a/modules/imgproc/test/test_drawing.cpp b/modules/imgproc/test/test_drawing.cpp index a6b125bcd1..fb7aeb0382 100644 --- a/modules/imgproc/test/test_drawing.cpp +++ b/modules/imgproc/test/test_drawing.cpp @@ -680,6 +680,75 @@ TEST(Drawing, fillpoly_circle) EXPECT_LT(diff_fp3, 1.); } +TEST(Drawing, fillpoly_contours) +{ + const int imgSize = 50; + const int type = CV_8UC1; + const int shift = 0; + const Scalar cl = Scalar::all(255); + const cv::LineTypes lineType = LINE_8; + + // check that contours of fillPoly and polylines match + { + cv::Mat img(imgSize, imgSize, type); + img = 0; + std::vector> polygonPoints{ + { {44, 27}, {7, 37}, {7, 19}, {38, 19} } + }; + cv::fillPoly(img, polygonPoints, cl, lineType, shift); + cv::polylines(img, polygonPoints, true, 0, 1, lineType, shift); + + { + cv::Mat labelImage(img.size(), CV_32S); + int labels = cv::connectedComponents(img, labelImage, 4); + EXPECT_EQ(2, labels) << "filling went over the border"; + } + } + + // check that line generated with fillPoly and polylines match + { + cv::Mat img1(imgSize, imgSize, type), img2(imgSize, imgSize, type); + img1 = 0; + img2 = 0; + std::vector> polygonPoints{ + { {44, 27}, {38, 19} } + }; + cv::fillPoly(img1, polygonPoints, cl, lineType, shift); + cv::polylines(img2, polygonPoints, true, cl, 1, lineType, shift); + EXPECT_MAT_N_DIFF(img1, img2, 0); + } +} + +TEST(Drawing, fillpoly_match_lines) +{ + const int imgSize = 49; + const int type = CV_8UC1; + const int shift = 0; + const Scalar cl = Scalar::all(255); + const cv::LineTypes lineType = LINE_8; + cv::Mat img1(imgSize, imgSize, type), img2(imgSize, imgSize, type); + for (int x1 = 0; x1 < imgSize; x1 += imgSize / 2) + { + for (int y1 = 0; y1 < imgSize; y1 += imgSize / 2) + { + for (int x2 = 0; x2 < imgSize; x2++) + { + for (int y2 = 0; y2 < imgSize; y2++) + { + img1 = 0; + img2 = 0; + std::vector> polygonPoints{ + { {x1, y1}, {x2, y2} } + }; + cv::fillPoly(img1, polygonPoints, cl, lineType, shift); + cv::polylines(img2, polygonPoints, true, cl, 1, lineType, shift); + EXPECT_MAT_N_DIFF(img1, img2, 0); + } + } + } + } +} + TEST(Drawing, fillpoly_fully) { unsigned imageWidth = 256;