From 7a1ec54c43715219aca5d759be910e4742d411f1 Mon Sep 17 00:00:00 2001 From: Aditya Jha <142375774+Ma-gi-cian@users.noreply.github.com> Date: Fri, 15 Aug 2025 17:35:27 +0530 Subject: [PATCH] Merge pull request #27641 from Ma-gi-cian:subdiv2d-rect2f-clean Subdiv2d rect2f clean #27641 Closes https://github.com/opencv/opencv/issues/27623 Changes: - Added Subdiv2D(Rect2f) constructor overload - Added initDelaunay(Rect2f) method overload - No changes to the previous implementation to keep it backward compatible - Added tests for init and testing with edge case of extremely small coordinates - [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 See original pull request at : https://github.com/opencv/opencv/pull/27631 --- modules/imgproc/include/opencv2/imgproc.hpp | 16 +++++- modules/imgproc/src/subdivision2d.cpp | 56 +++++++++++++++++++++ modules/imgproc/test/test_subdivision2d.cpp | 53 +++++++++++++++++++ 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 76e165fa82..69413772d3 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -1112,13 +1112,27 @@ public: */ CV_WRAP Subdiv2D(Rect rect); - /** @brief Creates a new empty Delaunay subdivision + /** @overload */ + CV_WRAP Subdiv2D(Rect2f rect); + + /** @overload + + @brief Creates a new empty Delaunay subdivision @param rect Rectangle that includes all of the 2D points that are to be added to the subdivision. */ CV_WRAP void initDelaunay(Rect rect); + /** @overload + + @brief Creates a new empty Delaunay subdivision + + @param rect Rectangle that includes all of the 2d points that are to be added to the subdivision. + + */ + CV_WRAP void initDelaunay(Rect2f rect); + /** @brief Insert a single point into a Delaunay triangulation. @param pt Point to insert. diff --git a/modules/imgproc/src/subdivision2d.cpp b/modules/imgproc/src/subdivision2d.cpp index 86a0f72852..671430ffb5 100644 --- a/modules/imgproc/src/subdivision2d.cpp +++ b/modules/imgproc/src/subdivision2d.cpp @@ -118,6 +118,16 @@ Subdiv2D::Subdiv2D(Rect rect) initDelaunay(rect); } +Subdiv2D::Subdiv2D(Rect2f rect) +{ + validGeometry = false; + freeQEdge = 0; + freePoint = 0; + recentEdge = 0; + + initDelaunay(rect); +} + Subdiv2D::QuadEdge::QuadEdge() { @@ -535,6 +545,52 @@ void Subdiv2D::initDelaunay( Rect rect ) recentEdge = edge_AB; } +void Subdiv2D::initDelaunay( Rect2f rect ) +{ + CV_INSTRUMENT_REGION(); + + float big_coord = 6.f * MAX( rect.width, rect.height ); + float rx = rect.x; + float ry = rect.y; + + vtx.clear(); + qedges.clear(); + + recentEdge = 0; + validGeometry = false; + + topLeft = Point2f( rx, ry ); + bottomRight = Point2f( rx + rect.width, ry + rect.height ); + + Point2f ppA( rx + big_coord, ry ); + Point2f ppB( rx, ry + big_coord ); + Point2f ppC( rx - big_coord, ry - big_coord ); + + vtx.push_back(Vertex()); + qedges.push_back(QuadEdge()); + + freeQEdge = 0; + freePoint = 0; + + int pA = newPoint(ppA, false); + int pB = newPoint(ppB, false); + int pC = newPoint(ppC, false); + + int edge_AB = newEdge(); + int edge_BC = newEdge(); + int edge_CA = newEdge(); + + setEdgePoints( edge_AB, pA, pB ); + setEdgePoints( edge_BC, pB, pC ); + setEdgePoints( edge_CA, pC, pA ); + + splice( edge_AB, symEdge( edge_CA )); + splice( edge_BC, symEdge( edge_AB )); + splice( edge_CA, symEdge( edge_BC )); + + recentEdge = edge_AB; +} + void Subdiv2D::clearVoronoi() { diff --git a/modules/imgproc/test/test_subdivision2d.cpp b/modules/imgproc/test/test_subdivision2d.cpp index a940adfc55..052715c7a6 100644 --- a/modules/imgproc/test/test_subdivision2d.cpp +++ b/modules/imgproc/test/test_subdivision2d.cpp @@ -64,4 +64,57 @@ TEST(Imgproc_Subdiv2D, issue_25696) { ASSERT_EQ(static_cast(2), triangles.size()); } + +// Initialization test +TEST(Imgproc_Subdiv2D, rect2f_constructor_and_init) +{ + cv::Rect2f rect_f(0.5f, 1.5f, 100.7f, 200.3f); + cv::Subdiv2D subdiv_f(rect_f); + + cv::Point2f pt1(50.2f, 80.1f); + cv::Point2f pt2(75.8f, 120.9f); + cv::Point2f pt3(25.5f, 150.3f); + + EXPECT_NO_THROW(subdiv_f.insert(pt1)); + EXPECT_NO_THROW(subdiv_f.insert(pt2)); + EXPECT_NO_THROW(subdiv_f.insert(pt3)); + + cv::Subdiv2D subdiv_init; + + EXPECT_NO_THROW(subdiv_init.initDelaunay(rect_f)); + EXPECT_NO_THROW(subdiv_init.insert(pt1)); + EXPECT_NO_THROW(subdiv_init.insert(pt2)); + EXPECT_NO_THROW(subdiv_init.insert(pt3)); + + std::vector triangles; + + EXPECT_NO_THROW(subdiv_f.getTriangleList(triangles)); + EXPECT_GT(triangles.size(), 0u); +} + +// test with small coordinates +TEST(Imgproc_Subdiv2D, rect2f_edge_cases) +{ + cv::Rect2f small_rect(0.0f, 0.0f, 0.1f, 0.1f); + cv::Subdiv2D subdiv_small(small_rect); + + cv::Point2f small_pt(0.05f, 0.05f); + EXPECT_NO_THROW(subdiv_small.insert(small_pt)); + cv::Rect2f float_rect(10.25f, 20.75f, 50.5f, 30.25f); + + cv::Subdiv2D subdiv_float(float_rect); + + cv::Point2f float_pt1(35.125f, 35.875f); + cv::Point2f float_pt2(45.375f, 25.625f); + cv::Point2f float_pt3(55.750f, 45.125f); + + EXPECT_NO_THROW(subdiv_float.insert(float_pt1)); + EXPECT_NO_THROW(subdiv_float.insert(float_pt2)); + EXPECT_NO_THROW(subdiv_float.insert(float_pt3)); + + std::vector triangles; + + subdiv_float.getTriangleList(triangles); + EXPECT_GT(triangles.size(), 0u); +} }}