mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
Merge pull request #28163 from dkurt:d.kurtaev/convexHull_repeats
Keep convexHull output indices monotone if possible #28163 ### Pull Request Readiness Checklist resolves https://github.com/opencv/opencv/issues/24907 ? resolves https://github.com/opencv/opencv/issues/4954 See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [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. - [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
@@ -219,9 +219,9 @@ void convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool ret
|
||||
}
|
||||
|
||||
for( i = 0; i < tl_count-1; i++ )
|
||||
hullbuf[nout++] = int(pointer[tl_stack[i]] - data0);
|
||||
hullbuf[nout++] = tl_stack[i];
|
||||
for( i = tr_count - 1; i > 0; i-- )
|
||||
hullbuf[nout++] = int(pointer[tr_stack[i]] - data0);
|
||||
hullbuf[nout++] = tr_stack[i];
|
||||
int stop_idx = tr_count > 2 ? tr_stack[1] : tl_count > 2 ? tl_stack[tl_count - 2] : -1;
|
||||
|
||||
// lower half
|
||||
@@ -257,9 +257,43 @@ void convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool ret
|
||||
}
|
||||
|
||||
for( i = 0; i < bl_count-1; i++ )
|
||||
hullbuf[nout++] = int(pointer[bl_stack[i]] - data0);
|
||||
hullbuf[nout++] = bl_stack[i];
|
||||
for( i = br_count-1; i > 0; i-- )
|
||||
hullbuf[nout++] = int(pointer[br_stack[i]] - data0);
|
||||
hullbuf[nout++] = br_stack[i];
|
||||
|
||||
if (!returnPoints)
|
||||
{
|
||||
// Try keep monotonous indices in case of self-intersection.
|
||||
for (i = 0; i < nout; ++i)
|
||||
{
|
||||
auto prev = pointer[hullbuf[(i == 0 ? nout : i) - 1]];
|
||||
auto next = pointer[hullbuf[(i + 1) % nout]];
|
||||
auto cur = pointer[hullbuf[i]];
|
||||
if ((prev < cur && cur < next) || (prev > cur && cur > next))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (int j = hullbuf[i] + 1; j < total; ++j)
|
||||
{
|
||||
cur = pointer[j];
|
||||
if (*pointer[hullbuf[i]] == *cur)
|
||||
{
|
||||
if ((prev < cur && cur < next) || (prev > cur && cur > next))
|
||||
{
|
||||
hullbuf[i] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
for (i = 0; i < nout; ++i)
|
||||
{
|
||||
hullbuf[i] = int(pointer[hullbuf[i]] - data0);
|
||||
}
|
||||
|
||||
// try to make the convex hull indices form
|
||||
// an ascending or descending sequence by the cyclic
|
||||
|
||||
@@ -304,9 +304,11 @@ TEST(Imgproc_ConvexityDefects, ordering_4539)
|
||||
vector<int> hull_ind;
|
||||
vector<Vec4i> defects;
|
||||
|
||||
#if 0 // deprecated behavior
|
||||
// first, check the original contour as-is, without intermediate fillPoly/drawContours.
|
||||
convexHull(contour_, hull_ind, false, false);
|
||||
EXPECT_THROW( convexityDefects(contour_, hull_ind, defects), cv::Exception );
|
||||
#endif
|
||||
|
||||
int scale = 20;
|
||||
contour_ *= (double)scale;
|
||||
@@ -319,10 +321,12 @@ TEST(Imgproc_ConvexityDefects, ordering_4539)
|
||||
findContours(canvas_gray, contours, noArray(), RETR_LIST, CHAIN_APPROX_SIMPLE);
|
||||
convexHull(contours[0], hull_ind, false, false);
|
||||
|
||||
#if 0 // deprecated behavior
|
||||
// the original contour contains self-intersections,
|
||||
// therefore convexHull does not return a monotonous sequence of points
|
||||
// and therefore convexityDefects throws an exception
|
||||
EXPECT_THROW( convexityDefects(contours[0], hull_ind, defects), cv::Exception );
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// one way to eliminate the contour self-intersection in this particular case is to apply dilate(),
|
||||
@@ -1283,6 +1287,56 @@ INSTANTIATE_TEST_CASE_P(Imgproc, minAreaRect_of_line,
|
||||
std::make_tuple(Point2f(9, 19), Point2f(4, 7), Point2f(6.5, 13), Size2f(0, 13), -22.6198654f)
|
||||
));
|
||||
|
||||
typedef testing::TestWithParam<tuple<tuple<std::vector<Point>, Mat>, bool> > convexHull_monotonous;
|
||||
TEST_P(convexHull_monotonous, self_intersecting_contour)
|
||||
{
|
||||
std::vector<Point> contour = get<0>(get<0>(GetParam()));
|
||||
Mat ref = get<1>(get<0>(GetParam())).clone();
|
||||
bool clockwise = get<1>(GetParam());
|
||||
if (!clockwise)
|
||||
{
|
||||
std::reverse(ref.begin<int>(), ref.end<int>());
|
||||
}
|
||||
|
||||
Mat indices;
|
||||
convexHull(contour, indices, clockwise, false);
|
||||
|
||||
Point minLoc;
|
||||
minMaxLoc(indices, nullptr, nullptr, &minLoc);
|
||||
std::rotate(indices.begin<int>(), indices.begin<int>() + minLoc.y, indices.end<int>());
|
||||
|
||||
minMaxLoc(ref, nullptr, nullptr, &minLoc);
|
||||
std::rotate(ref.begin<int>(), ref.begin<int>() + minLoc.y, ref.end<int>());
|
||||
|
||||
ASSERT_EQ( cvtest::norm(indices, ref, NORM_INF), 0) << indices;
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(Imgproc, convexHull_monotonous,
|
||||
testing::Combine(
|
||||
testing::Values(
|
||||
std::make_tuple(
|
||||
std::vector<Point>{
|
||||
Point(3, 2), Point(3, 4), Point(2, 5), Point(1, 5),
|
||||
Point(2, 5), Point(3, 4), Point(6, 4), Point(6, 2)
|
||||
},
|
||||
(Mat_<int>(5, 1) << 0, 3, 4, 6, 7)
|
||||
),
|
||||
std::make_tuple(
|
||||
std::vector<Point>{
|
||||
Point(3, -2), Point(3, -4), Point(2, -5), Point(1, -5),
|
||||
Point(2, -5), Point(3, -4), Point(6, -4), Point(6, -2)
|
||||
},
|
||||
(Mat_<int>(5, 1) << 3, 0, 7, 6, 4)
|
||||
),
|
||||
std::make_tuple(
|
||||
std::vector<Point>{
|
||||
Point(1, 1), Point(1, 0), Point(0, 0), Point(1, 0), Point(0, 1)
|
||||
},
|
||||
(Mat_<int>(4, 1) << 0, 1, 2, 4)
|
||||
)
|
||||
),
|
||||
testing::Bool()
|
||||
));
|
||||
|
||||
}} // namespace
|
||||
|
||||
/* End of file. */
|
||||
|
||||
Reference in New Issue
Block a user