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
457fa521
Commit
457fa521
authored
Jan 18, 2013
by
Vadim Pisarevsky
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
convex hull converted to C++; other 2 functions in convhull.cpp are yet to be finished.
parent
e3941d09
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
736 additions
and
74 deletions
+736
-74
contours.cpp
modules/imgproc/src/contours.cpp
+0
-71
convhull.cpp
modules/imgproc/src/convhull.cpp
+736
-3
No files found.
modules/imgproc/src/contours.cpp
View file @
457fa521
...
...
@@ -1813,77 +1813,6 @@ double cv::matchShapes( InputArray _contour1,
}
void
cv
::
convexHull
(
InputArray
_points
,
OutputArray
_hull
,
bool
clockwise
,
bool
returnPoints
)
{
Mat
points
=
_points
.
getMat
();
int
nelems
=
points
.
checkVector
(
2
),
depth
=
points
.
depth
();
CV_Assert
(
nelems
>=
0
&&
(
depth
==
CV_32F
||
depth
==
CV_32S
));
if
(
nelems
==
0
)
{
_hull
.
release
();
return
;
}
returnPoints
=
!
_hull
.
fixedType
()
?
returnPoints
:
_hull
.
type
()
!=
CV_32S
;
Mat
hull
(
nelems
,
1
,
returnPoints
?
CV_MAKETYPE
(
depth
,
2
)
:
CV_32S
);
CvMat
_cpoints
=
points
,
_chull
=
hull
;
cvConvexHull2
(
&
_cpoints
,
&
_chull
,
clockwise
?
CV_CLOCKWISE
:
CV_COUNTER_CLOCKWISE
,
returnPoints
);
_hull
.
create
(
_chull
.
rows
,
1
,
hull
.
type
(),
-
1
,
true
);
Mat
dhull
=
_hull
.
getMat
(),
shull
(
dhull
.
size
(),
dhull
.
type
(),
hull
.
data
);
shull
.
copyTo
(
dhull
);
}
void
cv
::
convexityDefects
(
InputArray
_points
,
InputArray
_hull
,
OutputArray
_defects
)
{
Mat
points
=
_points
.
getMat
();
int
ptnum
=
points
.
checkVector
(
2
,
CV_32S
);
CV_Assert
(
ptnum
>
3
);
Mat
hull
=
_hull
.
getMat
();
CV_Assert
(
hull
.
checkVector
(
1
,
CV_32S
)
>
2
);
Ptr
<
CvMemStorage
>
storage
=
cvCreateMemStorage
();
CvMat
c_points
=
points
,
c_hull
=
hull
;
CvSeq
*
seq
=
cvConvexityDefects
(
&
c_points
,
&
c_hull
,
storage
);
int
i
,
n
=
seq
->
total
;
if
(
n
==
0
)
{
_defects
.
release
();
return
;
}
_defects
.
create
(
n
,
1
,
CV_32SC4
);
Mat
defects
=
_defects
.
getMat
();
SeqIterator
<
CvConvexityDefect
>
it
=
Seq
<
CvConvexityDefect
>
(
seq
).
begin
();
CvPoint
*
ptorg
=
(
CvPoint
*
)
points
.
data
;
for
(
i
=
0
;
i
<
n
;
i
++
,
++
it
)
{
CvConvexityDefect
&
d
=
*
it
;
int
idx0
=
(
int
)(
d
.
start
-
ptorg
);
int
idx1
=
(
int
)(
d
.
end
-
ptorg
);
int
idx2
=
(
int
)(
d
.
depth_point
-
ptorg
);
CV_Assert
(
0
<=
idx0
&&
idx0
<
ptnum
);
CV_Assert
(
0
<=
idx1
&&
idx1
<
ptnum
);
CV_Assert
(
0
<=
idx2
&&
idx2
<
ptnum
);
CV_Assert
(
d
.
depth
>=
0
);
int
idepth
=
cvRound
(
d
.
depth
*
256
);
defects
.
at
<
Vec4i
>
(
i
)
=
Vec4i
(
idx0
,
idx1
,
idx2
,
idepth
);
}
}
bool
cv
::
isContourConvex
(
InputArray
_contour
)
{
Mat
contour
=
_contour
.
getMat
();
CV_Assert
(
contour
.
checkVector
(
2
)
>=
0
&&
(
contour
.
depth
()
==
CV_32F
||
contour
.
depth
()
==
CV_32S
));
CvMat
c
=
Mat
(
contour
);
return
cvCheckContourConvexity
(
&
c
)
>
0
;
}
cv
::
RotatedRect
cv
::
fitEllipse
(
InputArray
_points
)
{
...
...
modules/imgproc/src/convhull.cpp
View file @
457fa521
...
...
@@ -40,7 +40,9 @@
//M*/
#include "precomp.hpp"
#include <iostream>
#if 0
static int
icvSklansky_32s( CvPoint** array, int start, int end, int* stack, int nsign, int sign2 )
{
...
...
@@ -113,7 +115,6 @@ icvSklansky_32s( CvPoint** array, int start, int end, int* stack, int nsign, int
return --stacksize;
}
static int
icvSklansky_32f( CvPoint2D32f** array, int start, int end, int* stack, int nsign, int sign2 )
{
...
...
@@ -751,7 +752,7 @@ cvCheckContourConvexity( const CvArr* array )
dydx0 = dy * dx0;
/* find orientation */
/*orient = -dy0 * dx + dx0 * dy;
/*
orient = -dy0 * dx + dx0 * dy;
orientation |= (orient > 0) ? 1 : 2;
*/
orientation |= (dydx0 > dxdy0) ? 1 : ((dydx0 < dxdy0) ? 2 : 3);
...
...
@@ -792,7 +793,7 @@ cvCheckContourConvexity( const CvArr* array )
dydx0 = dy * dx0;
/* find orientation */
/*orient = -dy0 * dx + dx0 * dy;
/*
orient = -dy0 * dx + dx0 * dy;
orientation |= (orient > 0) ? 1 : 2;
*/
orientation |= (dydx0 > dxdy0) ? 1 : ((dydx0 < dxdy0) ? 2 : 3);
...
...
@@ -811,5 +812,737 @@ cvCheckContourConvexity( const CvArr* array )
return flag;
}
void cv::convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool returnPoints )
{
Mat points = _points.getMat();
int nelems = points.checkVector(2), depth = points.depth();
CV_Assert(nelems >= 0 && (depth == CV_32F || depth == CV_32S));
if( nelems == 0 )
{
_hull.release();
return;
}
returnPoints = !_hull.fixedType() ? returnPoints : _hull.type() != CV_32S;
Mat hull(nelems, 1, returnPoints ? CV_MAKETYPE(depth, 2) : CV_32S);
CvMat _cpoints = points, _chull = hull;
cvConvexHull2(&_cpoints, &_chull, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, returnPoints);
_hull.create(_chull.rows, 1, hull.type(), -1, true);
Mat dhull = _hull.getMat(), shull(dhull.size(), dhull.type(), hull.data);
shull.copyTo(dhull);
std::cout << "convex hull: " << dhull;
}
#else
namespace
cv
{
template
<
typename
_Tp
>
static
int
Sklansky_
(
Point_
<
_Tp
>**
array
,
int
start
,
int
end
,
int
*
stack
,
int
nsign
,
int
sign2
)
{
int
incr
=
end
>
start
?
1
:
-
1
;
// prepare first triangle
int
pprev
=
start
,
pcur
=
pprev
+
incr
,
pnext
=
pcur
+
incr
;
int
stacksize
=
3
;
if
(
start
==
end
||
(
array
[
start
]
->
x
==
array
[
end
]
->
x
&&
array
[
start
]
->
y
==
array
[
end
]
->
y
)
)
{
stack
[
0
]
=
start
;
return
1
;
}
stack
[
0
]
=
pprev
;
stack
[
1
]
=
pcur
;
stack
[
2
]
=
pnext
;
end
+=
incr
;
// make end = afterend
while
(
pnext
!=
end
)
{
// check the angle p1,p2,p3
_Tp
cury
=
array
[
pcur
]
->
y
;
_Tp
nexty
=
array
[
pnext
]
->
y
;
_Tp
by
=
nexty
-
cury
;
if
(
CV_SIGN
(
by
)
!=
nsign
)
{
_Tp
ax
=
array
[
pcur
]
->
x
-
array
[
pprev
]
->
x
;
_Tp
bx
=
array
[
pnext
]
->
x
-
array
[
pcur
]
->
x
;
_Tp
ay
=
cury
-
array
[
pprev
]
->
y
;
_Tp
convexity
=
ay
*
bx
-
ax
*
by
;
// if >0 then convex angle
if
(
CV_SIGN
(
convexity
)
==
sign2
&&
(
ax
!=
0
||
ay
!=
0
)
)
{
pprev
=
pcur
;
pcur
=
pnext
;
pnext
+=
incr
;
stack
[
stacksize
]
=
pnext
;
stacksize
++
;
}
else
{
if
(
pprev
==
start
)
{
pcur
=
pnext
;
stack
[
1
]
=
pcur
;
pnext
+=
incr
;
stack
[
2
]
=
pnext
;
}
else
{
stack
[
stacksize
-
2
]
=
pnext
;
pcur
=
pprev
;
pprev
=
stack
[
stacksize
-
4
];
stacksize
--
;
}
}
}
else
{
pnext
+=
incr
;
stack
[
stacksize
-
1
]
=
pnext
;
}
}
return
--
stacksize
;
}
template
<
typename
_Tp
>
struct
CHullCmpPoints
{
bool
operator
()(
const
Point_
<
_Tp
>*
p1
,
const
Point_
<
_Tp
>*
p2
)
const
{
return
p1
->
x
<
p2
->
x
||
(
p1
->
x
==
p2
->
x
&&
p1
->
y
<
p2
->
y
);
}
};
void
convexityDefects
(
InputArray
_points
,
InputArray
_hull
,
OutputArray
_defects
)
{
Mat
points
=
_points
.
getMat
();
int
ptnum
=
points
.
checkVector
(
2
,
CV_32S
);
CV_Assert
(
ptnum
>
3
);
Mat
hull
=
_hull
.
getMat
();
CV_Assert
(
hull
.
checkVector
(
1
,
CV_32S
)
>
2
);
Ptr
<
CvMemStorage
>
storage
=
cvCreateMemStorage
();
CvMat
c_points
=
points
,
c_hull
=
hull
;
CvSeq
*
seq
=
cvConvexityDefects
(
&
c_points
,
&
c_hull
,
storage
);
int
i
,
n
=
seq
->
total
;
if
(
n
==
0
)
{
_defects
.
release
();
return
;
}
_defects
.
create
(
n
,
1
,
CV_32SC4
);
Mat
defects
=
_defects
.
getMat
();
SeqIterator
<
CvConvexityDefect
>
it
=
Seq
<
CvConvexityDefect
>
(
seq
).
begin
();
CvPoint
*
ptorg
=
(
CvPoint
*
)
points
.
data
;
for
(
i
=
0
;
i
<
n
;
i
++
,
++
it
)
{
CvConvexityDefect
&
d
=
*
it
;
int
idx0
=
(
int
)(
d
.
start
-
ptorg
);
int
idx1
=
(
int
)(
d
.
end
-
ptorg
);
int
idx2
=
(
int
)(
d
.
depth_point
-
ptorg
);
CV_Assert
(
0
<=
idx0
&&
idx0
<
ptnum
);
CV_Assert
(
0
<=
idx1
&&
idx1
<
ptnum
);
CV_Assert
(
0
<=
idx2
&&
idx2
<
ptnum
);
CV_Assert
(
d
.
depth
>=
0
);
int
idepth
=
cvRound
(
d
.
depth
*
256
);
defects
.
at
<
Vec4i
>
(
i
)
=
Vec4i
(
idx0
,
idx1
,
idx2
,
idepth
);
}
}
bool
isContourConvex
(
InputArray
_contour
)
{
Mat
contour
=
_contour
.
getMat
();
CV_Assert
(
contour
.
checkVector
(
2
)
>=
0
&&
(
contour
.
depth
()
==
CV_32F
||
contour
.
depth
()
==
CV_32S
));
CvMat
c
=
Mat
(
contour
);
return
cvCheckContourConvexity
(
&
c
)
>
0
;
}
void
convexHull
(
InputArray
_points
,
OutputArray
_hull
,
bool
clockwise
,
bool
returnPoints
)
{
Mat
points
=
_points
.
getMat
();
int
i
,
total
=
points
.
checkVector
(
2
),
depth
=
points
.
depth
(),
nout
=
0
;
int
miny_ind
=
0
,
maxy_ind
=
0
;
CV_Assert
(
total
>=
0
&&
(
depth
==
CV_32F
||
depth
==
CV_32S
));
if
(
total
==
0
)
{
_hull
.
release
();
return
;
}
returnPoints
=
!
_hull
.
fixedType
()
?
returnPoints
:
_hull
.
type
()
!=
CV_32S
;
bool
is_float
=
depth
==
CV_32F
;
AutoBuffer
<
Point
*>
_pointer
(
total
);
AutoBuffer
<
int
>
_stack
(
total
+
2
),
_hullbuf
(
total
);
Point
**
pointer
=
_pointer
;
Point2f
**
pointerf
=
(
Point2f
**
)
pointer
;
Point
*
data0
=
(
Point
*
)
points
.
data
;
int
*
stack
=
_stack
;
int
*
hullbuf
=
_hullbuf
;
CV_Assert
(
points
.
isContinuous
());
for
(
i
=
0
;
i
<
total
;
i
++
)
pointer
[
i
]
=
&
data0
[
i
];
// sort the point set by x-coordinate, find min and max y
if
(
!
is_float
)
{
std
::
sort
(
pointer
,
pointer
+
total
,
CHullCmpPoints
<
int
>
());
for
(
i
=
1
;
i
<
total
;
i
++
)
{
int
y
=
pointer
[
i
]
->
y
;
if
(
pointer
[
miny_ind
]
->
y
>
y
)
miny_ind
=
i
;
if
(
pointer
[
maxy_ind
]
->
y
<
y
)
maxy_ind
=
i
;
}
}
else
{
std
::
sort
(
pointerf
,
pointerf
+
total
,
CHullCmpPoints
<
float
>
());
for
(
i
=
1
;
i
<
total
;
i
++
)
{
float
y
=
pointerf
[
i
]
->
y
;
if
(
pointerf
[
miny_ind
]
->
y
>
y
)
miny_ind
=
i
;
if
(
pointerf
[
maxy_ind
]
->
y
<
y
)
maxy_ind
=
i
;
}
}
if
(
pointer
[
0
]
->
x
==
pointer
[
total
-
1
]
->
x
&&
pointer
[
0
]
->
y
==
pointer
[
total
-
1
]
->
y
)
{
hullbuf
[
nout
++
]
=
0
;
}
else
{
// upper half
int
*
tl_stack
=
stack
;
int
tl_count
=
!
is_float
?
Sklansky_
(
pointer
,
0
,
maxy_ind
,
tl_stack
,
-
1
,
1
)
:
Sklansky_
(
pointerf
,
0
,
maxy_ind
,
tl_stack
,
-
1
,
1
);
int
*
tr_stack
=
stack
+
tl_count
;
int
tr_count
=
!
is_float
?
Sklansky_
(
pointer
,
total
-
1
,
maxy_ind
,
tr_stack
,
-
1
,
-
1
)
:
Sklansky_
(
pointerf
,
total
-
1
,
maxy_ind
,
tr_stack
,
-
1
,
-
1
);
// gather upper part of convex hull to output
if
(
!
clockwise
)
{
std
::
swap
(
tl_stack
,
tr_stack
);
std
::
swap
(
tl_count
,
tr_count
);
}
for
(
i
=
0
;
i
<
tl_count
-
1
;
i
++
)
hullbuf
[
nout
++
]
=
pointer
[
tl_stack
[
i
]]
-
data0
;
for
(
i
=
tr_count
-
1
;
i
>
0
;
i
--
)
hullbuf
[
nout
++
]
=
pointer
[
tr_stack
[
i
]]
-
data0
;
int
stop_idx
=
tr_count
>
2
?
tr_stack
[
1
]
:
tl_count
>
2
?
tl_stack
[
tl_count
-
2
]
:
-
1
;
// lower half
int
*
bl_stack
=
stack
;
int
bl_count
=
!
is_float
?
Sklansky_
(
pointer
,
0
,
miny_ind
,
bl_stack
,
1
,
-
1
)
:
Sklansky_
(
pointerf
,
0
,
miny_ind
,
bl_stack
,
1
,
-
1
);
int
*
br_stack
=
stack
+
bl_count
;
int
br_count
=
!
is_float
?
Sklansky_
(
pointer
,
total
-
1
,
miny_ind
,
br_stack
,
1
,
1
)
:
Sklansky_
(
pointerf
,
total
-
1
,
miny_ind
,
br_stack
,
1
,
1
);
if
(
clockwise
)
{
std
::
swap
(
bl_stack
,
br_stack
);
std
::
swap
(
bl_count
,
br_count
);
}
if
(
stop_idx
>=
0
)
{
int
check_idx
=
bl_count
>
2
?
bl_stack
[
1
]
:
bl_count
+
br_count
>
2
?
br_stack
[
2
-
bl_count
]
:
-
1
;
if
(
check_idx
==
stop_idx
||
(
check_idx
>=
0
&&
pointer
[
check_idx
]
->
x
==
pointer
[
stop_idx
]
->
x
&&
pointer
[
check_idx
]
->
y
==
pointer
[
stop_idx
]
->
y
)
)
{
// if all the points lie on the same line, then
// the bottom part of the convex hull is the mirrored top part
// (except the exteme points).
bl_count
=
MIN
(
bl_count
,
2
);
br_count
=
MIN
(
br_count
,
2
);
}
}
for
(
i
=
0
;
i
<
bl_count
-
1
;
i
++
)
hullbuf
[
nout
++
]
=
pointer
[
bl_stack
[
i
]]
-
data0
;
for
(
i
=
br_count
-
1
;
i
>
0
;
i
--
)
hullbuf
[
nout
++
]
=
pointer
[
br_stack
[
i
]]
-
data0
;
}
if
(
!
returnPoints
)
Mat
(
nout
,
1
,
CV_32S
,
hullbuf
).
copyTo
(
_hull
);
else
{
_hull
.
create
(
nout
,
1
,
CV_MAKETYPE
(
depth
,
2
));
Mat
hull
=
_hull
.
getMat
();
size_t
step
=
!
hull
.
isContinuous
()
?
hull
.
step
[
0
]
:
sizeof
(
Point
);
for
(
i
=
0
;
i
<
nout
;
i
++
)
*
(
Point
*
)(
hull
.
data
+
i
*
step
)
=
data0
[
hullbuf
[
i
]];
}
}
}
CV_IMPL
CvSeq
*
cvConvexHull2
(
const
CvArr
*
array
,
void
*
hull_storage
,
int
orientation
,
int
return_points
)
{
union
{
CvContour
*
c
;
CvSeq
*
s
;
}
hull
;
hull
.
s
=
0
;
CvMat
*
mat
=
0
;
CvContour
contour_header
;
union
{
CvContour
c
;
CvSeq
s
;
}
hull_header
;
CvSeqBlock
block
,
hullblock
;
CvSeq
*
ptseq
=
0
;
CvSeq
*
hullseq
=
0
;
if
(
CV_IS_SEQ
(
array
))
{
ptseq
=
(
CvSeq
*
)
array
;
if
(
!
CV_IS_SEQ_POINT_SET
(
ptseq
))
CV_Error
(
CV_StsBadArg
,
"Unsupported sequence type"
);
if
(
hull_storage
==
0
)
hull_storage
=
ptseq
->
storage
;
}
else
{
ptseq
=
cvPointSeqFromMat
(
CV_SEQ_KIND_GENERIC
,
array
,
&
contour_header
,
&
block
);
}
if
(
CV_IS_STORAGE
(
hull_storage
))
{
if
(
return_points
)
{
hullseq
=
cvCreateSeq
(
CV_SEQ_KIND_CURVE
|
CV_SEQ_ELTYPE
(
ptseq
)
|
CV_SEQ_FLAG_CLOSED
|
CV_SEQ_FLAG_CONVEX
,
sizeof
(
CvContour
),
sizeof
(
CvPoint
),(
CvMemStorage
*
)
hull_storage
);
}
else
{
hullseq
=
cvCreateSeq
(
CV_SEQ_KIND_CURVE
|
CV_SEQ_ELTYPE_PPOINT
|
CV_SEQ_FLAG_CLOSED
|
CV_SEQ_FLAG_CONVEX
,
sizeof
(
CvContour
),
sizeof
(
CvPoint
*
),
(
CvMemStorage
*
)
hull_storage
);
}
}
else
{
if
(
!
CV_IS_MAT
(
hull_storage
))
CV_Error
(
CV_StsBadArg
,
"Destination must be valid memory storage or matrix"
);
mat
=
(
CvMat
*
)
hull_storage
;
if
(
(
mat
->
cols
!=
1
&&
mat
->
rows
!=
1
)
||
!
CV_IS_MAT_CONT
(
mat
->
type
))
CV_Error
(
CV_StsBadArg
,
"The hull matrix should be continuous and have a single row or a single column"
);
if
(
mat
->
cols
+
mat
->
rows
-
1
<
ptseq
->
total
)
CV_Error
(
CV_StsBadSize
,
"The hull matrix size might be not enough to fit the hull"
);
if
(
CV_MAT_TYPE
(
mat
->
type
)
!=
CV_SEQ_ELTYPE
(
ptseq
)
&&
CV_MAT_TYPE
(
mat
->
type
)
!=
CV_32SC1
)
CV_Error
(
CV_StsUnsupportedFormat
,
"The hull matrix must have the same type as input or 32sC1 (integers)"
);
hullseq
=
cvMakeSeqHeaderForArray
(
CV_SEQ_KIND_CURVE
|
CV_MAT_TYPE
(
mat
->
type
)
|
CV_SEQ_FLAG_CLOSED
,
sizeof
(
contour_header
),
CV_ELEM_SIZE
(
mat
->
type
),
mat
->
data
.
ptr
,
mat
->
cols
+
mat
->
rows
-
1
,
&
hull_header
.
s
,
&
hullblock
);
cvClearSeq
(
hullseq
);
}
int
hulltype
=
CV_SEQ_ELTYPE
(
hullseq
);
int
total
=
ptseq
->
total
;
if
(
total
==
0
)
{
if
(
mat
)
CV_Error
(
CV_StsBadSize
,
"Point sequence can not be empty if the output is matrix"
);
return
hull
.
s
;
}
cv
::
AutoBuffer
<
cv
::
Point
>
_ptbuf
(
total
);
cv
::
Point
*
ptbuf
=
_ptbuf
;
cv
::
Mat
h0
;
cvCvtSeqToArray
(
ptseq
,
ptbuf
);
cv
::
convexHull
(
cv
::
Mat
(
total
,
1
,
CV_SEQ_ELTYPE
(
ptseq
),
ptbuf
),
h0
,
orientation
==
CV_CLOCKWISE
,
CV_MAT_CN
(
hulltype
)
==
2
);
if
(
hulltype
==
CV_SEQ_ELTYPE_PPOINT
)
{
const
int
*
idx
=
h0
.
ptr
<
int
>
();
int
ctotal
=
(
int
)
h0
.
total
();
for
(
int
i
=
0
;
i
<
ctotal
;
i
++
)
{
void
*
ptr
=
cvGetSeqElem
(
ptseq
,
idx
[
i
]);
cvSeqPush
(
hullseq
,
&
ptr
);
}
}
else
cvSeqPushMulti
(
hullseq
,
h0
.
data
,
(
int
)
h0
.
total
());
if
(
mat
)
{
if
(
mat
->
rows
>
mat
->
cols
)
mat
->
rows
=
hullseq
->
total
;
else
mat
->
cols
=
hullseq
->
total
;
}
else
{
hull
.
s
=
hullseq
;
hull
.
c
->
rect
=
cvBoundingRect
(
ptseq
,
ptseq
->
header_size
<
(
int
)
sizeof
(
CvContour
)
||
&
ptseq
->
flags
==
&
contour_header
.
flags
);
}
return
hull
.
s
;
}
/* contour must be a simple polygon */
/* it must have more than 3 points */
CV_IMPL
CvSeq
*
cvConvexityDefects
(
const
CvArr
*
array
,
const
CvArr
*
hullarray
,
CvMemStorage
*
storage
)
{
CvSeq
*
defects
=
0
;
int
i
,
index
;
CvPoint
*
hull_cur
;
/* is orientation of hull different from contour one */
int
rev_orientation
;
CvContour
contour_header
;
union
{
CvContour
c
;
CvSeq
s
;
}
hull_header
;
CvSeqBlock
block
,
hullblock
;
CvSeq
*
ptseq
=
(
CvSeq
*
)
array
,
*
hull
=
(
CvSeq
*
)
hullarray
;
CvSeqReader
hull_reader
;
CvSeqReader
ptseq_reader
;
CvSeqWriter
writer
;
int
is_index
;
if
(
CV_IS_SEQ
(
ptseq
))
{
if
(
!
CV_IS_SEQ_POINT_SET
(
ptseq
))
CV_Error
(
CV_StsUnsupportedFormat
,
"Input sequence is not a sequence of points"
);
if
(
!
storage
)
storage
=
ptseq
->
storage
;
}
else
{
ptseq
=
cvPointSeqFromMat
(
CV_SEQ_KIND_GENERIC
,
array
,
&
contour_header
,
&
block
);
}
if
(
CV_SEQ_ELTYPE
(
ptseq
)
!=
CV_32SC2
)
CV_Error
(
CV_StsUnsupportedFormat
,
"Floating-point coordinates are not supported here"
);
if
(
CV_IS_SEQ
(
hull
))
{
int
hulltype
=
CV_SEQ_ELTYPE
(
hull
);
if
(
hulltype
!=
CV_SEQ_ELTYPE_PPOINT
&&
hulltype
!=
CV_SEQ_ELTYPE_INDEX
)
CV_Error
(
CV_StsUnsupportedFormat
,
"Convex hull must represented as a sequence "
"of indices or sequence of pointers"
);
if
(
!
storage
)
storage
=
hull
->
storage
;
}
else
{
CvMat
*
mat
=
(
CvMat
*
)
hull
;
if
(
!
CV_IS_MAT
(
hull
))
CV_Error
(
CV_StsBadArg
,
"Convex hull is neither sequence nor matrix"
);
if
(
(
mat
->
cols
!=
1
&&
mat
->
rows
!=
1
)
||
!
CV_IS_MAT_CONT
(
mat
->
type
)
||
CV_MAT_TYPE
(
mat
->
type
)
!=
CV_32SC1
)
CV_Error
(
CV_StsBadArg
,
"The matrix should be 1-dimensional and continuous array of int's"
);
if
(
mat
->
cols
+
mat
->
rows
-
1
>
ptseq
->
total
)
CV_Error
(
CV_StsBadSize
,
"Convex hull is larger than the point sequence"
);
hull
=
cvMakeSeqHeaderForArray
(
CV_SEQ_KIND_CURVE
|
CV_MAT_TYPE
(
mat
->
type
)
|
CV_SEQ_FLAG_CLOSED
,
sizeof
(
CvContour
),
CV_ELEM_SIZE
(
mat
->
type
),
mat
->
data
.
ptr
,
mat
->
cols
+
mat
->
rows
-
1
,
&
hull_header
.
s
,
&
hullblock
);
}
is_index
=
CV_SEQ_ELTYPE
(
hull
)
==
CV_SEQ_ELTYPE_INDEX
;
if
(
!
storage
)
CV_Error
(
CV_StsNullPtr
,
"NULL storage pointer"
);
defects
=
cvCreateSeq
(
CV_SEQ_KIND_GENERIC
,
sizeof
(
CvSeq
),
sizeof
(
CvConvexityDefect
),
storage
);
if
(
ptseq
->
total
<
4
||
hull
->
total
<
3
)
{
//CV_ERROR( CV_StsBadSize,
// "point seq size must be >= 4, convex hull size must be >= 3" );
return
defects
;
}
/* recognize co-orientation of ptseq and its hull */
{
int
sign
=
0
;
int
index1
,
index2
,
index3
;
if
(
!
is_index
)
{
CvPoint
*
pos
=
*
CV_SEQ_ELEM
(
hull
,
CvPoint
*
,
0
);
index1
=
cvSeqElemIdx
(
ptseq
,
pos
);
pos
=
*
CV_SEQ_ELEM
(
hull
,
CvPoint
*
,
1
);
index2
=
cvSeqElemIdx
(
ptseq
,
pos
);
pos
=
*
CV_SEQ_ELEM
(
hull
,
CvPoint
*
,
2
);
index3
=
cvSeqElemIdx
(
ptseq
,
pos
);
}
else
{
index1
=
*
CV_SEQ_ELEM
(
hull
,
int
,
0
);
index2
=
*
CV_SEQ_ELEM
(
hull
,
int
,
1
);
index3
=
*
CV_SEQ_ELEM
(
hull
,
int
,
2
);
}
sign
+=
(
index2
>
index1
)
?
1
:
0
;
sign
+=
(
index3
>
index2
)
?
1
:
0
;
sign
+=
(
index1
>
index3
)
?
1
:
0
;
rev_orientation
=
(
sign
==
2
)
?
0
:
1
;
}
cvStartReadSeq
(
ptseq
,
&
ptseq_reader
,
0
);
cvStartReadSeq
(
hull
,
&
hull_reader
,
rev_orientation
);
if
(
!
is_index
)
{
hull_cur
=
*
(
CvPoint
**
)
hull_reader
.
prev_elem
;
index
=
cvSeqElemIdx
(
ptseq
,
(
char
*
)
hull_cur
,
0
);
}
else
{
index
=
*
(
int
*
)
hull_reader
.
prev_elem
;
hull_cur
=
CV_GET_SEQ_ELEM
(
CvPoint
,
ptseq
,
index
);
}
cvSetSeqReaderPos
(
&
ptseq_reader
,
index
);
cvStartAppendToSeq
(
defects
,
&
writer
);
/* cycle through ptseq and hull with computing defects */
for
(
i
=
0
;
i
<
hull
->
total
;
i
++
)
{
CvConvexityDefect
defect
;
int
is_defect
=
0
;
double
dx0
,
dy0
;
double
depth
=
0
,
scale
;
CvPoint
*
hull_next
;
if
(
!
is_index
)
hull_next
=
*
(
CvPoint
**
)
hull_reader
.
ptr
;
else
{
int
t
=
*
(
int
*
)
hull_reader
.
ptr
;
hull_next
=
CV_GET_SEQ_ELEM
(
CvPoint
,
ptseq
,
t
);
}
dx0
=
(
double
)
hull_next
->
x
-
(
double
)
hull_cur
->
x
;
dy0
=
(
double
)
hull_next
->
y
-
(
double
)
hull_cur
->
y
;
assert
(
dx0
!=
0
||
dy0
!=
0
);
scale
=
1.
/
sqrt
(
dx0
*
dx0
+
dy0
*
dy0
);
defect
.
start
=
hull_cur
;
defect
.
end
=
hull_next
;
for
(;;)
{
/* go through ptseq to achieve next hull point */
CV_NEXT_SEQ_ELEM
(
sizeof
(
CvPoint
),
ptseq_reader
);
if
(
ptseq_reader
.
ptr
==
(
schar
*
)
hull_next
)
break
;
else
{
CvPoint
*
cur
=
(
CvPoint
*
)
ptseq_reader
.
ptr
;
/* compute distance from current point to hull edge */
double
dx
=
(
double
)
cur
->
x
-
(
double
)
hull_cur
->
x
;
double
dy
=
(
double
)
cur
->
y
-
(
double
)
hull_cur
->
y
;
/* compute depth */
double
dist
=
fabs
(
-
dy0
*
dx
+
dx0
*
dy
)
*
scale
;
if
(
dist
>
depth
)
{
depth
=
dist
;
defect
.
depth_point
=
cur
;
defect
.
depth
=
(
float
)
depth
;
is_defect
=
1
;
}
}
}
if
(
is_defect
)
{
CV_WRITE_SEQ_ELEM
(
defect
,
writer
);
}
hull_cur
=
hull_next
;
if
(
rev_orientation
)
{
CV_PREV_SEQ_ELEM
(
hull
->
elem_size
,
hull_reader
);
}
else
{
CV_NEXT_SEQ_ELEM
(
hull
->
elem_size
,
hull_reader
);
}
}
return
cvEndWriteSeq
(
&
writer
);
}
CV_IMPL
int
cvCheckContourConvexity
(
const
CvArr
*
array
)
{
int
flag
=
-
1
;
int
i
;
int
orientation
=
0
;
CvSeqReader
reader
;
CvContour
contour_header
;
CvSeqBlock
block
;
CvSeq
*
contour
=
(
CvSeq
*
)
array
;
if
(
CV_IS_SEQ
(
contour
)
)
{
if
(
!
CV_IS_SEQ_POINT_SET
(
contour
))
CV_Error
(
CV_StsUnsupportedFormat
,
"Input sequence must be polygon (closed 2d curve)"
);
}
else
{
contour
=
cvPointSeqFromMat
(
CV_SEQ_KIND_CURVE
|
CV_SEQ_FLAG_CLOSED
,
array
,
&
contour_header
,
&
block
);
}
if
(
contour
->
total
==
0
)
return
-
1
;
cvStartReadSeq
(
contour
,
&
reader
,
0
);
flag
=
1
;
if
(
CV_SEQ_ELTYPE
(
contour
)
==
CV_32SC2
)
{
CvPoint
*
prev_pt
=
(
CvPoint
*
)
reader
.
prev_elem
;
CvPoint
*
cur_pt
=
(
CvPoint
*
)
reader
.
ptr
;
int
dx0
=
cur_pt
->
x
-
prev_pt
->
x
;
int
dy0
=
cur_pt
->
y
-
prev_pt
->
y
;
for
(
i
=
0
;
i
<
contour
->
total
;
i
++
)
{
int
dxdy0
,
dydx0
;
int
dx
,
dy
;
/*int orient; */
CV_NEXT_SEQ_ELEM
(
sizeof
(
CvPoint
),
reader
);
prev_pt
=
cur_pt
;
cur_pt
=
(
CvPoint
*
)
reader
.
ptr
;
dx
=
cur_pt
->
x
-
prev_pt
->
x
;
dy
=
cur_pt
->
y
-
prev_pt
->
y
;
dxdy0
=
dx
*
dy0
;
dydx0
=
dy
*
dx0
;
/* find orientation */
/* orient = -dy0 * dx + dx0 * dy;
orientation |= (orient > 0) ? 1 : 2;
*/
orientation
|=
(
dydx0
>
dxdy0
)
?
1
:
((
dydx0
<
dxdy0
)
?
2
:
3
);
if
(
orientation
==
3
)
{
flag
=
0
;
break
;
}
dx0
=
dx
;
dy0
=
dy
;
}
}
else
{
CV_Assert
(
CV_SEQ_ELTYPE
(
contour
)
==
CV_32FC2
);
CvPoint2D32f
*
prev_pt
=
(
CvPoint2D32f
*
)
reader
.
prev_elem
;
CvPoint2D32f
*
cur_pt
=
(
CvPoint2D32f
*
)
reader
.
ptr
;
float
dx0
=
cur_pt
->
x
-
prev_pt
->
x
;
float
dy0
=
cur_pt
->
y
-
prev_pt
->
y
;
for
(
i
=
0
;
i
<
contour
->
total
;
i
++
)
{
float
dxdy0
,
dydx0
;
float
dx
,
dy
;
/*int orient; */
CV_NEXT_SEQ_ELEM
(
sizeof
(
CvPoint2D32f
),
reader
);
prev_pt
=
cur_pt
;
cur_pt
=
(
CvPoint2D32f
*
)
reader
.
ptr
;
dx
=
cur_pt
->
x
-
prev_pt
->
x
;
dy
=
cur_pt
->
y
-
prev_pt
->
y
;
dxdy0
=
dx
*
dy0
;
dydx0
=
dy
*
dx0
;
/* find orientation */
/* orient = -dy0 * dx + dx0 * dy;
orientation |= (orient > 0) ? 1 : 2;
*/
orientation
|=
(
dydx0
>
dxdy0
)
?
1
:
((
dydx0
<
dxdy0
)
?
2
:
3
);
if
(
orientation
==
3
)
{
flag
=
0
;
break
;
}
dx0
=
dx
;
dy0
=
dy
;
}
}
return
flag
;
}
#endif
/* End of file. */
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