mirror of
https://github.com/opencv/opencv.git
synced 2025-08-06 14:36:36 +08:00
Merge pull request #26810 from MaximSmolskiy:improve-robustness-for-fitEllipseAMS
Improve robustness for fitEllipseAMS #26810 ### Pull Request Readiness Checklist Related to #26694 Added functionality to add noise to points in degenerate cases and try again for `fitEllipseAMS`. `fitEllipseNoDirect` and `fitEllipseDirect` already have this 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:
parent
ea023b72ce
commit
8ab0ad6e1b
@ -516,6 +516,7 @@ cv::RotatedRect cv::fitEllipseAMS( InputArray _points )
|
||||
Mat points = _points.getMat();
|
||||
int i, n = points.checkVector(2);
|
||||
int depth = points.depth();
|
||||
float eps = 0;
|
||||
CV_Assert( n >= 0 && (depth == CV_32F || depth == CV_32S));
|
||||
|
||||
RotatedRect box;
|
||||
@ -553,10 +554,16 @@ cv::RotatedRect cv::fitEllipseAMS( InputArray _points )
|
||||
}
|
||||
double scale = 100./(s > FLT_EPSILON ? s : (double)FLT_EPSILON);
|
||||
|
||||
// first, try the original pointset.
|
||||
// if it's singular, try to shift the points a bit
|
||||
int iter = 0;
|
||||
for( iter = 0; iter < 2; iter++ )
|
||||
{
|
||||
for( i = 0; i < n; i++ )
|
||||
{
|
||||
Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
|
||||
double px = (p.x - c.x)*scale, py = (p.y - c.y)*scale;
|
||||
const Point2f delta = getOfs(eps);
|
||||
const double px = (p.x + delta.x - c.x)*scale, py = (p.y + delta.y - c.y)*scale;
|
||||
|
||||
A.at<double>(i,0) = px*px;
|
||||
A.at<double>(i,1) = px*py;
|
||||
@ -604,6 +611,13 @@ cv::RotatedRect cv::fitEllipseAMS( InputArray _points )
|
||||
M(4,4)=DM(4,4);
|
||||
|
||||
if (fabs(cv::determinant(M)) > 1.0e-10) {
|
||||
break;
|
||||
}
|
||||
|
||||
eps = (float)(s/(n*2)*1e-2);
|
||||
}
|
||||
|
||||
if (iter < 2) {
|
||||
Mat eVal, eVec;
|
||||
eigenNonSymmetric(M, eVal, eVec);
|
||||
|
||||
|
@ -341,10 +341,10 @@ TEST(Imgproc_FitEllipseAMS_HorizontalLine, accuracy) {
|
||||
vector<Point2f> pts({{-300, 100}, {-200, 100}, {-100, 100}, {0, 100}, {100, 100}, {200, 100}, {300, 100}});
|
||||
const RotatedRect el = fitEllipseAMS(pts);
|
||||
|
||||
EXPECT_NEAR(el.center.x, -100, 100);
|
||||
EXPECT_NEAR(el.center.x, 0, 200);
|
||||
EXPECT_NEAR(el.center.y, 100, 1);
|
||||
EXPECT_NEAR(el.size.width, 1, 1);
|
||||
EXPECT_GE(el.size.height, 150);
|
||||
EXPECT_NEAR(el.size.height, 600, 100);
|
||||
EXPECT_NEAR(el.angle, 90, 0.1);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user