Merge pull request #5748 from songyuncen:fix#5745
This commit is contained in:
commit
35d4f998fd
@ -43,163 +43,171 @@
|
|||||||
namespace cv
|
namespace cv
|
||||||
{
|
{
|
||||||
|
|
||||||
static int intersectLines( double x1, double dx1, double y1, double dy1,
|
// inner product
|
||||||
double x2, double dx2, double y2, double dy2, double *t2 )
|
static float innerProduct(Point2f &v1, Point2f &v2)
|
||||||
{
|
{
|
||||||
double d = dx1 * dy2 - dx2 * dy1;
|
return v1.x * v2.y - v1.y * v2.x;
|
||||||
int result = -1;
|
|
||||||
|
|
||||||
if( d != 0 )
|
|
||||||
{
|
|
||||||
*t2 = ((x2 - x1) * dy1 - (y2 - y1) * dx1) / d;
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool findCircle( Point2f pt0, Point2f pt1, Point2f pt2,
|
static void findCircle3pts(Point2f *pts, Point2f ¢er, float &radius)
|
||||||
Point2f* center, float* radius )
|
|
||||||
{
|
{
|
||||||
double x1 = (pt0.x + pt1.x) * 0.5;
|
// two edges of the triangle v1, v2
|
||||||
double dy1 = pt0.x - pt1.x;
|
Point2f v1 = pts[1] - pts[0];
|
||||||
double x2 = (pt1.x + pt2.x) * 0.5;
|
Point2f v2 = pts[2] - pts[0];
|
||||||
double dy2 = pt1.x - pt2.x;
|
|
||||||
double y1 = (pt0.y + pt1.y) * 0.5;
|
|
||||||
double dx1 = pt1.y - pt0.y;
|
|
||||||
double y2 = (pt1.y + pt2.y) * 0.5;
|
|
||||||
double dx2 = pt2.y - pt1.y;
|
|
||||||
double t = 0;
|
|
||||||
|
|
||||||
if( intersectLines( x1, dx1, y1, dy1, x2, dx2, y2, dy2, &t ) >= 0 )
|
if (innerProduct(v1, v2) == 0.0f)
|
||||||
{
|
{
|
||||||
center->x = (float) (x2 + dx2 * t);
|
// v1, v2 colineation, can not determine a unique circle
|
||||||
center->y = (float) (y2 + dy2 * t);
|
// find the longtest distance as diameter line
|
||||||
*radius = (float)norm(*center - pt0);
|
float d1 = (float)norm(pts[0] - pts[1]);
|
||||||
return true;
|
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->x = center->y = 0.f;
|
{
|
||||||
*radius = 0;
|
center = (pts[0] + pts[2]) / 2.0f;
|
||||||
return false;
|
radius = (d2 / 2.0f);
|
||||||
}
|
}
|
||||||
|
else if (d3 >= d1 && d3 >= d2)
|
||||||
|
|
||||||
static double pointInCircle( Point2f pt, Point2f center, float radius )
|
|
||||||
{
|
{
|
||||||
double dx = pt.x - center.x;
|
center = (pts[1] + pts[2]) / 2.0f;
|
||||||
double dy = pt.y - center.y;
|
radius = (d3 / 2.0f);
|
||||||
return (double)radius*radius - dx*dx - dy*dy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int findEnslosingCicle4pts_32f( Point2f* pts, Point2f& _center, float& _radius )
|
|
||||||
{
|
|
||||||
int shuffles[4][4] = { {0, 1, 2, 3}, {0, 1, 3, 2}, {2, 3, 0, 1}, {2, 3, 1, 0} };
|
|
||||||
|
|
||||||
int idxs[4] = { 0, 1, 2, 3 };
|
|
||||||
int i, j, k = 1, mi = 0;
|
|
||||||
float max_dist = 0;
|
|
||||||
Point2f center;
|
|
||||||
Point2f min_center;
|
|
||||||
float radius, min_radius = FLT_MAX;
|
|
||||||
Point2f res_pts[4];
|
|
||||||
|
|
||||||
center = min_center = pts[0];
|
|
||||||
radius = 1.f;
|
|
||||||
|
|
||||||
for( i = 0; i < 4; i++ )
|
|
||||||
for( j = i + 1; j < 4; j++ )
|
|
||||||
{
|
|
||||||
float dist = (float)norm(pts[i] - pts[j]);
|
|
||||||
|
|
||||||
if( max_dist < dist )
|
|
||||||
{
|
|
||||||
max_dist = dist;
|
|
||||||
idxs[0] = i;
|
|
||||||
idxs[1] = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( max_dist > 0 )
|
|
||||||
{
|
|
||||||
k = 2;
|
|
||||||
for( i = 0; i < 4; i++ )
|
|
||||||
{
|
|
||||||
for( j = 0; j < k; j++ )
|
|
||||||
if( i == idxs[j] )
|
|
||||||
break;
|
|
||||||
if( j == k )
|
|
||||||
idxs[k++] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
center = Point2f( (pts[idxs[0]].x + pts[idxs[1]].x)*0.5f,
|
|
||||||
(pts[idxs[0]].y + pts[idxs[1]].y)*0.5f );
|
|
||||||
radius = (float)(norm(pts[idxs[0]] - center)*1.03);
|
|
||||||
if( radius < 1.f )
|
|
||||||
radius = 1.f;
|
|
||||||
|
|
||||||
if( pointInCircle( pts[idxs[2]], center, radius ) >= 0 &&
|
|
||||||
pointInCircle( pts[idxs[3]], center, radius ) >= 0 )
|
|
||||||
{
|
|
||||||
k = 2; //rand()%2+2;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mi = -1;
|
// center is intersection of midperpendicular lines of the two edges v1, v2
|
||||||
for( i = 0; i < 4; i++ )
|
// 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)
|
||||||
{
|
{
|
||||||
if( findCircle( pts[shuffles[i][0]], pts[shuffles[i][1]],
|
switch (count)
|
||||||
pts[shuffles[i][2]], ¢er, &radius ) )
|
|
||||||
{
|
{
|
||||||
radius *= 1.03f;
|
case 1:
|
||||||
if( radius < 2.f )
|
center = pts[0];
|
||||||
radius = 2.f;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if( pointInCircle( pts[shuffles[i][3]], center, radius ) >= 0 &&
|
radius += EPS;
|
||||||
min_radius > radius )
|
}
|
||||||
|
|
||||||
|
template<typename PT>
|
||||||
|
static void findThirdPoint(const PT *pts, int i, int j, Point2f ¢er, float &radius)
|
||||||
{
|
{
|
||||||
min_radius = radius;
|
center.x = (float)(pts[j].x + pts[i].x) / 2.0f;
|
||||||
min_center = center;
|
center.y = (float)(pts[j].y + pts[i].y) / 2.0f;
|
||||||
mi = i;
|
float dx = (float)(pts[j].x - pts[i].x);
|
||||||
}
|
float dy = (float)(pts[j].y - pts[i].y);
|
||||||
}
|
radius = (float)norm(Point2f(dx, dy)) / 2.0f + EPS;
|
||||||
}
|
|
||||||
CV_Assert( mi >= 0 );
|
|
||||||
if( mi < 0 )
|
|
||||||
mi = 0;
|
|
||||||
k = 3;
|
|
||||||
center = min_center;
|
|
||||||
radius = min_radius;
|
|
||||||
for( i = 0; i < 4; i++ )
|
|
||||||
idxs[i] = shuffles[mi][i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_center = center;
|
for (int k = 0; k < j; ++k)
|
||||||
_radius = radius;
|
|
||||||
|
|
||||||
/* reorder output points */
|
|
||||||
for( i = 0; i < 4; i++ )
|
|
||||||
res_pts[i] = pts[idxs[i]];
|
|
||||||
|
|
||||||
for( i = 0; i < 4; i++ )
|
|
||||||
{
|
{
|
||||||
pts[i] = res_pts[i];
|
dx = center.x - (float)pts[k].x;
|
||||||
CV_Assert( pointInCircle( pts[i], center, radius ) >= 0 );
|
dy = center.y - (float)pts[k].y;
|
||||||
|
if (norm(Point2f(dx, dy)) < radius)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Point2f ptsf[3];
|
||||||
|
ptsf[0] = (Point2f)pts[i];
|
||||||
|
ptsf[1] = (Point2f)pts[j];
|
||||||
|
ptsf[2] = (Point2f)pts[k];
|
||||||
|
findEnclosingCircle3pts_orLess_32f(ptsf, 3, center, radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return k;
|
|
||||||
|
template<typename PT>
|
||||||
|
void findSecondPoint(const PT *pts, int i, Point2f ¢er, float &radius)
|
||||||
|
{
|
||||||
|
center.x = (float)(pts[0].x + pts[i].x) / 2.0f;
|
||||||
|
center.y = (float)(pts[0].y + pts[i].y) / 2.0f;
|
||||||
|
float dx = (float)(pts[0].x - pts[i].x);
|
||||||
|
float dy = (float)(pts[0].y - pts[i].y);
|
||||||
|
radius = (float)norm(Point2f(dx, dy)) / 2.0f + EPS;
|
||||||
|
|
||||||
|
for (int j = 1; j < i; ++j)
|
||||||
|
{
|
||||||
|
dx = center.x - (float)pts[j].x;
|
||||||
|
dy = center.y - (float)pts[j].y;
|
||||||
|
if (norm(Point2f(dx, dy)) < radius)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
findThirdPoint(pts, i, j, center, radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
template<typename PT>
|
||||||
|
static void findMinEnclosingCircle(const PT *pts, int count, Point2f ¢er, float &radius)
|
||||||
|
{
|
||||||
|
center.x = (float)(pts[0].x + pts[1].x) / 2.0f;
|
||||||
|
center.y = (float)(pts[0].y + pts[1].y) / 2.0f;
|
||||||
|
float dx = (float)(pts[0].x - pts[1].x);
|
||||||
|
float dy = (float)(pts[0].y - pts[1].y);
|
||||||
|
radius = (float)norm(Point2f(dx, dy)) / 2.0f + EPS;
|
||||||
|
|
||||||
|
for (int i = 2; i < count; ++i)
|
||||||
|
{
|
||||||
|
dx = (float)pts[i].x - center.x;
|
||||||
|
dy = (float)pts[i].y - center.y;
|
||||||
|
float d = (float)norm(Point2f(dx, dy));
|
||||||
|
if (d < radius)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
findSecondPoint(pts, i, center, radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace cv
|
||||||
|
|
||||||
|
// see Welzl, Emo. Smallest enclosing disks (balls and ellipsoids). Springer Berlin Heidelberg, 1991.
|
||||||
void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radius )
|
void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radius )
|
||||||
{
|
{
|
||||||
int max_iters = 100;
|
|
||||||
const float eps = FLT_EPSILON*2;
|
|
||||||
bool result = false;
|
|
||||||
Mat points = _points.getMat();
|
Mat points = _points.getMat();
|
||||||
int i, j, k, count = points.checkVector(2);
|
int count = points.checkVector(2);
|
||||||
int depth = points.depth();
|
int depth = points.depth();
|
||||||
Point2f center;
|
Point2f center;
|
||||||
float radius = 0.f;
|
float radius = 0.f;
|
||||||
@ -215,78 +223,50 @@ 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>();
|
||||||
|
|
||||||
Point2f pt = is_float ? ptsf[0] : Point2f((float)ptsi[0].x,(float)ptsi[0].y);
|
// point count <= 3
|
||||||
Point2f pts[4] = {pt, pt, pt, pt};
|
if (count <= 3)
|
||||||
|
|
||||||
for( i = 1; i < count; i++ )
|
|
||||||
{
|
{
|
||||||
pt = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
|
Point2f ptsf3[3];
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
if( pt.x < pts[0].x )
|
{
|
||||||
pts[0] = pt;
|
ptsf3[i] = (is_float) ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
|
||||||
if( pt.x > pts[1].x )
|
}
|
||||||
pts[1] = pt;
|
findEnclosingCircle3pts_orLess_32f(ptsf3, count, center, radius);
|
||||||
if( pt.y < pts[2].y )
|
_center = center;
|
||||||
pts[2] = pt;
|
_radius = radius;
|
||||||
if( pt.y > pts[3].y )
|
return;
|
||||||
pts[3] = pt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for( k = 0; k < max_iters; k++ )
|
if (is_float)
|
||||||
{
|
{
|
||||||
double min_delta = 0, delta;
|
findMinEnclosingCircle<Point2f>(ptsf, count, center, radius);
|
||||||
Point2f farAway(0,0);
|
#if 0
|
||||||
/*only for first iteration because the alg is repared at the loop's foot*/
|
for (size_t m = 0; m < count; ++m)
|
||||||
if( k == 0 )
|
|
||||||
findEnslosingCicle4pts_32f( pts, center, radius );
|
|
||||||
|
|
||||||
for( i = 0; i < count; i++ )
|
|
||||||
{
|
{
|
||||||
pt = is_float ? ptsf[i] : Point2f((float)ptsi[i].x,(float)ptsi[i].y);
|
float d = (float)norm(ptsf[m] - center);
|
||||||
|
if (d > radius)
|
||||||
delta = pointInCircle( pt, center, radius );
|
|
||||||
if( delta < min_delta )
|
|
||||||
{
|
{
|
||||||
min_delta = delta;
|
printf("error!\n");
|
||||||
farAway = pt;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = min_delta >= 0;
|
#endif
|
||||||
if( result )
|
}
|
||||||
break;
|
else
|
||||||
|
|
||||||
Point2f ptsCopy[4];
|
|
||||||
// find good replacement partner for the point which is at most far away,
|
|
||||||
// starting with the one that lays in the actual circle (i=3)
|
|
||||||
for( i = 3; i >= 0; i-- )
|
|
||||||
{
|
{
|
||||||
for( j = 0; j < 4; j++ )
|
findMinEnclosingCircle<Point>(ptsi, count, center, radius);
|
||||||
ptsCopy[j] = i != j ? pts[j] : farAway;
|
#if 0
|
||||||
|
for (size_t m = 0; m < count; ++m)
|
||||||
findEnslosingCicle4pts_32f( ptsCopy, center, radius );
|
|
||||||
if( pointInCircle( pts[i], center, radius ) >= 0)
|
|
||||||
{
|
{
|
||||||
// replaced one again in the new circle?
|
double dx = ptsi[m].x - center.x;
|
||||||
pts[i] = farAway;
|
double dy = ptsi[m].y - center.y;
|
||||||
break;
|
double d = std::sqrt(dx * dx + dy * dy);
|
||||||
}
|
if (d > radius)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !result )
|
|
||||||
{
|
{
|
||||||
radius = 0.f;
|
printf("error!\n");
|
||||||
for( i = 0; i < count; i++ )
|
|
||||||
{
|
|
||||||
pt = is_float ? ptsf[i] : Point2f((float)ptsi[i].x,(float)ptsi[i].y);
|
|
||||||
float dx = center.x - pt.x, dy = center.y - pt.y;
|
|
||||||
float t = dx*dx + dy*dy;
|
|
||||||
radius = MAX(radius, t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
radius = (float)(std::sqrt(radius)*(1 + eps));
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
_center = center;
|
_center = center;
|
||||||
_radius = radius;
|
_radius = radius;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user