mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
Merge pull request #28043 from dkurt:d.kurtaev/convexHull_eps
Handle near-zero convexity in convexHull #28043 ### Pull Request Readiness Checklist resolves https://github.com/opencv/opencv/issues/21482 closes https://github.com/opencv/opencv/issues/14401 Also skip a code that determines orientation inside rotatingCalipers and rely on the order after convexHull 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. - [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
@@ -76,12 +76,16 @@ static int Sklansky_( Point_<_Tp>** array, int start, int end, int* stack, int n
|
||||
|
||||
if( CV_SIGN( by ) != nsign )
|
||||
{
|
||||
_Tp ax = array[pcur]->x - array[pprev]->x;
|
||||
_Tp bx = array[pnext]->x - array[pcur]->x;
|
||||
_Tp ay = cury - array[pprev]->y;
|
||||
_DotTp convexity = (_DotTp)ay*bx - (_DotTp)ax*by; // if >0 then convex angle
|
||||
Vec<_Tp, 2> a(array[pcur]->x - array[pprev]->x, cury - array[pprev]->y);
|
||||
Vec<_Tp, 2> b(array[pnext]->x - array[pcur]->x, by);
|
||||
if (std::is_floating_point<_Tp>::value)
|
||||
{
|
||||
a = normalize(a);
|
||||
b = normalize(b);
|
||||
}
|
||||
_DotTp convexity = (_DotTp)a[1]*b[0] - (_DotTp)a[0]*b[1]; // if >0 then convex angle
|
||||
|
||||
if( CV_SIGN( convexity ) == sign2 && (ax != 0 || ay != 0) )
|
||||
if( CV_SIGN( convexity ) == sign2 && (a[0] != 0 || a[1] != 0) )
|
||||
{
|
||||
pprev = pcur;
|
||||
pcur = pnext;
|
||||
|
||||
@@ -64,6 +64,7 @@ enum { CALIPERS_MAXHEIGHT=0, CALIPERS_MINAREARECT=1, CALIPERS_MAXDIST=2 };
|
||||
// Parameters:
|
||||
// points - convex hull vertices ( any orientation )
|
||||
// n - number of vertices
|
||||
// orientation - -1 for clockwise vertices order, 1 for CCW. 0 if unknown.
|
||||
// mode - concrete application of algorithm
|
||||
// can be CV_CALIPERS_MAXDIST or
|
||||
// CV_CALIPERS_MINAREARECT
|
||||
@@ -115,7 +116,7 @@ static bool firstVecIsRight(const cv::Point2f& vec1, const cv::Point2f &vec2)
|
||||
}
|
||||
|
||||
/* we will use usual cartesian coordinates */
|
||||
static void rotatingCalipers( const Point2f* points, int n, int mode, float* out )
|
||||
static void rotatingCalipers( const Point2f* points, int n, float orientation, int mode, float* out )
|
||||
{
|
||||
float minarea = FLT_MAX;
|
||||
float max_dist = 0;
|
||||
@@ -132,7 +133,6 @@ static void rotatingCalipers( const Point2f* points, int n, int mode, float* out
|
||||
(a,b) (-b,a) (-a,-b) (b, -a)
|
||||
*/
|
||||
/* this is a first base vector (a,b) initialized by (1,0) */
|
||||
float orientation = 0;
|
||||
float base_a;
|
||||
float base_b = 0;
|
||||
|
||||
@@ -171,6 +171,7 @@ static void rotatingCalipers( const Point2f* points, int n, int mode, float* out
|
||||
}
|
||||
|
||||
// find convex hull orientation
|
||||
if (orientation == 0.f)
|
||||
{
|
||||
double ax = vect[n-1].x;
|
||||
double ay = vect[n-1].y;
|
||||
@@ -365,7 +366,8 @@ cv::RotatedRect cv::minAreaRect( InputArray _points )
|
||||
Point2f out[3];
|
||||
RotatedRect box;
|
||||
|
||||
convexHull(_points, hull, false, true);
|
||||
static const bool clockwise = false;
|
||||
convexHull(_points, hull, clockwise, true);
|
||||
|
||||
if( hull.depth() != CV_32F )
|
||||
{
|
||||
@@ -379,7 +381,7 @@ cv::RotatedRect cv::minAreaRect( InputArray _points )
|
||||
|
||||
if( n > 2 )
|
||||
{
|
||||
rotatingCalipers( hpoints, n, CALIPERS_MINAREARECT, (float*)out );
|
||||
rotatingCalipers( hpoints, n, clockwise ? -1.f : 1.f, CALIPERS_MINAREARECT, (float*)out );
|
||||
box.center.x = out[0].x + (out[1].x + out[2].x)*0.5f;
|
||||
box.center.y = out[0].y + (out[1].y + out[2].y)*0.5f;
|
||||
box.size.width = (float)std::sqrt((double)out[1].x*out[1].x + (double)out[1].y*out[1].y);
|
||||
|
||||
@@ -1232,6 +1232,39 @@ TEST(minEnclosingPolygon, pentagon)
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Imgproc_minAreaRect, reproducer_21482)
|
||||
{
|
||||
const int N = 4;
|
||||
float pts_[N][2] = {
|
||||
{ 188.8991f, 12.400669f },
|
||||
{ 80.64467f, -49.644814f },
|
||||
{ 469.59897f, 173.28242f },
|
||||
{ 690.4597f, 299.86768f },
|
||||
};
|
||||
|
||||
Mat contour(N, 1, CV_32FC2, (void*)pts_);
|
||||
|
||||
RotatedRect rr = cv::minAreaRect(contour);
|
||||
|
||||
EXPECT_TRUE(checkMinAreaRect(rr, contour)) << rr.center << " " << rr.size << " " << rr.angle;
|
||||
EXPECT_NEAR(min(rr.size.width, rr.size.height), 0, 1e-5);
|
||||
EXPECT_GE(max(rr.size.width, rr.size.height), 702);
|
||||
}
|
||||
|
||||
TEST(Imgproc_minAreaRect, reproducer_21482_small_values)
|
||||
{
|
||||
const int N = 4;
|
||||
float pts_[N][2] = { { 0.f, 0.f }, { 1e-4f, 0.f }, { 1e-4f, 1e-4f }, { 0.f, 1e-4f },};
|
||||
|
||||
Mat contour(N, 1, CV_32FC2, (void*)pts_);
|
||||
|
||||
RotatedRect rr = cv::minAreaRect(contour);
|
||||
|
||||
EXPECT_TRUE(checkMinAreaRect(rr, contour)) << rr.center << " " << rr.size << " " << rr.angle;
|
||||
EXPECT_EQ(rr.size.width, 1e-4f);
|
||||
EXPECT_EQ(rr.size.height, 1e-4f);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
/* End of file. */
|
||||
|
||||
Reference in New Issue
Block a user