|
|
|
@ -43,11 +43,7 @@ |
|
|
|
|
namespace cv |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
// inner product
|
|
|
|
|
static float innerProduct(Point2f &v1, Point2f &v2) |
|
|
|
|
{ |
|
|
|
|
return v1.x * v2.y - v1.y * v2.x; |
|
|
|
|
} |
|
|
|
|
const float EPS = 1.0e-4f; |
|
|
|
|
|
|
|
|
|
static void findCircle3pts(Point2f *pts, Point2f ¢er, float &radius) |
|
|
|
|
{ |
|
|
|
@ -55,72 +51,21 @@ static void findCircle3pts(Point2f *pts, Point2f ¢er, float &radius) |
|
|
|
|
Point2f v1 = pts[1] - 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
|
|
|
|
|
// a1*x + b1*y = c1 where a1 = v1.x, b1 = v1.y
|
|
|
|
|
// a2*x + b2*y = c2 where a2 = v2.x, b2 = v2.y
|
|
|
|
|
Point2f midPoint1 = (pts[0] + pts[1]) / 2.0f; |
|
|
|
|
float c1 = midPoint1.x * v1.x + midPoint1.y * v1.y; |
|
|
|
|
Point2f midPoint2 = (pts[0] + pts[2]) / 2.0f; |
|
|
|
|
float c2 = midPoint2.x * v2.x + midPoint2.y * v2.y; |
|
|
|
|
float det = v1.x * v2.y - v1.y * v2.x; |
|
|
|
|
float cx = (c1 * v2.y - c2 * v1.y) / det; |
|
|
|
|
float cy = (v1.x * c2 - v2.x * c1) / det; |
|
|
|
|
center.x = (float)cx; |
|
|
|
|
center.y = (float)cy; |
|
|
|
|
cx -= pts[0].x; |
|
|
|
|
cy -= pts[0].y; |
|
|
|
|
radius = (float)(std::sqrt(cx *cx + cy * cy)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const float EPS = 1.0e-4f; |
|
|
|
|
|
|
|
|
|
static void findEnclosingCircle3pts_orLess_32f(Point2f *pts, int count, Point2f ¢er, 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; |
|
|
|
|
// center is intersection of midperpendicular lines of the two edges v1, v2
|
|
|
|
|
// a1*x + b1*y = c1 where a1 = v1.x, b1 = v1.y
|
|
|
|
|
// a2*x + b2*y = c2 where a2 = v2.x, b2 = v2.y
|
|
|
|
|
Point2f midPoint1 = (pts[0] + pts[1]) / 2.0f; |
|
|
|
|
float c1 = midPoint1.x * v1.x + midPoint1.y * v1.y; |
|
|
|
|
Point2f midPoint2 = (pts[0] + pts[2]) / 2.0f; |
|
|
|
|
float c2 = midPoint2.x * v2.x + midPoint2.y * v2.y; |
|
|
|
|
float det = v1.x * v2.y - v1.y * v2.x; |
|
|
|
|
float cx = (c1 * v2.y - c2 * v1.y) / det; |
|
|
|
|
float cy = (v1.x * c2 - v2.x * c1) / det; |
|
|
|
|
center.x = (float)cx; |
|
|
|
|
center.y = (float)cy; |
|
|
|
|
cx -= pts[0].x; |
|
|
|
|
cy -= pts[0].y; |
|
|
|
|
radius = (float)(std::sqrt(cx *cx + cy * cy)) + EPS; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template<typename PT> |
|
|
|
@ -146,7 +91,7 @@ static void findThirdPoint(const PT *pts, int i, int j, Point2f ¢er, float & |
|
|
|
|
ptsf[0] = (Point2f)pts[i]; |
|
|
|
|
ptsf[1] = (Point2f)pts[j]; |
|
|
|
|
ptsf[2] = (Point2f)pts[k]; |
|
|
|
|
findEnclosingCircle3pts_orLess_32f(ptsf, 3, center, radius); |
|
|
|
|
findCircle3pts(ptsf, center, radius); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -211,8 +156,6 @@ void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radiu |
|
|
|
|
Mat points = _points.getMat(); |
|
|
|
|
int count = points.checkVector(2); |
|
|
|
|
int depth = points.depth(); |
|
|
|
|
Point2f center; |
|
|
|
|
float radius = 0.f; |
|
|
|
|
CV_Assert(count >= 0 && (depth == CV_32F || depth == CV_32S)); |
|
|
|
|
|
|
|
|
|
_center.x = _center.y = 0.f; |
|
|
|
@ -225,52 +168,62 @@ void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radiu |
|
|
|
|
const Point* ptsi = points.ptr<Point>(); |
|
|
|
|
const Point2f* ptsf = points.ptr<Point2f>(); |
|
|
|
|
|
|
|
|
|
// point count <= 3
|
|
|
|
|
if (count <= 3) |
|
|
|
|
switch (count) |
|
|
|
|
{ |
|
|
|
|
Point2f ptsf3[3]; |
|
|
|
|
for (int i = 0; i < count; ++i) |
|
|
|
|
case 1: |
|
|
|
|
{ |
|
|
|
|
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); |
|
|
|
|
_center = center; |
|
|
|
|
_radius = radius; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (is_float) |
|
|
|
|
{ |
|
|
|
|
findMinEnclosingCircle<Point2f>(ptsf, count, center, radius); |
|
|
|
|
#if 0 |
|
|
|
|
for (size_t m = 0; m < count; ++m) |
|
|
|
|
case 2: |
|
|
|
|
{ |
|
|
|
|
float d = (float)norm(ptsf[m] - center); |
|
|
|
|
if (d > radius) |
|
|
|
|
{ |
|
|
|
|
printf("error!\n"); |
|
|
|
|
} |
|
|
|
|
Point2f p1 = (is_float) ? ptsf[0] : Point2f((float)ptsi[0].x, (float)ptsi[0].y); |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
findMinEnclosingCircle<Point>(ptsi, count, center, radius); |
|
|
|
|
#if 0 |
|
|
|
|
for (size_t m = 0; m < count; ++m) |
|
|
|
|
default: |
|
|
|
|
{ |
|
|
|
|
double dx = ptsi[m].x - center.x; |
|
|
|
|
double dy = ptsi[m].y - center.y; |
|
|
|
|
double d = std::sqrt(dx * dx + dy * dy); |
|
|
|
|
if (d > radius) |
|
|
|
|
Point2f center; |
|
|
|
|
float radius = 0.f; |
|
|
|
|
if (is_float) |
|
|
|
|
{ |
|
|
|
|
findMinEnclosingCircle<Point2f>(ptsf, count, center, radius); |
|
|
|
|
#if 0 |
|
|
|
|
for (size_t m = 0; m < count; ++m) |
|
|
|
|
{ |
|
|
|
|
float d = (float)norm(ptsf[m] - center); |
|
|
|
|
if (d > radius) |
|
|
|
|
{ |
|
|
|
|
printf("error!\n"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
printf("error!\n"); |
|
|
|
|
findMinEnclosingCircle<Point>(ptsi, count, center, radius); |
|
|
|
|
#if 0 |
|
|
|
|
for (size_t m = 0; m < count; ++m) |
|
|
|
|
{ |
|
|
|
|
double dx = ptsi[m].x - center.x; |
|
|
|
|
double dy = ptsi[m].y - center.y; |
|
|
|
|
double d = std::sqrt(dx * dx + dy * dy); |
|
|
|
|
if (d > radius) |
|
|
|
|
{ |
|
|
|
|
printf("error!\n"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
_center = center; |
|
|
|
|
_radius = radius; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
_center = center; |
|
|
|
|
_radius = radius; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|