Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
a69eeb6b
Commit
a69eeb6b
authored
Dec 08, 2015
by
songyuncen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
change the algorithm of minimum enclosing circle with EMO Welzl's method
parent
b81598bc
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
161 additions
and
174 deletions
+161
-174
shapedescr.cpp
modules/imgproc/src/shapedescr.cpp
+161
-174
No files found.
modules/imgproc/src/shapedescr.cpp
View file @
a69eeb6b
...
@@ -43,159 +43,172 @@
...
@@ -43,159 +43,172 @@
namespace
cv
namespace
cv
{
{
static
int
intersectLines
(
double
x1
,
double
dx1
,
double
y1
,
double
dy1
,
double
x2
,
double
dx2
,
double
y2
,
double
dy2
,
double
*
t2
)
{
double
d
=
dx1
*
dy2
-
dx2
*
dy1
;
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
,
// inner product
Point2f
*
center
,
float
*
radius
)
static
float
innerProduct
(
Point2f
&
v1
,
Point2f
&
v2
)
{
{
double
x1
=
(
pt0
.
x
+
pt1
.
x
)
*
0.5
;
return
v1
.
x
*
v2
.
y
-
v1
.
y
*
v2
.
x
;
double
dy1
=
pt0
.
x
-
pt1
.
x
;
double
x2
=
(
pt1
.
x
+
pt2
.
x
)
*
0.5
;
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
)
{
center
->
x
=
(
float
)
(
x2
+
dx2
*
t
);
center
->
y
=
(
float
)
(
y2
+
dy2
*
t
);
*
radius
=
(
float
)
norm
(
*
center
-
pt0
);
return
true
;
}
center
->
x
=
center
->
y
=
0.
f
;
*
radius
=
0
;
return
false
;
}
}
static
void
findCircle3pts
(
Point2f
*
pts
,
Point2f
&
center
,
float
&
radius
)
static
double
pointInCircle
(
Point2f
pt
,
Point2f
center
,
float
radius
)
{
double
dx
=
pt
.
x
-
center
.
x
;
double
dy
=
pt
.
y
-
center
.
y
;
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
}
};
// two edges of the triangle v1, v2
Point2f
v1
=
pts
[
1
]
-
pts
[
0
];
Point2f
v2
=
pts
[
2
]
-
pts
[
0
];
int
idxs
[
4
]
=
{
0
,
1
,
2
,
3
};
if
(
innerProduct
(
v1
,
v2
)
==
0.0
f
)
int
i
,
j
,
k
=
1
,
mi
=
0
;
float
max_dist
=
0.0
f
;
Point2f
center
=
pts
[
0
];
Point2f
min_center
;
float
radius
,
min_radius
=
FLT_MAX
;
Point2f
res_pts
[
4
];
const
float
eps
=
FLT_EPSILON
;
center
=
min_center
=
pts
[
0
];
radius
=
0.
f
;
for
(
i
=
0
;
i
<
4
;
i
++
)
for
(
j
=
i
+
1
;
j
<
4
;
j
++
)
{
{
float
dist
=
(
float
)
norm
(
pts
[
i
]
-
pts
[
j
]);
// v1, v2 colineation, can not determine a unique circle
// find the longtest distance as diameter line
if
(
max_dist
<
dist
)
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
)
{
{
max_dist
=
dist
;
center
=
(
pts
[
0
]
+
pts
[
1
])
/
2.0
f
;
idxs
[
0
]
=
i
;
radius
=
(
d1
/
2.0
f
);
idxs
[
1
]
=
j
;
}
}
else
if
(
d2
>=
d1
&&
d2
>=
d3
)
{
center
=
(
pts
[
0
]
+
pts
[
2
])
/
2.0
f
;
radius
=
(
d2
/
2.0
f
);
}
}
else
if
(
d3
>=
d1
&&
d3
>=
d2
)
if
(
max_dist
>
0.0
f
)
{
{
k
=
2
;
center
=
(
pts
[
1
]
+
pts
[
2
])
/
2.0
f
;
for
(
i
=
0
;
i
<
4
;
i
++
)
radius
=
(
d3
/
2.0
f
);
}
}
else
{
{
for
(
j
=
0
;
j
<
k
;
j
++
)
// center is intersection of midperpendicular lines of the two edges v1, v2
if
(
i
==
idxs
[
j
]
)
// a1*x + b1*y = c1 where a1 = v1.x, b1 = v1.y
break
;
// a2*x + b2*y = c2 where a2 = v2.x, b2 = v2.y
if
(
j
==
k
)
Point2f
midPoint1
=
(
pts
[
0
]
+
pts
[
1
])
/
2.0
f
;
idxs
[
k
++
]
=
i
;
float
c1
=
midPoint1
.
x
*
v1
.
x
+
midPoint1
.
y
*
v1
.
y
;
Point2f
midPoint2
=
(
pts
[
0
]
+
pts
[
2
])
/
2.0
f
;
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
));
}
}
}
center
=
Point2f
(
(
pts
[
idxs
[
0
]].
x
+
pts
[
idxs
[
1
]].
x
)
*
0.5
f
,
const
float
EPS
=
1.0e-4
f
;
(
pts
[
idxs
[
0
]].
y
+
pts
[
idxs
[
1
]].
y
)
*
0.5
f
);
radius
=
(
float
)(
norm
(
pts
[
idxs
[
0
]]
-
center
))
+
eps
;
if
(
pointInCircle
(
pts
[
idxs
[
2
]],
center
,
radius
)
>=
0.0
&&
static
void
findEnclosingCircle3pts_orLess_32f
(
Point2f
*
pts
,
int
count
,
Point2f
&
center
,
float
&
radius
)
pointInCircle
(
pts
[
idxs
[
3
]],
center
,
radius
)
>=
0.0
)
{
switch
(
count
)
{
{
k
=
2
;
//rand()%2+2;
case
1
:
center
=
pts
[
0
];
radius
=
0.0
f
;
break
;
case
2
:
center
.
x
=
(
pts
[
0
].
x
+
pts
[
1
].
x
)
/
2.0
f
;
center
.
y
=
(
pts
[
0
].
y
+
pts
[
1
].
y
)
/
2.0
f
;
radius
=
(
float
)(
norm
(
pts
[
0
]
-
pts
[
1
])
/
2.0
);
break
;
case
3
:
findCircle3pts
(
pts
,
center
,
radius
);
break
;
default:
break
;
}
}
else
{
radius
+=
EPS
;
mi
=
-
1
;
}
for
(
i
=
0
;
i
<
4
;
i
++
)
template
<
typename
PT
>
static
void
findThirdPoint
(
const
PT
*
pts
,
int
i
,
int
j
,
Point2f
&
center
,
float
&
radius
)
{
center
.
x
=
(
float
)(
pts
[
j
].
x
+
pts
[
i
].
x
)
/
2.0
f
;
center
.
y
=
(
float
)(
pts
[
j
].
y
+
pts
[
i
].
y
)
/
2.0
f
;
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.0
f
+
EPS
;
for
(
int
k
=
0
;
k
<
j
;
++
k
)
{
{
if
(
findCircle
(
pts
[
shuffles
[
i
][
0
]],
pts
[
shuffles
[
i
][
1
]],
dx
=
center
.
x
-
(
float
)
pts
[
k
].
x
;
pts
[
shuffles
[
i
][
2
]],
&
center
,
&
radius
)
)
dy
=
center
.
y
-
(
float
)
pts
[
k
].
y
;
if
(
norm
(
Point2f
(
dx
,
dy
))
<
radius
)
{
{
radius
+=
eps
;
continue
;
if
(
pointInCircle
(
pts
[
shuffles
[
i
][
3
]],
center
,
radius
)
>=
0.0
&&
}
min_radius
>
radius
)
else
{
{
min_radius
=
radius
;
Point2f
ptsf
[
3
];
min_center
=
center
;
ptsf
[
0
]
=
(
Point2f
)
pts
[
i
];
mi
=
i
;
ptsf
[
1
]
=
(
Point2f
)
pts
[
j
];
ptsf
[
2
]
=
(
Point2f
)
pts
[
k
];
findEnclosingCircle3pts_orLess_32f
(
ptsf
,
3
,
center
,
radius
);
}
}
}
}
}
template
<
typename
PT
>
void
findSecondPoint
(
const
PT
*
pts
,
int
i
,
Point2f
&
center
,
float
&
radius
)
{
center
.
x
=
(
float
)(
pts
[
0
].
x
+
pts
[
i
].
x
)
/
2.0
f
;
center
.
y
=
(
float
)(
pts
[
0
].
y
+
pts
[
i
].
y
)
/
2.0
f
;
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.0
f
+
EPS
;
for
(
int
j
=
1
;
j
<
i
;
++
j
)
{
float
dx
=
center
.
x
-
(
float
)
pts
[
j
].
x
;
float
dy
=
center
.
y
-
(
float
)
pts
[
j
].
y
;
if
(
norm
(
Point2f
(
dx
,
dy
))
<
radius
)
{
continue
;
}
}
CV_Assert
(
mi
>=
0
);
else
if
(
mi
<
0
)
{
mi
=
0
;
findThirdPoint
(
pts
,
i
,
j
,
center
,
radius
);
k
=
3
;
center
=
min_center
;
radius
=
min_radius
;
for
(
i
=
0
;
i
<
4
;
i
++
)
idxs
[
i
]
=
shuffles
[
mi
][
i
];
}
}
}
}
}
_center
=
center
;
_radius
=
radius
;
/* reorder output points */
template
<
typename
PT
>
for
(
i
=
0
;
i
<
4
;
i
++
)
static
void
findMinEnclosingCircle
(
const
PT
*
pts
,
int
count
,
Point2f
&
center
,
float
&
radius
)
res_pts
[
i
]
=
pts
[
idxs
[
i
]];
{
center
.
x
=
(
float
)(
pts
[
0
].
x
+
pts
[
1
].
x
)
/
2.0
f
;
center
.
y
=
(
float
)(
pts
[
0
].
y
+
pts
[
1
].
y
)
/
2.0
f
;
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.0
f
+
EPS
;
for
(
i
=
0
;
i
<
4
;
i
++
)
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
)
{
{
pts
[
i
]
=
res_pts
[
i
];
continue
;
CV_Assert
(
pointInCircle
(
pts
[
i
],
center
,
radius
)
>=
0
);
}
else
{
findSecondPoint
(
pts
,
i
,
center
,
radius
);
}
}
}
return
k
;
}
}
}
}
// 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
;
...
@@ -212,77 +225,51 @@ void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radiu
...
@@ -212,77 +225,51 @@ void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radiu
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
);
Point2f
pt
=
is_float
?
ptsf
[
0
]
:
Point2f
((
float
)
ptsi
[
0
].
x
,(
float
)
ptsi
[
0
].
y
);
Point2f
pts
[
4
]
=
{
pt
,
pt
,
pt
,
pt
};
for
(
i
=
1
;
i
<
count
;
i
++
)
// point count <= 3
if
(
count
<=
3
)
{
{
pt
=
is_float
?
ptsf
[
i
]
:
Point2f
((
float
)
ptsi
[
i
].
x
,
(
float
)
ptsi
[
i
].
y
);
Point2f
ptsf3
[
3
];
for
(
size_t
i
=
0
;
i
<
count
;
++
i
)
if
(
pt
.
x
<
pts
[
0
].
x
)
pts
[
0
]
=
pt
;
if
(
pt
.
x
>
pts
[
1
].
x
)
pts
[
1
]
=
pt
;
if
(
pt
.
y
<
pts
[
2
].
y
)
pts
[
2
]
=
pt
;
if
(
pt
.
y
>
pts
[
3
].
y
)
pts
[
3
]
=
pt
;
}
for
(
k
=
0
;
k
<
max_iters
;
k
++
)
{
{
double
min_delta
=
0
,
delta
;
ptsf3
[
i
]
=
(
is_float
)
?
ptsf
[
i
]
:
Point2f
((
float
)
ptsi
[
i
].
x
,
(
float
)
ptsi
[
i
].
y
);
Point2f
farAway
(
0
,
0
);
/*only for first iteration because the alg is repared at the loop's foot*/
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
);
delta
=
pointInCircle
(
pt
,
center
,
radius
);
if
(
delta
<
min_delta
)
{
min_delta
=
delta
;
farAway
=
pt
;
}
}
findEnclosingCircle3pts_orLess_32f
(
ptsf3
,
count
,
center
,
radius
);
_center
=
center
;
_radius
=
radius
;
return
;
}
}
result
=
min_delta
>=
0
;
if
(
result
)
break
;
Point2f
ptsCopy
[
4
];
if
(
is_float
)
// 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
<
Point2f
>
(
ptsf
,
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?
float d = (float)norm(ptsf[m] - center);
pts
[
i
]
=
farAway
;
if (d > radius)
break
;
{
printf("error!\n");
}
}
}
}
#endif
}
}
else
if
(
!
result
)
{
{
radius
=
0.
f
;
findMinEnclosingCircle
<
Point
>
(
ptsi
,
count
,
center
,
radius
);
for
(
i
=
0
;
i
<
count
;
i
++
)
#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)
{
{
pt
=
is_float
?
ptsf
[
i
]
:
Point2f
((
float
)
ptsi
[
i
].
x
,(
float
)
ptsi
[
i
].
y
);
printf("error!\n");
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
;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment