Commit ff190b1e authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

Merge pull request #9802 from Nickolays:Fix#9797

parents 1a495a58 b2b56b68
...@@ -42,11 +42,7 @@ ...@@ -42,11 +42,7 @@
namespace cv namespace cv
{ {
// inner product const float EPS = 1.0e-4f;
static float innerProduct(Point2f &v1, Point2f &v2)
{
return v1.x * v2.y - v1.y * v2.x;
}
static void findCircle3pts(Point2f *pts, Point2f &center, float &radius) static void findCircle3pts(Point2f *pts, Point2f &center, float &radius)
{ {
...@@ -54,31 +50,6 @@ static void findCircle3pts(Point2f *pts, Point2f &center, float &radius) ...@@ -54,31 +50,6 @@ static void findCircle3pts(Point2f *pts, Point2f &center, float &radius)
Point2f v1 = pts[1] - pts[0]; Point2f v1 = pts[1] - pts[0];
Point2f v2 = pts[2] - pts[0]; Point2f v2 = pts[2] - pts[0];
if (innerProduct(v1, v2) == 0.0f)
{
// v1, v2 colineation, can not determine a unique circle
// find the longtest distance as diameter line
float d1 = (float)norm(pts[0] - pts[1]);
float d2 = (float)norm(pts[0] - pts[2]);
float d3 = (float)norm(pts[1] - pts[2]);
if (d1 >= d2 && d1 >= d3)
{
center = (pts[0] + pts[1]) / 2.0f;
radius = (d1 / 2.0f);
}
else if (d2 >= d1 && d2 >= d3)
{
center = (pts[0] + pts[2]) / 2.0f;
radius = (d2 / 2.0f);
}
else if (d3 >= d1 && d3 >= d2)
{
center = (pts[1] + pts[2]) / 2.0f;
radius = (d3 / 2.0f);
}
}
else
{
// center is intersection of midperpendicular lines of the two edges v1, v2 // center is intersection of midperpendicular lines of the two edges v1, v2
// a1*x + b1*y = c1 where a1 = v1.x, b1 = v1.y // a1*x + b1*y = c1 where a1 = v1.x, b1 = v1.y
// a2*x + b2*y = c2 where a2 = v2.x, b2 = v2.y // a2*x + b2*y = c2 where a2 = v2.x, b2 = v2.y
...@@ -93,33 +64,7 @@ static void findCircle3pts(Point2f *pts, Point2f &center, float &radius) ...@@ -93,33 +64,7 @@ static void findCircle3pts(Point2f *pts, Point2f &center, float &radius)
center.y = (float)cy; center.y = (float)cy;
cx -= pts[0].x; cx -= pts[0].x;
cy -= pts[0].y; cy -= pts[0].y;
radius = (float)(std::sqrt(cx *cx + cy * cy)); radius = (float)(std::sqrt(cx *cx + cy * cy)) + EPS;
}
}
const float EPS = 1.0e-4f;
static void findEnclosingCircle3pts_orLess_32f(Point2f *pts, int count, Point2f &center, float &radius)
{
switch (count)
{
case 1:
center = pts[0];
radius = 0.0f;
break;
case 2:
center.x = (pts[0].x + pts[1].x) / 2.0f;
center.y = (pts[0].y + pts[1].y) / 2.0f;
radius = (float)(norm(pts[0] - pts[1]) / 2.0);
break;
case 3:
findCircle3pts(pts, center, radius);
break;
default:
break;
}
radius += EPS;
} }
template<typename PT> template<typename PT>
...@@ -145,7 +90,7 @@ static void findThirdPoint(const PT *pts, int i, int j, Point2f &center, float & ...@@ -145,7 +90,7 @@ static void findThirdPoint(const PT *pts, int i, int j, Point2f &center, float &
ptsf[0] = (Point2f)pts[i]; ptsf[0] = (Point2f)pts[i];
ptsf[1] = (Point2f)pts[j]; ptsf[1] = (Point2f)pts[j];
ptsf[2] = (Point2f)pts[k]; ptsf[2] = (Point2f)pts[k];
findEnclosingCircle3pts_orLess_32f(ptsf, 3, center, radius); findCircle3pts(ptsf, center, radius);
} }
} }
} }
...@@ -210,8 +155,6 @@ void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radiu ...@@ -210,8 +155,6 @@ void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radiu
Mat points = _points.getMat(); Mat points = _points.getMat();
int count = points.checkVector(2); int count = points.checkVector(2);
int depth = points.depth(); int depth = points.depth();
Point2f center;
float radius = 0.f;
CV_Assert(count >= 0 && (depth == CV_32F || depth == CV_32S)); CV_Assert(count >= 0 && (depth == CV_32F || depth == CV_32S));
_center.x = _center.y = 0.f; _center.x = _center.y = 0.f;
...@@ -224,24 +167,31 @@ void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radiu ...@@ -224,24 +167,31 @@ void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radiu
const Point* ptsi = points.ptr<Point>(); const Point* ptsi = points.ptr<Point>();
const Point2f* ptsf = points.ptr<Point2f>(); const Point2f* ptsf = points.ptr<Point2f>();
// point count <= 3 switch (count)
if (count <= 3)
{ {
Point2f ptsf3[3]; case 1:
for (int i = 0; i < count; ++i)
{ {
ptsf3[i] = (is_float) ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y); _center = (is_float) ? ptsf[0] : Point2f((float)ptsi[0].x, (float)ptsi[0].y);
_radius = EPS;
break;
} }
findEnclosingCircle3pts_orLess_32f(ptsf3, count, center, radius); case 2:
_center = center; {
_radius = radius; Point2f p1 = (is_float) ? ptsf[0] : Point2f((float)ptsi[0].x, (float)ptsi[0].y);
return; Point2f p2 = (is_float) ? ptsf[1] : Point2f((float)ptsi[1].x, (float)ptsi[1].y);
_center.x = (p1.x + p2.x) / 2.0f;
_center.y = (p1.y + p2.y) / 2.0f;
_radius = (float)(norm(p1 - p2) / 2.0) + EPS;
break;
} }
default:
{
Point2f center;
float radius = 0.f;
if (is_float) if (is_float)
{ {
findMinEnclosingCircle<Point2f>(ptsf, count, center, radius); findMinEnclosingCircle<Point2f>(ptsf, count, center, radius);
#if 0 #if 0
for (size_t m = 0; m < count; ++m) for (size_t m = 0; m < count; ++m)
{ {
float d = (float)norm(ptsf[m] - center); float d = (float)norm(ptsf[m] - center);
...@@ -250,12 +200,12 @@ void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radiu ...@@ -250,12 +200,12 @@ void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radiu
printf("error!\n"); printf("error!\n");
} }
} }
#endif #endif
} }
else else
{ {
findMinEnclosingCircle<Point>(ptsi, count, center, radius); findMinEnclosingCircle<Point>(ptsi, count, center, radius);
#if 0 #if 0
for (size_t m = 0; m < count; ++m) for (size_t m = 0; m < count; ++m)
{ {
double dx = ptsi[m].x - center.x; double dx = ptsi[m].x - center.x;
...@@ -266,10 +216,13 @@ void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radiu ...@@ -266,10 +216,13 @@ void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radiu
printf("error!\n"); printf("error!\n");
} }
} }
#endif #endif
} }
_center = center; _center = center;
_radius = radius; _radius = radius;
break;
}
}
} }
......
...@@ -1017,6 +1017,62 @@ _exit_: ...@@ -1017,6 +1017,62 @@ _exit_:
return code; return code;
} }
/****************************************************************************************\
* MinEnclosingCircle Test 2 *
\****************************************************************************************/
class CV_MinCircleTest2 : public CV_BaseShapeDescrTest
{
public:
CV_MinCircleTest2();
protected:
RNG rng;
void run_func(void);
int validate_test_results( int test_case_idx );
float delta;
};
CV_MinCircleTest2::CV_MinCircleTest2()
{
rng = ts->get_rng();
}
void CV_MinCircleTest2::run_func()
{
Point2f center = Point2f(rng.uniform(0.0f, 1000.0f), rng.uniform(0.0f, 1000.0f));;
float radius = rng.uniform(0.0f, 500.0f);
float angle = (float)rng.uniform(0.0f, (float)(CV_2PI));
vector<Point2f> pts;
pts.push_back(center + Point2f(radius * cos(angle), radius * sin(angle)));
angle += (float)CV_PI;
pts.push_back(center + Point2f(radius * cos(angle), radius * sin(angle)));
float radius2 = radius * radius;
float x = rng.uniform(center.x - radius, center.x + radius);
float deltaX = x - center.x;
float upperBoundY = sqrt(radius2 - deltaX * deltaX);
float y = rng.uniform(center.y - upperBoundY, center.y + upperBoundY);
pts.push_back(Point2f(x, y));
// Find the minimum area enclosing circle
Point2f calcCenter;
float calcRadius;
minEnclosingCircle(pts, calcCenter, calcRadius);
delta = (float)norm(calcCenter - center) + abs(calcRadius - radius);
}
int CV_MinCircleTest2::validate_test_results( int test_case_idx )
{
float eps = 1.0F;
int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
if (delta > eps)
{
ts->printf( cvtest::TS::LOG, "Delta center and calcCenter > %f\n", eps );
code = cvtest::TS::FAIL_BAD_ACCURACY;
ts->set_failed_test_info( code );
}
return code;
}
/****************************************************************************************\ /****************************************************************************************\
* Perimeter Test * * Perimeter Test *
...@@ -1905,6 +1961,7 @@ TEST(Imgproc_ConvexHull, accuracy) { CV_ConvHullTest test; test.safe_run(); } ...@@ -1905,6 +1961,7 @@ TEST(Imgproc_ConvexHull, accuracy) { CV_ConvHullTest test; test.safe_run(); }
TEST(Imgproc_MinAreaRect, accuracy) { CV_MinAreaRectTest test; test.safe_run(); } TEST(Imgproc_MinAreaRect, accuracy) { CV_MinAreaRectTest test; test.safe_run(); }
TEST(Imgproc_MinTriangle, accuracy) { CV_MinTriangleTest test; test.safe_run(); } TEST(Imgproc_MinTriangle, accuracy) { CV_MinTriangleTest test; test.safe_run(); }
TEST(Imgproc_MinCircle, accuracy) { CV_MinCircleTest test; test.safe_run(); } TEST(Imgproc_MinCircle, accuracy) { CV_MinCircleTest test; test.safe_run(); }
TEST(Imgproc_MinCircle2, accuracy) { CV_MinCircleTest2 test; test.safe_run(); }
TEST(Imgproc_ContourPerimeter, accuracy) { CV_PerimeterTest test; test.safe_run(); } TEST(Imgproc_ContourPerimeter, accuracy) { CV_PerimeterTest test; test.safe_run(); }
TEST(Imgproc_FitEllipse, accuracy) { CV_FitEllipseTest test; test.safe_run(); } TEST(Imgproc_FitEllipse, accuracy) { CV_FitEllipseTest test; test.safe_run(); }
TEST(Imgproc_FitEllipse, parallel) { CV_FitEllipseParallelTest test; test.safe_run(); } TEST(Imgproc_FitEllipse, parallel) { CV_FitEllipseParallelTest test; test.safe_run(); }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment