Commit 58f31819 authored by Andrey Kamaev's avatar Andrey Kamaev

Return drawContours back to imgproc

This partly reverts commit 6ca61827.
parent dbd30d4f
...@@ -483,88 +483,6 @@ Draws several polygonal curves. ...@@ -483,88 +483,6 @@ Draws several polygonal curves.
The function ``polylines`` draws one or more polygonal curves. The function ``polylines`` draws one or more polygonal curves.
drawContours
----------------
Draws contours outlines or filled contours.
.. ocv:function:: void drawContours( InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
.. ocv:pyfunction:: cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) -> None
.. ocv:cfunction:: void cvDrawContours( CvArr * img, CvSeq* contour, CvScalar external_color, CvScalar hole_color, int max_level, int thickness=1, int line_type=8, CvPoint offset=cvPoint(0,0) )
.. ocv:pyoldfunction:: cv.DrawContours(img, contour, external_color, hole_color, max_level, thickness=1, lineType=8, offset=(0, 0))-> None
:param image: Destination image.
:param contours: All the input contours. Each contour is stored as a point vector.
:param contourIdx: Parameter indicating a contour to draw. If it is negative, all the contours are drawn.
:param color: Color of the contours.
:param thickness: Thickness of lines the contours are drawn with. If it is negative (for example, ``thickness=CV_FILLED`` ), the contour interiors are
drawn.
:param lineType: Line connectivity. See :ocv:func:`line` for details.
:param hierarchy: Optional information about hierarchy. It is only needed if you want to draw only some of the contours (see ``maxLevel`` ).
:param maxLevel: Maximal level for drawn contours. If it is 0, only
the specified contour is drawn. If it is 1, the function draws the contour(s) and all the nested contours. If it is 2, the function draws the contours, all the nested contours, all the nested-to-nested contours, and so on. This parameter is only taken into account when there is ``hierarchy`` available.
:param offset: Optional contour shift parameter. Shift all the drawn contours by the specified :math:`\texttt{offset}=(dx,dy)` .
:param contour: Pointer to the first contour.
:param external_color: Color of external contours.
:param hole_color: Color of internal contours (holes).
The function draws contour outlines in the image if
:math:`\texttt{thickness} \ge 0` or fills the area bounded by the contours if
:math:`\texttt{thickness}<0` . The example below shows how to retrieve connected components from the binary image and label them: ::
#include "cv.h"
#include "highgui.h"
using namespace cv;
int main( int argc, char** argv )
{
Mat src;
// the first command-line parameter must be a filename of the binary
// (black-n-white) image
if( argc != 2 || !(src=imread(argv[1], 0)).data)
return -1;
Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
src = src > 1;
namedWindow( "Source", 1 );
imshow( "Source", src );
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( src, contours, hierarchy,
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
// iterate through all the top-level contours,
// draw each connected component with its own random color
int idx = 0;
for( ; idx >= 0; idx = hierarchy[idx][0] )
{
Scalar color( rand()&255, rand()&255, rand()&255 );
drawContours( dst, contours, idx, color, CV_FILLED, 8, hierarchy );
}
namedWindow( "Components", 1 );
imshow( "Components", dst );
waitKey(0);
}
putText putText
----------- -----------
......
...@@ -2578,13 +2578,6 @@ CV_EXPORTS_W void polylines(InputOutputArray img, InputArrayOfArrays pts, ...@@ -2578,13 +2578,6 @@ CV_EXPORTS_W void polylines(InputOutputArray img, InputArrayOfArrays pts,
bool isClosed, const Scalar& color, bool isClosed, const Scalar& color,
int thickness=1, int lineType=8, int shift=0 ); int thickness=1, int lineType=8, int shift=0 );
//! draws contours in the image
CV_EXPORTS_W void drawContours( InputOutputArray image, InputArrayOfArrays contours,
int contourIdx, const Scalar& color,
int thickness=1, int lineType=8,
InputArray hierarchy=noArray(),
int maxLevel=INT_MAX, Point offset=Point() );
//! clips the line segment by the rectangle Rect(0, 0, imgSize.width, imgSize.height) //! clips the line segment by the rectangle Rect(0, 0, imgSize.width, imgSize.height)
CV_EXPORTS bool clipLine(Size imgSize, CV_IN_OUT Point& pt1, CV_IN_OUT Point& pt2); CV_EXPORTS bool clipLine(Size imgSize, CV_IN_OUT Point& pt1, CV_IN_OUT Point& pt2);
......
...@@ -140,11 +140,11 @@ bool clipLine( Rect img_rect, Point& pt1, Point& pt2 ) ...@@ -140,11 +140,11 @@ bool clipLine( Rect img_rect, Point& pt1, Point& pt2 )
pt1 -= tl; pt2 -= tl; pt1 -= tl; pt2 -= tl;
bool inside = clipLine(img_rect.size(), pt1, pt2); bool inside = clipLine(img_rect.size(), pt1, pt2);
pt1 += tl; pt2 += tl; pt1 += tl; pt2 += tl;
return inside; return inside;
} }
/* /*
Initializes line iterator. Initializes line iterator.
Returns number of points on the line or negative number if error. Returns number of points on the line or negative number if error.
*/ */
...@@ -195,7 +195,7 @@ LineIterator::LineIterator(const Mat& img, Point pt1, Point pt2, ...@@ -195,7 +195,7 @@ LineIterator::LineIterator(const Mat& img, Point pt1, Point pt2,
istep = (istep ^ s) - s; istep = (istep ^ s) - s;
s = dy > dx ? -1 : 0; s = dy > dx ? -1 : 0;
/* conditional swaps */ /* conditional swaps */
dx ^= dy & s; dx ^= dy & s;
dy ^= dx & s; dy ^= dx & s;
...@@ -208,7 +208,7 @@ LineIterator::LineIterator(const Mat& img, Point pt1, Point pt2, ...@@ -208,7 +208,7 @@ LineIterator::LineIterator(const Mat& img, Point pt1, Point pt2,
if( connectivity == 8 ) if( connectivity == 8 )
{ {
assert( dx >= 0 && dy >= 0 ); assert( dx >= 0 && dy >= 0 );
err = dx - (dy + dy); err = dx - (dy + dy);
plusDelta = dx + dx; plusDelta = dx + dx;
minusDelta = -(dy + dy); minusDelta = -(dy + dy);
...@@ -219,7 +219,7 @@ LineIterator::LineIterator(const Mat& img, Point pt1, Point pt2, ...@@ -219,7 +219,7 @@ LineIterator::LineIterator(const Mat& img, Point pt1, Point pt2,
else /* connectivity == 4 */ else /* connectivity == 4 */
{ {
assert( dx >= 0 && dy >= 0 ); assert( dx >= 0 && dy >= 0 );
err = 0; err = 0;
plusDelta = (dx + dx) + (dy + dy); plusDelta = (dx + dx) + (dy + dy);
minusDelta = -(dy + dy); minusDelta = -(dy + dy);
...@@ -227,7 +227,7 @@ LineIterator::LineIterator(const Mat& img, Point pt1, Point pt2, ...@@ -227,7 +227,7 @@ LineIterator::LineIterator(const Mat& img, Point pt1, Point pt2,
minusStep = bt_pix; minusStep = bt_pix;
count = dx + dy + 1; count = dx + dy + 1;
} }
this->ptr0 = img.data; this->ptr0 = img.data;
this->step = (int)img.step; this->step = (int)img.step;
this->elemSize = bt_pix0; this->elemSize = bt_pix0;
...@@ -621,10 +621,10 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color ) ...@@ -621,10 +621,10 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
tptr[1] = (uchar)cg; \ tptr[1] = (uchar)cg; \
tptr[2] = (uchar)cr; \ tptr[2] = (uchar)cr; \
} }
ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT, ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT,
(pt2.y + (XY_ONE >> 1)) >> XY_SHIFT); (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT);
if( ax > ay ) if( ax > ay )
{ {
pt1.x >>= XY_SHIFT; pt1.x >>= XY_SHIFT;
...@@ -640,7 +640,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color ) ...@@ -640,7 +640,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
else else
{ {
pt1.y >>= XY_SHIFT; pt1.y >>= XY_SHIFT;
while( ecount >= 0 ) while( ecount >= 0 )
{ {
ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y); ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y);
...@@ -664,8 +664,8 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color ) ...@@ -664,8 +664,8 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
} }
ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT, ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT,
(pt2.y + (XY_ONE >> 1)) >> XY_SHIFT); (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT);
if( ax > ay ) if( ax > ay )
{ {
pt1.x >>= XY_SHIFT; pt1.x >>= XY_SHIFT;
...@@ -681,7 +681,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color ) ...@@ -681,7 +681,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
else else
{ {
pt1.y >>= XY_SHIFT; pt1.y >>= XY_SHIFT;
while( ecount >= 0 ) while( ecount >= 0 )
{ {
ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y); ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y);
...@@ -690,7 +690,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color ) ...@@ -690,7 +690,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
ecount--; ecount--;
} }
} }
#undef ICV_PUT_POINT #undef ICV_PUT_POINT
} }
else else
...@@ -706,12 +706,12 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color ) ...@@ -706,12 +706,12 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
} }
ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT, ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT,
(pt2.y + (XY_ONE >> 1)) >> XY_SHIFT); (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT);
if( ax > ay ) if( ax > ay )
{ {
pt1.x >>= XY_SHIFT; pt1.x >>= XY_SHIFT;
while( ecount >= 0 ) while( ecount >= 0 )
{ {
ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT); ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT);
...@@ -723,7 +723,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color ) ...@@ -723,7 +723,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
else else
{ {
pt1.y >>= XY_SHIFT; pt1.y >>= XY_SHIFT;
while( ecount >= 0 ) while( ecount >= 0 )
{ {
ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y); ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y);
...@@ -732,7 +732,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color ) ...@@ -732,7 +732,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
ecount--; ecount--;
} }
} }
#undef ICV_PUT_POINT #undef ICV_PUT_POINT
} }
} }
...@@ -830,7 +830,7 @@ sincos( int angle, float& cosval, float& sinval ) ...@@ -830,7 +830,7 @@ sincos( int angle, float& cosval, float& sinval )
cosval = SinTable[450 - angle]; cosval = SinTable[450 - angle];
} }
/* /*
constructs polygon that represents elliptic arc. constructs polygon that represents elliptic arc.
*/ */
void ellipse2Poly( Point center, Size axes, int angle, void ellipse2Poly( Point center, Size axes, int angle,
...@@ -880,7 +880,7 @@ void ellipse2Poly( Point center, Size axes, int angle, ...@@ -880,7 +880,7 @@ void ellipse2Poly( Point center, Size axes, int angle,
angle = arc_end; angle = arc_end;
if( angle < 0 ) if( angle < 0 )
angle += 360; angle += 360;
x = size_a * SinTable[450-angle]; x = size_a * SinTable[450-angle];
y = size_b * SinTable[angle]; y = size_b * SinTable[angle];
Point pt; Point pt;
...@@ -922,7 +922,7 @@ EllipseEx( Mat& img, Point center, Size axes, ...@@ -922,7 +922,7 @@ EllipseEx( Mat& img, Point center, Size axes,
/****************************************************************************************\ /****************************************************************************************\
* Polygons filling * * Polygons filling *
\****************************************************************************************/ \****************************************************************************************/
/* helper macros: filling horizontal row */ /* helper macros: filling horizontal row */
...@@ -1010,7 +1010,7 @@ FillConvexPoly( Mat& img, const Point* v, int npts, const void* color, int line_ ...@@ -1010,7 +1010,7 @@ FillConvexPoly( Mat& img, const Point* v, int npts, const void* color, int line_
LineAA( img, p0, p, color ); LineAA( img, p0, p, color );
p0 = p; p0 = p;
} }
xmin = (xmin + delta) >> shift; xmin = (xmin + delta) >> shift;
xmax = (xmax + delta) >> shift; xmax = (xmax + delta) >> shift;
ymin = (ymin + delta) >> shift; ymin = (ymin + delta) >> shift;
...@@ -1118,7 +1118,7 @@ CollectPolyEdges( Mat& img, const Point* v, int count, vector<PolyEdge>& edges, ...@@ -1118,7 +1118,7 @@ CollectPolyEdges( Mat& img, const Point* v, int count, vector<PolyEdge>& edges,
{ {
Point t0, t1; Point t0, t1;
PolyEdge edge; PolyEdge edge;
pt1 = v[i]; pt1 = v[i];
pt1.x = (pt1.x + offset.x) << (XY_SHIFT - shift); pt1.x = (pt1.x + offset.x) << (XY_SHIFT - shift);
pt1.y = (pt1.y + delta) >> shift; pt1.y = (pt1.y + delta) >> shift;
...@@ -1337,7 +1337,7 @@ Circle( Mat& img, Point center, int radius, const void* color, int fill ) ...@@ -1337,7 +1337,7 @@ Circle( Mat& img, Point center, int radius, const void* color, int fill )
{ {
uchar *tptr0 = ptr + y11 * step; uchar *tptr0 = ptr + y11 * step;
uchar *tptr1 = ptr + y12 * step; uchar *tptr1 = ptr + y12 * step;
if( !fill ) if( !fill )
{ {
ICV_PUT_POINT( tptr0, x11 ); ICV_PUT_POINT( tptr0, x11 );
...@@ -1374,7 +1374,7 @@ Circle( Mat& img, Point center, int radius, const void* color, int fill ) ...@@ -1374,7 +1374,7 @@ Circle( Mat& img, Point center, int radius, const void* color, int fill )
x11 = std::max( x11, 0 ); x11 = std::max( x11, 0 );
x12 = MIN( x12, size.width - 1 ); x12 = MIN( x12, size.width - 1 );
} }
if( (unsigned)y11 < (unsigned)size.height ) if( (unsigned)y11 < (unsigned)size.height )
{ {
uchar *tptr = ptr + y11 * step; uchar *tptr = ptr + y11 * step;
...@@ -1523,7 +1523,7 @@ ThickLine( Mat& img, Point p0, Point p1, const void* color, ...@@ -1523,7 +1523,7 @@ ThickLine( Mat& img, Point p0, Point p1, const void* color,
Point center; Point center;
center.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT; center.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT;
center.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT; center.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT;
Circle( img, center, (thickness + (XY_ONE>>1)) >> XY_SHIFT, color, 1 ); Circle( img, center, (thickness + (XY_ONE>>1)) >> XY_SHIFT, color, 1 );
} }
else else
{ {
...@@ -1544,7 +1544,7 @@ PolyLine( Mat& img, const Point* v, int count, bool is_closed, ...@@ -1544,7 +1544,7 @@ PolyLine( Mat& img, const Point* v, int count, bool is_closed,
{ {
if( !v || count <= 0 ) if( !v || count <= 0 )
return; return;
int i = is_closed ? count - 1 : 0; int i = is_closed ? count - 1 : 0;
int flags = 2 + !is_closed; int flags = 2 + !is_closed;
Point p0; Point p0;
...@@ -1575,7 +1575,7 @@ void line( Mat& img, Point pt1, Point pt2, const Scalar& color, ...@@ -1575,7 +1575,7 @@ void line( Mat& img, Point pt1, Point pt2, const Scalar& color,
double buf[4]; double buf[4];
scalarToRawData( color, buf, img.type(), 0 ); scalarToRawData( color, buf, img.type(), 0 );
ThickLine( img, pt1, pt2, buf, thickness, line_type, 3, shift ); ThickLine( img, pt1, pt2, buf, thickness, line_type, 3, shift );
} }
void rectangle( Mat& img, Point pt1, Point pt2, void rectangle( Mat& img, Point pt1, Point pt2,
...@@ -1606,7 +1606,7 @@ void rectangle( Mat& img, Point pt1, Point pt2, ...@@ -1606,7 +1606,7 @@ void rectangle( Mat& img, Point pt1, Point pt2,
FillConvexPoly( img, pt, 4, buf, lineType, shift ); FillConvexPoly( img, pt, 4, buf, lineType, shift );
} }
void rectangle( Mat& img, Rect rec, void rectangle( Mat& img, Rect rec,
const Scalar& color, int thickness, const Scalar& color, int thickness,
int lineType, int shift ) int lineType, int shift )
...@@ -1617,7 +1617,7 @@ void rectangle( Mat& img, Rect rec, ...@@ -1617,7 +1617,7 @@ void rectangle( Mat& img, Rect rec,
color, thickness, lineType, shift ); color, thickness, lineType, shift );
} }
void circle( Mat& img, Point center, int radius, void circle( Mat& img, Point center, int radius,
const Scalar& color, int thickness, int line_type, int shift ) const Scalar& color, int thickness, int line_type, int shift )
{ {
...@@ -1667,25 +1667,25 @@ void ellipse( Mat& img, Point center, Size axes, ...@@ -1667,25 +1667,25 @@ void ellipse( Mat& img, Point center, Size axes,
EllipseEx( img, center, axes, _angle, _start_angle, EllipseEx( img, center, axes, _angle, _start_angle,
_end_angle, buf, thickness, line_type ); _end_angle, buf, thickness, line_type );
} }
void ellipse(Mat& img, const RotatedRect& box, const Scalar& color, void ellipse(Mat& img, const RotatedRect& box, const Scalar& color,
int thickness, int lineType) int thickness, int lineType)
{ {
if( lineType == CV_AA && img.depth() != CV_8U ) if( lineType == CV_AA && img.depth() != CV_8U )
lineType = 8; lineType = 8;
CV_Assert( box.size.width >= 0 && box.size.height >= 0 && CV_Assert( box.size.width >= 0 && box.size.height >= 0 &&
thickness <= 255 ); thickness <= 255 );
double buf[4]; double buf[4];
scalarToRawData(color, buf, img.type(), 0); scalarToRawData(color, buf, img.type(), 0);
int _angle = cvRound(box.angle); int _angle = cvRound(box.angle);
Point center(cvRound(box.center.x*(1 << XY_SHIFT)), Point center(cvRound(box.center.x*(1 << XY_SHIFT)),
cvRound(box.center.y*(1 << XY_SHIFT))); cvRound(box.center.y*(1 << XY_SHIFT)));
Size axes(cvRound(box.size.width*(1 << (XY_SHIFT - 1))), Size axes(cvRound(box.size.width*(1 << (XY_SHIFT - 1))),
cvRound(box.size.height*(1 << (XY_SHIFT - 1)))); cvRound(box.size.height*(1 << (XY_SHIFT - 1))));
EllipseEx( img, center, axes, _angle, 0, 360, buf, thickness, lineType ); EllipseEx( img, center, axes, _angle, 0, 360, buf, thickness, lineType );
} }
void fillConvexPoly( Mat& img, const Point* pts, int npts, void fillConvexPoly( Mat& img, const Point* pts, int npts,
...@@ -1875,12 +1875,12 @@ static const int HersheyScriptComplex[] = { ...@@ -1875,12 +1875,12 @@ static const int HersheyScriptComplex[] = {
2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676, 2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676,
2225, 2229, 2226, 2246 }; 2225, 2229, 2226, 2246 };
static const int* getFontData(int fontFace) static const int* getFontData(int fontFace)
{ {
bool isItalic = (fontFace & FONT_ITALIC) != 0; bool isItalic = (fontFace & FONT_ITALIC) != 0;
const int* ascii = 0; const int* ascii = 0;
switch( fontFace & 15 ) switch( fontFace & 15 )
{ {
case FONT_HERSHEY_SIMPLEX: case FONT_HERSHEY_SIMPLEX:
...@@ -1912,15 +1912,15 @@ static const int* getFontData(int fontFace) ...@@ -1912,15 +1912,15 @@ static const int* getFontData(int fontFace)
} }
return ascii; return ascii;
} }
void putText( Mat& img, const string& text, Point org, void putText( Mat& img, const string& text, Point org,
int fontFace, double fontScale, Scalar color, int fontFace, double fontScale, Scalar color,
int thickness, int line_type, bool bottomLeftOrigin ) int thickness, int line_type, bool bottomLeftOrigin )
{ {
const int* ascii = getFontData(fontFace); const int* ascii = getFontData(fontFace);
double buf[4]; double buf[4];
scalarToRawData(color, buf, img.type(), 0); scalarToRawData(color, buf, img.type(), 0);
...@@ -1959,7 +1959,7 @@ void putText( Mat& img, const string& text, Point org, ...@@ -1959,7 +1959,7 @@ void putText( Mat& img, const string& text, Point org,
if( *ptr == ' ' || !*ptr ) if( *ptr == ' ' || !*ptr )
{ {
if( pts.size() > 1 ) if( pts.size() > 1 )
PolyLine( img, &pts[0], (int)pts.size(), false, buf, thickness, line_type, XY_SHIFT ); PolyLine( img, &pts[0], (int)pts.size(), false, buf, thickness, line_type, XY_SHIFT );
if( !*ptr++ ) if( !*ptr++ )
break; break;
pts.resize(0); pts.resize(0);
...@@ -2030,7 +2030,7 @@ void cv::fillPoly(InputOutputArray _img, InputArrayOfArrays pts, ...@@ -2030,7 +2030,7 @@ void cv::fillPoly(InputOutputArray _img, InputArrayOfArrays pts,
AutoBuffer<int> _npts(ncontours); AutoBuffer<int> _npts(ncontours);
Point** ptsptr = _ptsptr; Point** ptsptr = _ptsptr;
int* npts = _npts; int* npts = _npts;
for( i = 0; i < ncontours; i++ ) for( i = 0; i < ncontours; i++ )
{ {
Mat p = pts.getMat(i); Mat p = pts.getMat(i);
...@@ -2056,7 +2056,7 @@ void cv::polylines(InputOutputArray _img, InputArrayOfArrays pts, ...@@ -2056,7 +2056,7 @@ void cv::polylines(InputOutputArray _img, InputArrayOfArrays pts,
AutoBuffer<int> _npts(ncontours); AutoBuffer<int> _npts(ncontours);
Point** ptsptr = _ptsptr; Point** ptsptr = _ptsptr;
int* npts = _npts; int* npts = _npts;
for( i = 0; i < ncontours; i++ ) for( i = 0; i < ncontours; i++ )
{ {
Mat p = pts.getMat(manyContours ? i : -1); Mat p = pts.getMat(manyContours ? i : -1);
...@@ -2069,116 +2069,6 @@ void cv::polylines(InputOutputArray _img, InputArrayOfArrays pts, ...@@ -2069,116 +2069,6 @@ void cv::polylines(InputOutputArray _img, InputArrayOfArrays pts,
polylines(img, (const Point**)ptsptr, npts, (int)ncontours, isClosed, color, thickness, lineType, shift); polylines(img, (const Point**)ptsptr, npts, (int)ncontours, isClosed, color, thickness, lineType, shift);
} }
namespace
{
using namespace cv;
static void addChildContour(InputArrayOfArrays contours,
size_t ncontours,
const Vec4i* hierarchy,
int i, vector<CvSeq>& seq,
vector<CvSeqBlock>& block)
{
for( ; i >= 0; i = hierarchy[i][0] )
{
Mat ci = contours.getMat(i);
cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
!ci.empty() ? (void*)ci.data : 0, (int)ci.total(),
&seq[i], &block[i] );
int h_next = hierarchy[i][0], h_prev = hierarchy[i][1],
v_next = hierarchy[i][2], v_prev = hierarchy[i][3];
seq[i].h_next = (size_t)h_next < ncontours ? &seq[h_next] : 0;
seq[i].h_prev = (size_t)h_prev < ncontours ? &seq[h_prev] : 0;
seq[i].v_next = (size_t)v_next < ncontours ? &seq[v_next] : 0;
seq[i].v_prev = (size_t)v_prev < ncontours ? &seq[v_prev] : 0;
if( v_next >= 0 )
addChildContour(contours, ncontours, hierarchy, v_next, seq, block);
}
}
}
void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours,
int contourIdx, const Scalar& color, int thickness,
int lineType, InputArray _hierarchy,
int maxLevel, Point offset )
{
Mat image = _image.getMat(), hierarchy = _hierarchy.getMat();
CvMat _cimage = image;
size_t ncontours = _contours.total();
size_t i = 0, first = 0, last = ncontours;
vector<CvSeq> seq;
vector<CvSeqBlock> block;
if( !last )
return;
seq.resize(last);
block.resize(last);
for( i = first; i < last; i++ )
seq[i].first = 0;
if( contourIdx >= 0 )
{
CV_Assert( 0 <= contourIdx && contourIdx < (int)last );
first = contourIdx;
last = contourIdx + 1;
}
for( i = first; i < last; i++ )
{
Mat ci = _contours.getMat((int)i);
if( ci.empty() )
continue;
int npoints = ci.checkVector(2, CV_32S);
CV_Assert( npoints > 0 );
cvMakeSeqHeaderForArray( CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
ci.data, npoints, &seq[i], &block[i] );
}
if( hierarchy.empty() || maxLevel == 0 )
for( i = first; i < last; i++ )
{
seq[i].h_next = i < last-1 ? &seq[i+1] : 0;
seq[i].h_prev = i > first ? &seq[i-1] : 0;
}
else
{
size_t count = last - first;
CV_Assert(hierarchy.total() == ncontours && hierarchy.type() == CV_32SC4 );
const Vec4i* h = hierarchy.ptr<Vec4i>();
if( count == ncontours )
{
for( i = first; i < last; i++ )
{
int h_next = h[i][0], h_prev = h[i][1],
v_next = h[i][2], v_prev = h[i][3];
seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0;
seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0;
seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0;
seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0;
}
}
else
{
int child = h[first][2];
if( child >= 0 )
{
addChildContour(_contours, ncontours, h, child, seq, block);
seq[first].v_next = &seq[child];
}
}
}
cvDrawContours( &_cimage, &seq[first], color, color, contourIdx >= 0 ?
-maxLevel : maxLevel, thickness, lineType, offset );
}
static const int CodeDeltas[8][2] = static const int CodeDeltas[8][2] =
{ {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} }; { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
...@@ -2188,7 +2078,7 @@ static const int CodeDeltas[8][2] = ...@@ -2188,7 +2078,7 @@ static const int CodeDeltas[8][2] =
CV_IMPL void CV_IMPL void
cvDrawContours( void* _img, CvSeq* contour, cvDrawContours( void* _img, CvSeq* contour,
CvScalar _externalColor, CvScalar _holeColor, CvScalar _externalColor, CvScalar _holeColor,
int maxLevel, int thickness, int maxLevel, int thickness,
int line_type, CvPoint _offset ) int line_type, CvPoint _offset )
{ {
...@@ -2214,7 +2104,7 @@ cvDrawContours( void* _img, CvSeq* contour, ...@@ -2214,7 +2104,7 @@ cvDrawContours( void* _img, CvSeq* contour,
maxLevel = MAX(maxLevel, INT_MIN+2); maxLevel = MAX(maxLevel, INT_MIN+2);
maxLevel = MIN(maxLevel, INT_MAX-1); maxLevel = MIN(maxLevel, INT_MAX-1);
if( maxLevel < 0 ) if( maxLevel < 0 )
{ {
h_next = contour->h_next; h_next = contour->h_next;
...@@ -2258,7 +2148,7 @@ cvDrawContours( void* _img, CvSeq* contour, ...@@ -2258,7 +2148,7 @@ cvDrawContours( void* _img, CvSeq* contour,
pts.push_back(pt); pts.push_back(pt);
prev_pt = pt; prev_pt = pt;
} }
pt.x += CodeDeltas[(int)code][0]; pt.x += CodeDeltas[(int)code][0];
pt.y += CodeDeltas[(int)code][1]; pt.y += CodeDeltas[(int)code][1];
} }
...@@ -2276,7 +2166,7 @@ cvDrawContours( void* _img, CvSeq* contour, ...@@ -2276,7 +2166,7 @@ cvDrawContours( void* _img, CvSeq* contour,
CV_Assert( elem_type == CV_32SC2 ); CV_Assert( elem_type == CV_32SC2 );
cv::Point pt1, pt2; cv::Point pt1, pt2;
int shift = 0; int shift = 0;
count -= !CV_IS_SEQ_CLOSED(contour); count -= !CV_IS_SEQ_CLOSED(contour);
CV_READ_SEQ_ELEM( pt1, reader ); CV_READ_SEQ_ELEM( pt1, reader );
pt1 += offset; pt1 += offset;
...@@ -2328,7 +2218,7 @@ CV_IMPL CvScalar ...@@ -2328,7 +2218,7 @@ CV_IMPL CvScalar
cvColorToScalar( double packed_color, int type ) cvColorToScalar( double packed_color, int type )
{ {
CvScalar scalar; CvScalar scalar;
if( CV_MAT_DEPTH( type ) == CV_8U ) if( CV_MAT_DEPTH( type ) == CV_8U )
{ {
int icolor = cvRound( packed_color ); int icolor = cvRound( packed_color );
......
...@@ -166,6 +166,87 @@ The function retrieves contours from the binary image using the algorithm ...@@ -166,6 +166,87 @@ The function retrieves contours from the binary image using the algorithm
.. note:: If you use the new Python interface then the ``CV_`` prefix has to be omitted in contour retrieval mode and contour approximation method parameters (for example, use ``cv2.RETR_LIST`` and ``cv2.CHAIN_APPROX_NONE`` parameters). If you use the old Python interface then these parameters have the ``CV_`` prefix (for example, use ``cv.CV_RETR_LIST`` and ``cv.CV_CHAIN_APPROX_NONE``). .. note:: If you use the new Python interface then the ``CV_`` prefix has to be omitted in contour retrieval mode and contour approximation method parameters (for example, use ``cv2.RETR_LIST`` and ``cv2.CHAIN_APPROX_NONE`` parameters). If you use the old Python interface then these parameters have the ``CV_`` prefix (for example, use ``cv.CV_RETR_LIST`` and ``cv.CV_CHAIN_APPROX_NONE``).
drawContours
----------------
Draws contours outlines or filled contours.
.. ocv:function:: void drawContours( InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
.. ocv:pyfunction:: cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) -> None
.. ocv:cfunction:: void cvDrawContours( CvArr *img, CvSeq* contour, CvScalar externalColor, CvScalar holeColor, int maxLevel, int thickness=1, int lineType=8 )
.. ocv:pyoldfunction:: cv.DrawContours(img, contour, external_color, hole_color, max_level, thickness=1, lineType=8, offset=(0, 0))-> None
:param image: Destination image.
:param contours: All the input contours. Each contour is stored as a point vector.
:param contourIdx: Parameter indicating a contour to draw. If it is negative, all the contours are drawn.
:param color: Color of the contours.
:param thickness: Thickness of lines the contours are drawn with. If it is negative (for example, ``thickness=CV_FILLED`` ), the contour interiors are
drawn.
:param lineType: Line connectivity. See :ocv:func:`line` for details.
:param hierarchy: Optional information about hierarchy. It is only needed if you want to draw only some of the contours (see ``maxLevel`` ).
:param maxLevel: Maximal level for drawn contours. If it is 0, only
the specified contour is drawn. If it is 1, the function draws the contour(s) and all the nested contours. If it is 2, the function draws the contours, all the nested contours, all the nested-to-nested contours, and so on. This parameter is only taken into account when there is ``hierarchy`` available.
:param offset: Optional contour shift parameter. Shift all the drawn contours by the specified :math:`\texttt{offset}=(dx,dy)` .
:param contour: Pointer to the first contour.
:param externalColor: Color of external contours.
:param holeColor: Color of internal contours (holes).
The function draws contour outlines in the image if
:math:`\texttt{thickness} \ge 0` or fills the area bounded by the contours if
:math:`\texttt{thickness}<0` . The example below shows how to retrieve connected components from the binary image and label them: ::
#include "cv.h"
#include "highgui.h"
using namespace cv;
int main( int argc, char** argv )
{
Mat src;
// the first command-line parameter must be a filename of the binary
// (black-n-white) image
if( argc != 2 || !(src=imread(argv[1], 0)).data)
return -1;
Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
src = src > 1;
namedWindow( "Source", 1 );
imshow( "Source", src );
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( src, contours, hierarchy,
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
// iterate through all the top-level contours,
// draw each connected component with its own random color
int idx = 0;
for( ; idx >= 0; idx = hierarchy[idx][0] )
{
Scalar color( rand()&255, rand()&255, rand()&255 );
drawContours( dst, contours, idx, color, CV_FILLED, 8, hierarchy );
}
namedWindow( "Components", 1 );
imshow( "Components", dst );
waitKey(0);
}
approxPolyDP approxPolyDP
---------------- ----------------
......
...@@ -1121,6 +1121,13 @@ CV_EXPORTS_W void findContours( InputOutputArray image, OutputArrayOfArrays cont ...@@ -1121,6 +1121,13 @@ CV_EXPORTS_W void findContours( InputOutputArray image, OutputArrayOfArrays cont
CV_EXPORTS void findContours( InputOutputArray image, OutputArrayOfArrays contours, CV_EXPORTS void findContours( InputOutputArray image, OutputArrayOfArrays contours,
int mode, int method, Point offset=Point()); int mode, int method, Point offset=Point());
//! draws contours in the image
CV_EXPORTS_W void drawContours( InputOutputArray image, InputArrayOfArrays contours,
int contourIdx, const Scalar& color,
int thickness=1, int lineType=8,
InputArray hierarchy=noArray(),
int maxLevel=INT_MAX, Point offset=Point() );
//! approximates contour or a curve using Douglas-Peucker algorithm //! approximates contour or a curve using Douglas-Peucker algorithm
CV_EXPORTS_W void approxPolyDP( InputArray curve, CV_EXPORTS_W void approxPolyDP( InputArray curve,
OutputArray approxCurve, OutputArray approxCurve,
......
...@@ -159,7 +159,7 @@ typedef struct _CvContourScanner ...@@ -159,7 +159,7 @@ typedef struct _CvContourScanner
external contours and holes), external contours and holes),
3 - full hierarchy; 3 - full hierarchy;
4 - connected components of a multi-level image 4 - connected components of a multi-level image
*/ */
int subst_flag; int subst_flag;
int seq_type1; /* type of fetched contours */ int seq_type1; /* type of fetched contours */
int header_size1; /* hdr size of fetched contours */ int header_size1; /* hdr size of fetched contours */
...@@ -190,7 +190,7 @@ cvStartFindContours( void* _img, CvMemStorage* storage, ...@@ -190,7 +190,7 @@ cvStartFindContours( void* _img, CvMemStorage* storage,
if( CV_MAT_TYPE(mat->type) == CV_32SC1 && mode == CV_RETR_CCOMP ) if( CV_MAT_TYPE(mat->type) == CV_32SC1 && mode == CV_RETR_CCOMP )
mode = CV_RETR_FLOODFILL; mode = CV_RETR_FLOODFILL;
if( !((CV_IS_MASK_ARR( mat ) && mode < CV_RETR_FLOODFILL) || if( !((CV_IS_MASK_ARR( mat ) && mode < CV_RETR_FLOODFILL) ||
(CV_MAT_TYPE(mat->type) == CV_32SC1 && mode == CV_RETR_FLOODFILL)) ) (CV_MAT_TYPE(mat->type) == CV_32SC1 && mode == CV_RETR_FLOODFILL)) )
CV_Error( CV_StsUnsupportedFormat, "[Start]FindContours support only 8uC1 and 32sC1 images" ); CV_Error( CV_StsUnsupportedFormat, "[Start]FindContours support only 8uC1 and 32sC1 images" );
...@@ -207,7 +207,7 @@ cvStartFindContours( void* _img, CvMemStorage* storage, ...@@ -207,7 +207,7 @@ cvStartFindContours( void* _img, CvMemStorage* storage,
CvContourScanner scanner = (CvContourScanner)cvAlloc( sizeof( *scanner )); CvContourScanner scanner = (CvContourScanner)cvAlloc( sizeof( *scanner ));
memset( scanner, 0, sizeof(*scanner) ); memset( scanner, 0, sizeof(*scanner) );
scanner->storage1 = scanner->storage2 = storage; scanner->storage1 = scanner->storage2 = storage;
scanner->img0 = (schar *) img; scanner->img0 = (schar *) img;
scanner->img = (schar *) (img + step); scanner->img = (schar *) (img + step);
...@@ -805,13 +805,13 @@ icvTraceContour_32s( int *ptr, int step, int *stop_ptr, int is_hole ) ...@@ -805,13 +805,13 @@ icvTraceContour_32s( int *ptr, int step, int *stop_ptr, int is_hole )
const int new_flag = (int)((unsigned)INT_MIN >> 1); const int new_flag = (int)((unsigned)INT_MIN >> 1);
const int value_mask = ~(right_flag | new_flag); const int value_mask = ~(right_flag | new_flag);
const int ccomp_val = *i0 & value_mask; const int ccomp_val = *i0 & value_mask;
/* initialize local state */ /* initialize local state */
CV_INIT_3X3_DELTAS( deltas, step, 1 ); CV_INIT_3X3_DELTAS( deltas, step, 1 );
memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] )); memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
s_end = s = is_hole ? 0 : 4; s_end = s = is_hole ? 0 : 4;
do do
{ {
s = (s - 1) & 7; s = (s - 1) & 7;
...@@ -820,9 +820,9 @@ icvTraceContour_32s( int *ptr, int step, int *stop_ptr, int is_hole ) ...@@ -820,9 +820,9 @@ icvTraceContour_32s( int *ptr, int step, int *stop_ptr, int is_hole )
break; break;
} }
while( s != s_end ); while( s != s_end );
i3 = i0; i3 = i0;
/* check single pixel domain */ /* check single pixel domain */
if( s != s_end ) if( s != s_end )
{ {
...@@ -830,17 +830,17 @@ icvTraceContour_32s( int *ptr, int step, int *stop_ptr, int is_hole ) ...@@ -830,17 +830,17 @@ icvTraceContour_32s( int *ptr, int step, int *stop_ptr, int is_hole )
for( ;; ) for( ;; )
{ {
s_end = s; s_end = s;
for( ;; ) for( ;; )
{ {
i4 = i3 + deltas[++s]; i4 = i3 + deltas[++s];
if( (*i4 & value_mask) == ccomp_val ) if( (*i4 & value_mask) == ccomp_val )
break; break;
} }
if( i3 == stop_ptr || (i4 == i0 && i3 == i1) ) if( i3 == stop_ptr || (i4 == i0 && i3 == i1) )
break; break;
i3 = i4; i3 = i4;
s = (s + 4) & 7; s = (s + 4) & 7;
} /* end of border following loop */ } /* end of border following loop */
...@@ -869,24 +869,24 @@ icvFetchContourEx_32s( int* ptr, ...@@ -869,24 +869,24 @@ icvFetchContourEx_32s( int* ptr,
const int ccomp_val = *i0 & value_mask; const int ccomp_val = *i0 & value_mask;
const int nbd0 = ccomp_val | new_flag; const int nbd0 = ccomp_val | new_flag;
const int nbd1 = nbd0 | right_flag; const int nbd1 = nbd0 | right_flag;
assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE ); assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE );
/* initialize local state */ /* initialize local state */
CV_INIT_3X3_DELTAS( deltas, step, 1 ); CV_INIT_3X3_DELTAS( deltas, step, 1 );
memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] )); memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
/* initialize writer */ /* initialize writer */
cvStartAppendToSeq( contour, &writer ); cvStartAppendToSeq( contour, &writer );
if( method < 0 ) if( method < 0 )
((CvChain *)contour)->origin = pt; ((CvChain *)contour)->origin = pt;
rect.x = rect.width = pt.x; rect.x = rect.width = pt.x;
rect.y = rect.height = pt.y; rect.y = rect.height = pt.y;
s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4; s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4;
do do
{ {
s = (s - 1) & 7; s = (s - 1) & 7;
...@@ -895,7 +895,7 @@ icvFetchContourEx_32s( int* ptr, ...@@ -895,7 +895,7 @@ icvFetchContourEx_32s( int* ptr,
break; break;
} }
while( s != s_end ); while( s != s_end );
if( s == s_end ) /* single pixel domain */ if( s == s_end ) /* single pixel domain */
{ {
*i0 = nbd1; *i0 = nbd1;
...@@ -908,12 +908,12 @@ icvFetchContourEx_32s( int* ptr, ...@@ -908,12 +908,12 @@ icvFetchContourEx_32s( int* ptr,
{ {
i3 = i0; i3 = i0;
prev_s = s ^ 4; prev_s = s ^ 4;
/* follow border */ /* follow border */
for( ;; ) for( ;; )
{ {
s_end = s; s_end = s;
for( ;; ) for( ;; )
{ {
i4 = i3 + deltas[++s]; i4 = i3 + deltas[++s];
...@@ -921,7 +921,7 @@ icvFetchContourEx_32s( int* ptr, ...@@ -921,7 +921,7 @@ icvFetchContourEx_32s( int* ptr,
break; break;
} }
s &= 7; s &= 7;
/* check "right" bound */ /* check "right" bound */
if( (unsigned) (s - 1) < (unsigned) s_end ) if( (unsigned) (s - 1) < (unsigned) s_end )
{ {
...@@ -931,7 +931,7 @@ icvFetchContourEx_32s( int* ptr, ...@@ -931,7 +931,7 @@ icvFetchContourEx_32s( int* ptr,
{ {
*i3 = nbd0; *i3 = nbd0;
} }
if( method < 0 ) if( method < 0 )
{ {
schar _s = (schar) s; schar _s = (schar) s;
...@@ -941,7 +941,7 @@ icvFetchContourEx_32s( int* ptr, ...@@ -941,7 +941,7 @@ icvFetchContourEx_32s( int* ptr,
{ {
CV_WRITE_SEQ_ELEM( pt, writer ); CV_WRITE_SEQ_ELEM( pt, writer );
} }
if( s != prev_s ) if( s != prev_s )
{ {
/* update bounds */ /* update bounds */
...@@ -949,37 +949,37 @@ icvFetchContourEx_32s( int* ptr, ...@@ -949,37 +949,37 @@ icvFetchContourEx_32s( int* ptr,
rect.x = pt.x; rect.x = pt.x;
else if( pt.x > rect.width ) else if( pt.x > rect.width )
rect.width = pt.x; rect.width = pt.x;
if( pt.y < rect.y ) if( pt.y < rect.y )
rect.y = pt.y; rect.y = pt.y;
else if( pt.y > rect.height ) else if( pt.y > rect.height )
rect.height = pt.y; rect.height = pt.y;
} }
prev_s = s; prev_s = s;
pt.x += icvCodeDeltas[s].x; pt.x += icvCodeDeltas[s].x;
pt.y += icvCodeDeltas[s].y; pt.y += icvCodeDeltas[s].y;
if( i4 == i0 && i3 == i1 ) break; if( i4 == i0 && i3 == i1 ) break;
i3 = i4; i3 = i4;
s = (s + 4) & 7; s = (s + 4) & 7;
} /* end of border following loop */ } /* end of border following loop */
} }
rect.width -= rect.x - 1; rect.width -= rect.x - 1;
rect.height -= rect.y - 1; rect.height -= rect.y - 1;
cvEndWriteSeq( &writer ); cvEndWriteSeq( &writer );
if( _method != CV_CHAIN_CODE ) if( _method != CV_CHAIN_CODE )
((CvContour*)contour)->rect = rect; ((CvContour*)contour)->rect = rect;
assert( (writer.seq->total == 0 && writer.seq->first == 0) || assert( (writer.seq->total == 0 && writer.seq->first == 0) ||
writer.seq->total > writer.seq->first->count || writer.seq->total > writer.seq->first->count ||
(writer.seq->first->prev == writer.seq->first && (writer.seq->first->prev == writer.seq->first &&
writer.seq->first->next == writer.seq->first) ); writer.seq->first->next == writer.seq->first) );
if( _rect ) *_rect = rect; if( _rect ) *_rect = rect;
} }
...@@ -1005,7 +1005,7 @@ cvFindNextContour( CvContourScanner scanner ) ...@@ -1005,7 +1005,7 @@ cvFindNextContour( CvContourScanner scanner )
int nbd = scanner->nbd; int nbd = scanner->nbd;
int prev = img[x - 1]; int prev = img[x - 1];
int new_mask = -2; int new_mask = -2;
if( mode == CV_RETR_FLOODFILL ) if( mode == CV_RETR_FLOODFILL )
{ {
prev = ((int*)img)[x - 1]; prev = ((int*)img)[x - 1];
...@@ -1017,13 +1017,13 @@ cvFindNextContour( CvContourScanner scanner ) ...@@ -1017,13 +1017,13 @@ cvFindNextContour( CvContourScanner scanner )
int* img0_i = 0; int* img0_i = 0;
int* img_i = 0; int* img_i = 0;
int p = 0; int p = 0;
if( mode == CV_RETR_FLOODFILL ) if( mode == CV_RETR_FLOODFILL )
{ {
img0_i = (int*)img0; img0_i = (int*)img0;
img_i = (int*)img; img_i = (int*)img;
} }
for( ; x < width; x++ ) for( ; x < width; x++ )
{ {
if( img_i ) if( img_i )
...@@ -1036,10 +1036,10 @@ cvFindNextContour( CvContourScanner scanner ) ...@@ -1036,10 +1036,10 @@ cvFindNextContour( CvContourScanner scanner )
for( ; x < width && (p = img[x]) == prev; x++ ) for( ; x < width && (p = img[x]) == prev; x++ )
; ;
} }
if( x >= width ) if( x >= width )
break; break;
{ {
_CvContourInfo *par_info = 0; _CvContourInfo *par_info = 0;
_CvContourInfo *l_cinfo = 0; _CvContourInfo *l_cinfo = 0;
...@@ -1053,7 +1053,7 @@ cvFindNextContour( CvContourScanner scanner ) ...@@ -1053,7 +1053,7 @@ cvFindNextContour( CvContourScanner scanner )
{ {
/* check hole */ /* check hole */
if( (!img_i && (p != 0 || prev < 1)) || if( (!img_i && (p != 0 || prev < 1)) ||
(img_i && ((prev & new_mask) != 0 || (p & new_mask) != 0))) (img_i && ((prev & new_mask) != 0 || (p & new_mask) != 0)))
goto resume_scan; goto resume_scan;
if( prev & new_mask ) if( prev & new_mask )
...@@ -1219,7 +1219,7 @@ cvFindNextContour( CvContourScanner scanner ) ...@@ -1219,7 +1219,7 @@ cvFindNextContour( CvContourScanner scanner )
return l_cinfo->contour; return l_cinfo->contour;
resume_scan: resume_scan:
prev = p; prev = p;
/* update lnbd */ /* update lnbd */
if( prev & -2 ) if( prev & -2 )
...@@ -1663,7 +1663,7 @@ cvFindContours( void* img, CvMemStorage* storage, ...@@ -1663,7 +1663,7 @@ cvFindContours( void* img, CvMemStorage* storage,
if( !firstContour ) if( !firstContour )
CV_Error( CV_StsNullPtr, "NULL double CvSeq pointer" ); CV_Error( CV_StsNullPtr, "NULL double CvSeq pointer" );
*firstContour = 0; *firstContour = 0;
if( method == CV_LINK_RUNS ) if( method == CV_LINK_RUNS )
...@@ -1733,7 +1733,7 @@ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours, ...@@ -1733,7 +1733,7 @@ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours,
{ {
_hierarchy.create(1, total, CV_32SC4, -1, true); _hierarchy.create(1, total, CV_32SC4, -1, true);
Vec4i* hierarchy = _hierarchy.getMat().ptr<Vec4i>(); Vec4i* hierarchy = _hierarchy.getMat().ptr<Vec4i>();
it = all_contours.begin(); it = all_contours.begin();
for( i = 0; i < total; i++, ++it ) for( i = 0; i < total; i++, ++it )
{ {
...@@ -1753,6 +1753,116 @@ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours, ...@@ -1753,6 +1753,116 @@ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours,
findContours(_image, _contours, noArray(), mode, method, offset); findContours(_image, _contours, noArray(), mode, method, offset);
} }
namespace cv
{
static void addChildContour(InputArrayOfArrays contours,
size_t ncontours,
const Vec4i* hierarchy,
int i, vector<CvSeq>& seq,
vector<CvSeqBlock>& block)
{
for( ; i >= 0; i = hierarchy[i][0] )
{
Mat ci = contours.getMat(i);
cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
!ci.empty() ? (void*)ci.data : 0, (int)ci.total(),
&seq[i], &block[i] );
int h_next = hierarchy[i][0], h_prev = hierarchy[i][1],
v_next = hierarchy[i][2], v_prev = hierarchy[i][3];
seq[i].h_next = (size_t)h_next < ncontours ? &seq[h_next] : 0;
seq[i].h_prev = (size_t)h_prev < ncontours ? &seq[h_prev] : 0;
seq[i].v_next = (size_t)v_next < ncontours ? &seq[v_next] : 0;
seq[i].v_prev = (size_t)v_prev < ncontours ? &seq[v_prev] : 0;
if( v_next >= 0 )
addChildContour(contours, ncontours, hierarchy, v_next, seq, block);
}
}
}
void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours,
int contourIdx, const Scalar& color, int thickness,
int lineType, InputArray _hierarchy,
int maxLevel, Point offset )
{
Mat image = _image.getMat(), hierarchy = _hierarchy.getMat();
CvMat _cimage = image;
size_t ncontours = _contours.total();
size_t i = 0, first = 0, last = ncontours;
vector<CvSeq> seq;
vector<CvSeqBlock> block;
if( !last )
return;
seq.resize(last);
block.resize(last);
for( i = first; i < last; i++ )
seq[i].first = 0;
if( contourIdx >= 0 )
{
CV_Assert( 0 <= contourIdx && contourIdx < (int)last );
first = contourIdx;
last = contourIdx + 1;
}
for( i = first; i < last; i++ )
{
Mat ci = _contours.getMat((int)i);
if( ci.empty() )
continue;
int npoints = ci.checkVector(2, CV_32S);
CV_Assert( npoints > 0 );
cvMakeSeqHeaderForArray( CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
ci.data, npoints, &seq[i], &block[i] );
}
if( hierarchy.empty() || maxLevel == 0 )
for( i = first; i < last; i++ )
{
seq[i].h_next = i < last-1 ? &seq[i+1] : 0;
seq[i].h_prev = i > first ? &seq[i-1] : 0;
}
else
{
size_t count = last - first;
CV_Assert(hierarchy.total() == ncontours && hierarchy.type() == CV_32SC4 );
const Vec4i* h = hierarchy.ptr<Vec4i>();
if( count == ncontours )
{
for( i = first; i < last; i++ )
{
int h_next = h[i][0], h_prev = h[i][1],
v_next = h[i][2], v_prev = h[i][3];
seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0;
seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0;
seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0;
seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0;
}
}
else
{
int child = h[first][2];
if( child >= 0 )
{
addChildContour(_contours, ncontours, h, child, seq, block);
seq[first].v_next = &seq[child];
}
}
}
cvDrawContours( &_cimage, &seq[first], color, color, contourIdx >= 0 ?
-maxLevel : maxLevel, thickness, lineType, offset );
}
void cv::approxPolyDP( InputArray _curve, OutputArray _approxCurve, void cv::approxPolyDP( InputArray _curve, OutputArray _approxCurve,
double epsilon, bool closed ) double epsilon, bool closed )
{ {
...@@ -1824,7 +1934,7 @@ double cv::matchShapes( InputArray _contour1, ...@@ -1824,7 +1934,7 @@ double cv::matchShapes( InputArray _contour1,
CV_Assert(contour1.checkVector(2) >= 0 && contour2.checkVector(2) >= 0 && CV_Assert(contour1.checkVector(2) >= 0 && contour2.checkVector(2) >= 0 &&
(contour1.depth() == CV_32F || contour1.depth() == CV_32S) && (contour1.depth() == CV_32F || contour1.depth() == CV_32S) &&
contour1.depth() == contour2.depth()); contour1.depth() == contour2.depth());
CvMat c1 = Mat(contour1), c2 = Mat(contour2); CvMat c1 = Mat(contour1), c2 = Mat(contour2);
return cvMatchShapes(&c1, &c2, method, parameter); return cvMatchShapes(&c1, &c2, method, parameter);
} }
...@@ -1835,13 +1945,13 @@ void cv::convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool ...@@ -1835,13 +1945,13 @@ void cv::convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool
Mat points = _points.getMat(); Mat points = _points.getMat();
int nelems = points.checkVector(2), depth = points.depth(); int nelems = points.checkVector(2), depth = points.depth();
CV_Assert(nelems >= 0 && (depth == CV_32F || depth == CV_32S)); CV_Assert(nelems >= 0 && (depth == CV_32F || depth == CV_32S));
if( nelems == 0 ) if( nelems == 0 )
{ {
_hull.release(); _hull.release();
return; return;
} }
returnPoints = !_hull.fixedType() ? returnPoints : _hull.type() != CV_32S; returnPoints = !_hull.fixedType() ? returnPoints : _hull.type() != CV_32S;
Mat hull(nelems, 1, returnPoints ? CV_MAKETYPE(depth, 2) : CV_32S); Mat hull(nelems, 1, returnPoints ? CV_MAKETYPE(depth, 2) : CV_32S);
CvMat _cpoints = points, _chull = hull; CvMat _cpoints = points, _chull = hull;
...@@ -1860,23 +1970,23 @@ void cv::convexityDefects( InputArray _points, InputArray _hull, OutputArray _de ...@@ -1860,23 +1970,23 @@ void cv::convexityDefects( InputArray _points, InputArray _hull, OutputArray _de
Mat hull = _hull.getMat(); Mat hull = _hull.getMat();
CV_Assert( hull.checkVector(1, CV_32S) > 2 ); CV_Assert( hull.checkVector(1, CV_32S) > 2 );
Ptr<CvMemStorage> storage = cvCreateMemStorage(); Ptr<CvMemStorage> storage = cvCreateMemStorage();
CvMat c_points = points, c_hull = hull; CvMat c_points = points, c_hull = hull;
CvSeq* seq = cvConvexityDefects(&c_points, &c_hull, storage); CvSeq* seq = cvConvexityDefects(&c_points, &c_hull, storage);
int i, n = seq->total; int i, n = seq->total;
if( n == 0 ) if( n == 0 )
{ {
_defects.release(); _defects.release();
return; return;
} }
_defects.create(n, 1, CV_32SC4); _defects.create(n, 1, CV_32SC4);
Mat defects = _defects.getMat(); Mat defects = _defects.getMat();
SeqIterator<CvConvexityDefect> it = Seq<CvConvexityDefect>(seq).begin(); SeqIterator<CvConvexityDefect> it = Seq<CvConvexityDefect>(seq).begin();
CvPoint* ptorg = (CvPoint*)points.data; CvPoint* ptorg = (CvPoint*)points.data;
for( i = 0; i < n; i++, ++it ) for( i = 0; i < n; i++, ++it )
{ {
CvConvexityDefect& d = *it; CvConvexityDefect& d = *it;
...@@ -1924,9 +2034,9 @@ void cv::fitLine( InputArray _points, OutputArray _line, int distType, ...@@ -1924,9 +2034,9 @@ void cv::fitLine( InputArray _points, OutputArray _line, int distType,
CvMat _cpoints = points.reshape(2 + (int)is3d); CvMat _cpoints = points.reshape(2 + (int)is3d);
float line[6]; float line[6];
cvFitLine(&_cpoints, distType, param, reps, aeps, &line[0]); cvFitLine(&_cpoints, distType, param, reps, aeps, &line[0]);
int out_size = (is2d)?( (is3d)? (points.channels() * points.rows * 2) : 4 ): 6; int out_size = (is2d)?( (is3d)? (points.channels() * points.rows * 2) : 4 ): 6;
_line.create(out_size, 1, CV_32F, -1, true); _line.create(out_size, 1, CV_32F, -1, true);
Mat l = _line.getMat(); Mat l = _line.getMat();
CV_Assert( l.isContinuous() ); CV_Assert( l.isContinuous() );
......
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