1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
43 /* initializes 8-element array for fast access to 3x3 neighborhood of a pixel */
44 #define CV_INIT_3X3_DELTAS( deltas, step, nch ) \
45 ((deltas)[0] = (nch), (deltas)[1] = -(step) + (nch), \
46 (deltas)[2] = -(step), (deltas)[3] = -(step) - (nch), \
47 (deltas)[4] = -(nch), (deltas)[5] = (step) - (nch), \
48 (deltas)[6] = (step), (deltas)[7] = (step) + (nch))
50 static const CvPoint icvCodeDeltas[8] =
51 { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
54 cvStartReadChainPoints( CvChain * chain, CvChainPtReader * reader )
58 CV_FUNCNAME( "cvStartReadChainPoints" );
62 if( !chain || !reader )
63 CV_ERROR( CV_StsNullPtr, "" );
65 if( chain->elem_size != 1 || chain->header_size < (int)sizeof(CvChain))
66 CV_ERROR( CV_StsBadSize, "" );
68 cvStartReadSeq( (CvSeq *) chain, (CvSeqReader *) reader, 0 );
71 reader->pt = chain->origin;
73 for( i = 0; i < 8; i++ )
75 reader->deltas[i][0] = (schar) icvCodeDeltas[i].x;
76 reader->deltas[i][1] = (schar) icvCodeDeltas[i].y;
83 /* retrieves next point of the chain curve and updates reader */
85 cvReadChainPoint( CvChainPtReader * reader )
89 CvPoint pt = { 0, 0 };
91 CV_FUNCNAME( "cvReadChainPoint" );
96 CV_ERROR( CV_StsNullPtr, "" );
105 if( ptr >= reader->block_max )
107 cvChangeSeqBlock( (CvSeqReader *) reader, 1 );
112 reader->code = (schar)code;
113 assert( (code & ~7) == 0 );
114 reader->pt.x = pt.x + icvCodeDeltas[code].x;
115 reader->pt.y = pt.y + icvCodeDeltas[code].y;
124 /****************************************************************************************\
125 * Raster->Chain Tree (Suzuki algorithms) *
126 \****************************************************************************************/
128 typedef struct _CvContourInfo
131 struct _CvContourInfo *next; /* next contour with the same mark value */
132 struct _CvContourInfo *parent; /* information about parent contour */
133 CvSeq *contour; /* corresponding contour (may be 0, if rejected) */
134 CvRect rect; /* bounding rectangle */
135 CvPoint origin; /* origin point (where the contour was traced from) */
136 int is_hole; /* hole flag */
142 Structure that is used for sequental retrieving contours from the image.
143 It supports both hierarchical and plane variants of Suzuki algorithm.
145 typedef struct _CvContourScanner
147 CvMemStorage *storage1; /* contains fetched contours */
148 CvMemStorage *storage2; /* contains approximated contours
149 (!=storage1 if approx_method2 != approx_method1) */
150 CvMemStorage *cinfo_storage; /* contains _CvContourInfo nodes */
151 CvSet *cinfo_set; /* set of _CvContourInfo nodes */
152 CvMemStoragePos initial_pos; /* starting storage pos */
153 CvMemStoragePos backup_pos; /* beginning of the latest approx. contour */
154 CvMemStoragePos backup_pos2; /* ending of the latest approx. contour */
155 schar *img0; /* image origin */
156 schar *img; /* current image row */
157 int img_step; /* image step */
158 CvSize img_size; /* ROI size */
159 CvPoint offset; /* ROI offset: coordinates, added to each contour point */
160 CvPoint pt; /* current scanner position */
161 CvPoint lnbd; /* position of the last met contour */
162 int nbd; /* current mark val */
163 _CvContourInfo *l_cinfo; /* information about latest approx. contour */
164 _CvContourInfo cinfo_temp; /* temporary var which is used in simple modes */
165 _CvContourInfo frame_info; /* information about frame */
166 CvSeq frame; /* frame itself */
167 int approx_method1; /* approx method when tracing */
168 int approx_method2; /* final approx method */
169 int mode; /* contour scanning mode:
171 1 - all the contours w/o any hierarchy
172 2 - connected components (i.e. two-level structure -
173 external contours and holes) */
175 int seq_type1; /* type of fetched contours */
176 int header_size1; /* hdr size of fetched contours */
177 int elem_size1; /* elem size of fetched contours */
179 int header_size2; /* the same for approx. contours */
180 int elem_size2; /* */
181 _CvContourInfo *cinfo_table[126];
185 #define _CV_FIND_CONTOURS_FLAGS_EXTERNAL_ONLY 1
186 #define _CV_FIND_CONTOURS_FLAGS_HIERARCHIC 2
189 Initializes scanner structure.
190 Prepare image for scanning ( clear borders and convert all pixels to 0-1.
192 CV_IMPL CvContourScanner
193 cvStartFindContours( void* _img, CvMemStorage* storage,
194 int header_size, int mode,
195 int method, CvPoint offset )
201 CvContourScanner scanner = 0;
202 CvMat stub, *mat = (CvMat*)_img;
204 CV_FUNCNAME( "cvStartFindContours" );
209 CV_ERROR( CV_StsNullPtr, "" );
211 CV_CALL( mat = cvGetMat( mat, &stub ));
213 if( !CV_IS_MASK_ARR( mat ))
214 CV_ERROR( CV_StsUnsupportedFormat, "[Start]FindContours support only 8uC1 images" );
216 size = cvSize( mat->width, mat->height );
218 img = (uchar*)(mat->data.ptr);
220 if( method < 0 || method > CV_CHAIN_APPROX_TC89_KCOS )
221 CV_ERROR( CV_StsOutOfRange, "" );
223 if( header_size < (int) (method == CV_CHAIN_CODE ? sizeof( CvChain ) : sizeof( CvContour )))
224 CV_ERROR( CV_StsBadSize, "" );
226 scanner = (CvContourScanner)cvAlloc( sizeof( *scanner ));
227 memset( scanner, 0, sizeof( *scanner ));
229 scanner->storage1 = scanner->storage2 = storage;
230 scanner->img0 = (schar *) img;
231 scanner->img = (schar *) (img + step);
232 scanner->img_step = step;
233 scanner->img_size.width = size.width - 1; /* exclude rightest column */
234 scanner->img_size.height = size.height - 1; /* exclude bottomost row */
235 scanner->mode = mode;
236 scanner->offset = offset;
237 scanner->pt.x = scanner->pt.y = 1;
241 scanner->mode = (int) mode;
242 scanner->frame_info.contour = &(scanner->frame);
243 scanner->frame_info.is_hole = 1;
244 scanner->frame_info.next = 0;
245 scanner->frame_info.parent = 0;
246 scanner->frame_info.rect = cvRect( 0, 0, size.width, size.height );
247 scanner->l_cinfo = 0;
248 scanner->subst_flag = 0;
250 scanner->frame.flags = CV_SEQ_FLAG_HOLE;
252 scanner->approx_method2 = scanner->approx_method1 = method;
254 if( method == CV_CHAIN_APPROX_TC89_L1 || method == CV_CHAIN_APPROX_TC89_KCOS )
255 scanner->approx_method1 = CV_CHAIN_CODE;
257 if( scanner->approx_method1 == CV_CHAIN_CODE )
259 scanner->seq_type1 = CV_SEQ_CHAIN_CONTOUR;
260 scanner->header_size1 = scanner->approx_method1 == scanner->approx_method2 ?
261 header_size : sizeof( CvChain );
262 scanner->elem_size1 = sizeof( char );
266 scanner->seq_type1 = CV_SEQ_POLYGON;
267 scanner->header_size1 = scanner->approx_method1 == scanner->approx_method2 ?
268 header_size : sizeof( CvContour );
269 scanner->elem_size1 = sizeof( CvPoint );
272 scanner->header_size2 = header_size;
274 if( scanner->approx_method2 == CV_CHAIN_CODE )
276 scanner->seq_type2 = scanner->seq_type1;
277 scanner->elem_size2 = scanner->elem_size1;
281 scanner->seq_type2 = CV_SEQ_POLYGON;
282 scanner->elem_size2 = sizeof( CvPoint );
285 scanner->seq_type1 = scanner->approx_method1 == CV_CHAIN_CODE ?
286 CV_SEQ_CHAIN_CONTOUR : CV_SEQ_POLYGON;
288 scanner->seq_type2 = scanner->approx_method2 == CV_CHAIN_CODE ?
289 CV_SEQ_CHAIN_CONTOUR : CV_SEQ_POLYGON;
291 cvSaveMemStoragePos( storage, &(scanner->initial_pos) );
293 if( method > CV_CHAIN_APPROX_SIMPLE )
295 scanner->storage1 = cvCreateChildMemStorage( scanner->storage2 );
298 if( mode > CV_RETR_LIST )
300 scanner->cinfo_storage = cvCreateChildMemStorage( scanner->storage2 );
301 scanner->cinfo_set = cvCreateSet( 0, sizeof( CvSet ), sizeof( _CvContourInfo ),
302 scanner->cinfo_storage );
305 /* make zero borders */
306 memset( img, 0, size.width );
307 memset( img + step * (size.height - 1), 0, size.width );
309 for( y = 1, img += step; y < size.height - 1; y++, img += step )
311 img[0] = img[size.width - 1] = 0;
314 /* converts all pixels to 0 or 1 */
315 cvThreshold( mat, mat, 0, 1, CV_THRESH_BINARY );
320 if( cvGetErrStatus() < 0 )
327 Final stage of contour processing.
328 Three variants possible:
329 1. Contour, which was retrieved using border following, is added to
330 the contour tree. It is the case when the icvSubstituteContour function
331 was not called after retrieving the contour.
333 2. New contour, assigned by icvSubstituteContour function, is added to the
334 tree. The retrieved contour itself is removed from the storage.
335 Here two cases are possible:
336 2a. If one deals with plane variant of algorithm
337 (hierarchical strucutre is not reconstructed),
338 the contour is removed completely.
339 2b. In hierarchical case, the header of the contour is not removed.
340 It's marked as "link to contour" and h_next pointer of it is set to
341 new, substituting contour.
343 3. The similar to 2, but when NULL pointer was assigned by
344 icvSubstituteContour function. In this case, the function removes
345 retrieved contour completely if plane case and
346 leaves header if hierarchical (but doesn't mark header as "link").
347 ------------------------------------------------------------------------
348 The 1st variant can be used to retrieve and store all the contours from the image
349 (with optional convertion from chains to contours using some approximation from
350 restriced set of methods). Some characteristics of contour can be computed in the
353 The usage scheme can look like:
355 icvContourScanner scanner;
356 CvMemStorage* contour_storage;
357 CvSeq* first_contour;
362 icvCreateMemStorage( &contour_storage, block_size/0 );
367 ( img, contour_storage,
368 header_size, approx_method,
375 result = icvFindNextContour( &scanner, &contour/0 );
377 if( result != CV_OK ) break;
379 // calculate some characteristics
383 if( result < 0 ) goto error_processing;
385 cvEndFindContours( &scanner, &first_contour );
388 -----------------------------------------------------------------
390 Second variant is more complex and can be used when someone wants store not
391 the retrieved contours but transformed ones. (e.g. approximated with some
392 non-default algorithm ).
394 The scheme can be the as following:
396 icvContourScanner scanner;
397 CvMemStorage* contour_storage;
398 CvMemStorage* temp_storage;
399 CvSeq* first_contour;
404 icvCreateMemStorage( &contour_storage, block_size/0 );
405 icvCreateMemStorage( &temp_storage, block_size/0 );
409 icvStartFindContours8uC1R
410 ( <img_params>, temp_storage,
411 header_size, approx_method,
419 result = icvFindNextContour( scanner, &temp_contour );
421 if( result != CV_OK ) break;
423 <approximation_function>( temp_contour, contour_storage,
424 &new_contour, <parameters...> );
426 icvSubstituteContour( scanner, new_contour );
430 if( result < 0 ) goto error_processing;
432 cvEndFindContours( &scanner, &first_contour );
435 ----------------------------------------------------------------------------
436 Third method to retrieve contours may be applied if contours are irrelevant
437 themselves but some characteristics of them are used only.
438 The usage is similar to second except slightly different internal loop
443 result = icvFindNextContour( &scanner, &temp_contour );
445 if( result != CV_OK ) break;
447 // calculate some characteristics of temp_contour
449 icvSubstituteContour( scanner, 0 );
453 new_storage variable is not needed here.
456 1. Second and third method can interleave. I.e. it is possible to
457 remain contours that satisfy with some criteria and reject others.
458 In hierarchic case the resulting tree is the part of original tree with
459 some nodes absent. But in the resulting tree the contour1 is a child
460 (may be indirect) of contour2 iff in the original tree the contour1
461 is a child (may be indirect) of contour2.
464 icvEndProcessContour( CvContourScanner scanner )
466 _CvContourInfo *l_cinfo = scanner->l_cinfo;
470 if( scanner->subst_flag )
472 CvMemStoragePos temp;
474 cvSaveMemStoragePos( scanner->storage2, &temp );
476 if( temp.top == scanner->backup_pos2.top &&
477 temp.free_space == scanner->backup_pos2.free_space )
479 cvRestoreMemStoragePos( scanner->storage2, &scanner->backup_pos );
481 scanner->subst_flag = 0;
484 if( l_cinfo->contour )
486 cvInsertNodeIntoTree( l_cinfo->contour, l_cinfo->parent->contour,
489 scanner->l_cinfo = 0;
493 /* replaces one contour with another */
495 cvSubstituteContour( CvContourScanner scanner, CvSeq * new_contour )
497 _CvContourInfo *l_cinfo;
499 CV_FUNCNAME( "cvSubstituteContour" );
504 CV_ERROR( CV_StsNullPtr, "" );
506 l_cinfo = scanner->l_cinfo;
507 if( l_cinfo && l_cinfo->contour && l_cinfo->contour != new_contour )
509 l_cinfo->contour = new_contour;
510 scanner->subst_flag = 1;
518 marks domain border with +/-<constant> and stores the contour into CvSeq.
522 >0 - simple approximation
525 icvFetchContour( schar *ptr,
534 schar *i0 = ptr, *i1, *i3, *i4 = 0;
535 int prev_s = -1, s, s_end;
536 int method = _method - 1;
538 assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE );
540 /* initialize local state */
541 CV_INIT_3X3_DELTAS( deltas, step, 1 );
542 memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
544 /* initialize writer */
545 cvStartAppendToSeq( contour, &writer );
548 ((CvChain *) contour)->origin = pt;
550 s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4;
561 if( s == s_end ) /* single pixel domain */
563 *i0 = (schar) (nbd | -128);
566 CV_WRITE_SEQ_ELEM( pt, writer );
581 i4 = i3 + deltas[++s];
587 /* check "right" bound */
588 if( (unsigned) (s - 1) < (unsigned) s_end )
590 *i3 = (schar) (nbd | -128);
599 schar _s = (schar) s;
601 CV_WRITE_SEQ_ELEM( _s, writer );
605 if( s != prev_s || method == 0 )
607 CV_WRITE_SEQ_ELEM( pt, writer );
611 pt.x += icvCodeDeltas[s].x;
612 pt.y += icvCodeDeltas[s].y;
616 if( i4 == i0 && i3 == i1 )
621 } /* end of border following loop */
624 cvEndWriteSeq( &writer );
626 if( _method != CV_CHAIN_CODE )
627 cvBoundingRect( contour, 1 );
629 assert( (writer.seq->total == 0 && writer.seq->first == 0) ||
630 writer.seq->total > writer.seq->first->count ||
631 (writer.seq->first->prev == writer.seq->first &&
632 writer.seq->first->next == writer.seq->first) );
640 trace contour until certain point is met.
641 returns 1 if met, 0 else.
644 icvTraceContour( schar *ptr, int step, schar *stop_ptr, int is_hole )
647 schar *i0 = ptr, *i1, *i3, *i4;
650 /* initialize local state */
651 CV_INIT_3X3_DELTAS( deltas, step, 1 );
652 memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
654 assert( (*i0 & -2) != 0 );
656 s_end = s = is_hole ? 0 : 4;
669 /* check single pixel domain */
679 i4 = i3 + deltas[++s];
684 if( i3 == stop_ptr || (i4 == i0 && i3 == i1) )
689 } /* end of border following loop */
691 return i3 == stop_ptr;
696 icvFetchContourEx( schar* ptr,
706 schar *i0 = ptr, *i1, *i3, *i4;
708 int prev_s = -1, s, s_end;
709 int method = _method - 1;
711 assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE );
712 assert( 1 < nbd && nbd < 128 );
714 /* initialize local state */
715 CV_INIT_3X3_DELTAS( deltas, step, 1 );
716 memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
718 /* initialize writer */
719 cvStartAppendToSeq( contour, &writer );
722 ((CvChain *)contour)->origin = pt;
724 rect.x = rect.width = pt.x;
725 rect.y = rect.height = pt.y;
727 s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4;
738 if( s == s_end ) /* single pixel domain */
740 *i0 = (schar) (nbd | 0x80);
743 CV_WRITE_SEQ_ELEM( pt, writer );
759 i4 = i3 + deltas[++s];
765 /* check "right" bound */
766 if( (unsigned) (s - 1) < (unsigned) s_end )
768 *i3 = (schar) (nbd | 0x80);
777 schar _s = (schar) s;
778 CV_WRITE_SEQ_ELEM( _s, writer );
780 else if( s != prev_s || method == 0 )
782 CV_WRITE_SEQ_ELEM( pt, writer );
790 else if( pt.x > rect.width )
795 else if( pt.y > rect.height )
800 pt.x += icvCodeDeltas[s].x;
801 pt.y += icvCodeDeltas[s].y;
803 if( i4 == i0 && i3 == i1 ) break;
807 } /* end of border following loop */
810 rect.width -= rect.x - 1;
811 rect.height -= rect.y - 1;
813 cvEndWriteSeq( &writer );
815 if( _method != CV_CHAIN_CODE )
816 ((CvContour*)contour)->rect = rect;
818 assert( (writer.seq->total == 0 && writer.seq->first == 0) ||
819 writer.seq->total > writer.seq->first->count ||
820 (writer.seq->first->prev == writer.seq->first &&
821 writer.seq->first->next == writer.seq->first) );
823 if( _rect ) *_rect = rect;
830 cvFindNextContour( CvContourScanner scanner )
842 CvStatus result = (CvStatus) 1;
844 CV_FUNCNAME( "cvFindNextContour" );
849 CV_ERROR( CV_StsNullPtr, "" );
850 icvEndProcessContour( scanner );
852 /* initialize local state */
853 img0 = scanner->img0;
855 step = scanner->img_step;
858 width = scanner->img_size.width;
859 height = scanner->img_size.height;
860 mode = scanner->mode;
861 lnbd = scanner->lnbd;
866 for( ; y < height; y++, img += step )
868 for( ; x < width; x++ )
874 _CvContourInfo *par_info = 0;
875 _CvContourInfo *l_cinfo = 0;
880 if( !(prev == 0 && p == 1) ) /* if not external contour */
883 if( p != 0 || prev < 1 )
893 if( mode == 0 && (is_hole || img0[lnbd.y * step + lnbd.x] > 0) )
897 origin.x = x - is_hole;
899 /* find contour parent */
900 if( mode <= 1 || (!is_hole && mode == 2) || lnbd.x <= 0 )
902 par_info = &(scanner->frame_info);
906 int lval = img0[lnbd.y * step + lnbd.x] & 0x7f;
907 _CvContourInfo *cur = scanner->cinfo_table[lval - 2];
911 /* find the first bounding contour */
914 if( (unsigned) (lnbd.x - cur->rect.x) < (unsigned) cur->rect.width &&
915 (unsigned) (lnbd.y - cur->rect.y) < (unsigned) cur->rect.height )
919 if( icvTraceContour( scanner->img0 +
920 par_info->origin.y * step +
921 par_info->origin.x, step, img + lnbd.x,
922 par_info->is_hole ) > 0 )
930 assert( par_info != 0 );
932 /* if current contour is a hole and previous contour is a hole or
933 current contour is external and previous contour is external then
934 the parent of the contour is the parent of the previous contour else
935 the parent is the previous contour itself. */
936 if( par_info->is_hole == is_hole )
938 par_info = par_info->parent;
939 /* every contour must have a parent
940 (at least, the frame of the image) */
942 par_info = &(scanner->frame_info);
945 /* hole flag of the parent must differ from the flag of the contour */
946 assert( par_info->is_hole != is_hole );
947 if( par_info->contour == 0 ) /* removed contour */
951 lnbd.x = x - is_hole;
953 cvSaveMemStoragePos( scanner->storage2, &(scanner->backup_pos) );
955 seq = cvCreateSeq( scanner->seq_type1, scanner->header_size1,
956 scanner->elem_size1, scanner->storage1 );
957 seq->flags |= is_hole ? CV_SEQ_FLAG_HOLE : 0;
959 /* initialize header */
962 l_cinfo = &(scanner->cinfo_temp);
963 result = icvFetchContour( img + x - is_hole, step,
964 cvPoint( origin.x + scanner->offset.x,
965 origin.y + scanner->offset.y),
966 seq, scanner->approx_method1 );
972 union { _CvContourInfo* ci; CvSetElem* se; } v;
974 cvSetAdd( scanner->cinfo_set, 0, &v.se );
977 result = icvFetchContourEx( img + x - is_hole, step,
978 cvPoint( origin.x + scanner->offset.x,
979 origin.y + scanner->offset.y),
980 seq, scanner->approx_method1,
981 nbd, &(l_cinfo->rect) );
984 l_cinfo->rect.x -= scanner->offset.x;
985 l_cinfo->rect.y -= scanner->offset.y;
987 l_cinfo->next = scanner->cinfo_table[nbd - 2];
988 scanner->cinfo_table[nbd - 2] = l_cinfo;
991 nbd = (nbd + 1) & 127;
992 nbd += nbd == 0 ? 3 : 0;
995 l_cinfo->is_hole = is_hole;
996 l_cinfo->contour = seq;
997 l_cinfo->origin = origin;
998 l_cinfo->parent = par_info;
1000 if( scanner->approx_method1 != scanner->approx_method2 )
1002 result = icvApproximateChainTC89( (CvChain *) seq,
1003 scanner->header_size2,
1005 &(l_cinfo->contour),
1006 scanner->approx_method2 );
1009 cvClearMemStorage( scanner->storage1 );
1012 l_cinfo->contour->v_prev = l_cinfo->parent->contour;
1014 if( par_info->contour == 0 )
1016 l_cinfo->contour = 0;
1017 if( scanner->storage1 == scanner->storage2 )
1019 cvRestoreMemStoragePos( scanner->storage1, &(scanner->backup_pos) );
1023 cvClearMemStorage( scanner->storage1 );
1029 cvSaveMemStoragePos( scanner->storage2, &(scanner->backup_pos2) );
1030 scanner->l_cinfo = l_cinfo;
1031 scanner->pt.x = x + 1;
1033 scanner->lnbd = lnbd;
1034 scanner->img = (schar *) img;
1036 contour = l_cinfo->contour;
1047 } /* end of prev != p */
1048 } /* end of loop on x */
1055 } /* end of loop on y */
1062 CV_ERROR( result, "" );
1071 The function add to tree the last retrieved/substituted contour,
1072 releases temp_storage, restores state of dst_storage (if needed), and
1073 returns pointer to root of the contour tree */
1075 cvEndFindContours( CvContourScanner * _scanner )
1077 CvContourScanner scanner;
1080 CV_FUNCNAME( "cvFindNextContour" );
1085 CV_ERROR( CV_StsNullPtr, "" );
1086 scanner = *_scanner;
1090 icvEndProcessContour( scanner );
1092 if( scanner->storage1 != scanner->storage2 )
1093 cvReleaseMemStorage( &(scanner->storage1) );
1095 if( scanner->cinfo_storage )
1096 cvReleaseMemStorage( &(scanner->cinfo_storage) );
1098 first = scanner->frame.v_next;
1108 #define ICV_SINGLE 0
1109 #define ICV_CONNECTING_ABOVE 1
1110 #define ICV_CONNECTING_BELOW -1
1111 #define ICV_IS_COMPONENT_POINT(val) ((val) != 0)
1113 #define CV_GET_WRITTEN_ELEM( writer ) ((writer).ptr - (writer).seq->elem_size)
1115 typedef struct CvLinkedRunPoint
1117 struct CvLinkedRunPoint* link;
1118 struct CvLinkedRunPoint* next;
1125 icvFindContoursInInterval( const CvArr* src,
1126 /*int minValue, int maxValue,*/
1127 CvMemStorage* storage,
1129 int contourHeaderSize )
1132 CvMemStorage* storage00 = 0;
1133 CvMemStorage* storage01 = 0;
1136 CV_FUNCNAME( "icvFindContoursInInterval" );
1142 uchar* src_data = 0;
1152 CvLinkedRunPoint tmp;
1153 CvLinkedRunPoint* tmp_prev;
1154 CvLinkedRunPoint* upper_line = 0;
1155 CvLinkedRunPoint* lower_line = 0;
1156 CvLinkedRunPoint* last_elem;
1158 CvLinkedRunPoint* upper_run = 0;
1159 CvLinkedRunPoint* lower_run = 0;
1160 CvLinkedRunPoint* prev_point = 0;
1162 CvSeqWriter writer_ext;
1163 CvSeqWriter writer_int;
1167 CvSeq* external_contours;
1168 CvSeq* internal_contours;
1172 CV_ERROR( CV_StsNullPtr, "NULL storage pointer" );
1175 CV_ERROR( CV_StsNullPtr, "NULL double CvSeq pointer" );
1177 if( contourHeaderSize < (int)sizeof(CvContour))
1178 CV_ERROR( CV_StsBadSize, "Contour header size must be >= sizeof(CvContour)" );
1180 CV_CALL( storage00 = cvCreateChildMemStorage(storage));
1181 CV_CALL( storage01 = cvCreateChildMemStorage(storage));
1186 CV_CALL( mat = cvGetMat( src, &stub ));
1187 if( !CV_IS_MASK_ARR(mat))
1188 CV_ERROR( CV_StsBadArg, "Input array must be 8uC1 or 8sC1" );
1189 src_data = mat->data.ptr;
1190 img_step = mat->step;
1191 img_size = cvGetMatSize( mat );
1194 // Create temporary sequences
1195 runs = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvLinkedRunPoint), storage00 );
1196 cvStartAppendToSeq( runs, &writer );
1198 cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_ext );
1199 cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_int );
1205 // First line. None of runs is binded
1208 CV_WRITE_SEQ_ELEM( tmp, writer );
1209 upper_line = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1211 tmp_prev = upper_line;
1212 for( j = 0; j < img_size.width; )
1214 for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
1216 if( j == img_size.width )
1220 CV_WRITE_SEQ_ELEM( tmp, writer );
1221 tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1222 tmp_prev = tmp_prev->next;
1224 for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
1228 CV_WRITE_SEQ_ELEM( tmp, writer );
1229 tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1230 tmp_prev->link = tmp_prev->next;
1231 // First point of contour
1232 CV_WRITE_SEQ_ELEM( tmp_prev, writer_ext );
1233 tmp_prev = tmp_prev->next;
1235 cvFlushSeqWriter( &writer );
1236 upper_line = upper_line->next;
1237 upper_total = runs->total - 1;
1238 last_elem = tmp_prev;
1241 for( i = 1; i < img_size.height; i++ )
1243 //------// Find runs in next line
1244 src_data += img_step;
1246 all_total = runs->total;
1247 for( j = 0; j < img_size.width; )
1249 for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
1251 if( j == img_size.width ) break;
1254 CV_WRITE_SEQ_ELEM( tmp, writer );
1255 tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1256 tmp_prev = tmp_prev->next;
1258 for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
1262 CV_WRITE_SEQ_ELEM( tmp, writer );
1263 tmp_prev = tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1265 cvFlushSeqWriter( &writer );
1266 lower_line = last_elem->next;
1267 lower_total = runs->total - all_total;
1268 last_elem = tmp_prev;
1271 //------// Find links between runs of lower_line and upper_line
1272 upper_run = upper_line;
1273 lower_run = lower_line;
1274 connect_flag = ICV_SINGLE;
1276 for( k = 0, n = 0; k < upper_total/2 && n < lower_total/2; )
1278 switch( connect_flag )
1281 if( upper_run->next->pt.x < lower_run->next->pt.x )
1283 if( upper_run->next->pt.x >= lower_run->pt.x -1 )
1285 lower_run->link = upper_run;
1286 connect_flag = ICV_CONNECTING_ABOVE;
1287 prev_point = upper_run->next;
1290 upper_run->next->link = upper_run;
1292 upper_run = upper_run->next->next;
1296 if( upper_run->pt.x <= lower_run->next->pt.x +1 )
1298 lower_run->link = upper_run;
1299 connect_flag = ICV_CONNECTING_BELOW;
1300 prev_point = lower_run->next;
1304 lower_run->link = lower_run->next;
1305 // First point of contour
1306 CV_WRITE_SEQ_ELEM( lower_run, writer_ext );
1309 lower_run = lower_run->next->next;
1312 case ICV_CONNECTING_ABOVE:
1313 if( upper_run->pt.x > lower_run->next->pt.x +1 )
1315 prev_point->link = lower_run->next;
1316 connect_flag = ICV_SINGLE;
1318 lower_run = lower_run->next->next;
1322 prev_point->link = upper_run;
1323 if( upper_run->next->pt.x < lower_run->next->pt.x )
1326 prev_point = upper_run->next;
1327 upper_run = upper_run->next->next;
1331 connect_flag = ICV_CONNECTING_BELOW;
1332 prev_point = lower_run->next;
1334 lower_run = lower_run->next->next;
1338 case ICV_CONNECTING_BELOW:
1339 if( lower_run->pt.x > upper_run->next->pt.x +1 )
1341 upper_run->next->link = prev_point;
1342 connect_flag = ICV_SINGLE;
1344 upper_run = upper_run->next->next;
1348 // First point of contour
1349 CV_WRITE_SEQ_ELEM( lower_run, writer_int );
1351 lower_run->link = prev_point;
1352 if( lower_run->next->pt.x < upper_run->next->pt.x )
1355 prev_point = lower_run->next;
1356 lower_run = lower_run->next->next;
1360 connect_flag = ICV_CONNECTING_ABOVE;
1362 prev_point = upper_run->next;
1363 upper_run = upper_run->next->next;
1370 for( ; n < lower_total/2; n++ )
1372 if( connect_flag != ICV_SINGLE )
1374 prev_point->link = lower_run->next;
1375 connect_flag = ICV_SINGLE;
1376 lower_run = lower_run->next->next;
1379 lower_run->link = lower_run->next;
1381 //First point of contour
1382 CV_WRITE_SEQ_ELEM( lower_run, writer_ext );
1384 lower_run = lower_run->next->next;
1387 for( ; k < upper_total/2; k++ )
1389 if( connect_flag != ICV_SINGLE )
1391 upper_run->next->link = prev_point;
1392 connect_flag = ICV_SINGLE;
1393 upper_run = upper_run->next->next;
1396 upper_run->next->link = upper_run;
1397 upper_run = upper_run->next->next;
1399 upper_line = lower_line;
1400 upper_total = lower_total;
1403 upper_run = upper_line;
1405 //the last line of image
1406 for( k = 0; k < upper_total/2; k++ )
1408 upper_run->next->link = upper_run;
1409 upper_run = upper_run->next->next;
1413 //------//Find end read contours
1414 external_contours = cvEndWriteSeq( &writer_ext );
1415 internal_contours = cvEndWriteSeq( &writer_int );
1417 for( k = 0; k < 2; k++ )
1419 CvSeq* contours = k == 0 ? external_contours : internal_contours;
1421 cvStartReadSeq( contours, &reader );
1423 for( j = 0; j < contours->total; j++, count++ )
1425 CvLinkedRunPoint* p_temp;
1426 CvLinkedRunPoint* p00;
1427 CvLinkedRunPoint* p01;
1430 CV_READ_SEQ_ELEM( p00, reader );
1436 cvStartWriteSeq( CV_SEQ_ELTYPE_POINT | CV_SEQ_POLYLINE | CV_SEQ_FLAG_CLOSED,
1437 contourHeaderSize, sizeof(CvPoint), storage, &writer );
1440 CV_WRITE_SEQ_ELEM( p00->pt, writer );
1445 while( p00 != p01 );
1447 contour = cvEndWriteSeq( &writer );
1448 cvBoundingRect( contour, 1 );
1451 contour->flags |= CV_SEQ_FLAG_HOLE;
1454 prev = first = contour;
1457 contour->h_prev = prev;
1458 prev = prev->h_next = contour;
1471 cvReleaseMemStorage(&storage00);
1472 cvReleaseMemStorage(&storage01);
1479 /*F///////////////////////////////////////////////////////////////////////////////////////
1480 // Name: cvFindContours
1482 // Finds all the contours on the bi-level image.
1485 // img - source image.
1486 // Non-zero pixels are considered as 1-pixels
1487 // and zero pixels as 0-pixels.
1488 // step - full width of source image in bytes.
1489 // size - width and height of the image in pixels
1490 // storage - pointer to storage where will the output contours be placed.
1491 // header_size - header size of resulting contours
1492 // mode - mode of contour retrieval.
1493 // method - method of approximation that is applied to contours
1494 // first_contour - pointer to first contour pointer
1496 // CV_OK or error code
1500 cvFindContours( void* img, CvMemStorage* storage,
1501 CvSeq** firstContour, int cntHeaderSize,
1503 int method, CvPoint offset )
1505 CvContourScanner scanner = 0;
1509 CV_FUNCNAME( "cvFindContours" );
1514 CV_ERROR( CV_StsNullPtr, "NULL double CvSeq pointer" );
1516 if( method == CV_LINK_RUNS )
1518 if( offset.x != 0 || offset.y != 0 )
1519 CV_ERROR( CV_StsOutOfRange,
1520 "Nonzero offset is not supported in CV_LINK_RUNS yet" );
1522 CV_CALL( count = icvFindContoursInInterval( img, storage,
1523 firstContour, cntHeaderSize ));
1527 CV_CALL( scanner = cvStartFindContours( img, storage,
1528 cntHeaderSize, mode, method, offset ));
1534 contour = cvFindNextContour( scanner );
1536 while( contour != 0 );
1538 *firstContour = cvEndFindContours( &scanner );
1549 _findContours( const Mat& image, vector<vector<Point> >& contours,
1550 vector<Vec4i>* hierarchy, int mode, int method, Point offset )
1552 MemStorage storage(cvCreateMemStorage());
1553 CvMat _image = image;
1554 CvSeq* _contours = 0;
1557 cvFindContours(&_image, storage, &_contours, sizeof(CvContour), mode, method, offset);
1563 Seq<CvSeq*> all_contours(cvTreeToNodeSeq( _contours, sizeof(CvSeq), storage ));
1564 size_t i, total = all_contours.size();
1565 contours.resize(total);
1566 SeqIterator<CvSeq*> it = all_contours.begin();
1567 for( i = 0; i < total; i++, ++it )
1570 ((CvContour*)c)->color = (int)i;
1571 Seq<Point>(c).copyTo(contours[i]);
1576 hierarchy->resize(total);
1577 it = all_contours.begin();
1578 for( i = 0; i < total; i++, ++it )
1581 int h_next = c->h_next ? ((CvContour*)c->h_next)->color : -1;
1582 int h_prev = c->h_next ? ((CvContour*)c->h_next)->color : -1;
1583 int v_next = c->h_next ? ((CvContour*)c->h_next)->color : -1;
1584 int v_prev = c->h_next ? ((CvContour*)c->h_next)->color : -1;
1585 (*hierarchy)[i] = Vec4i(h_next, h_prev, v_next, v_prev);
1591 void cv::findContours( const Mat& image, vector<vector<Point> >& contours,
1592 vector<Vec4i>& hierarchy, int mode, int method, Point offset )
1594 _findContours(image, contours, &hierarchy, mode, method, offset);
1597 void cv::findContours( const Mat& image, vector<vector<Point> >& contours,
1598 int mode, int method, Point offset)
1600 _findContours(image, contours, 0, mode, method, offset);
1606 static void addChildContour(const vector<vector<Point> >& contours,
1607 const vector<Vec4i>& hierarchy,
1608 int i, vector<CvSeq>& seq,
1609 vector<CvSeqBlock>& block)
1611 size_t count = contours.size();
1612 for( ; i >= 0; i = hierarchy[i][0] )
1614 const vector<Point>& ci = contours[i];
1615 cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
1616 !ci.empty() ? (void*)&ci[0] : 0, (int)ci.size(),
1617 &seq[i], &block[i] );
1619 int h_next = hierarchy[i][0], h_prev = hierarchy[i][1],
1620 v_next = hierarchy[i][2], v_prev = hierarchy[i][3];
1621 seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0;
1622 seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0;
1623 seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0;
1624 seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0;
1627 addChildContour(contours, hierarchy, v_next, seq, block);
1633 void cv::drawContours( Mat& image, const vector<vector<Point> >& contours,
1634 int contourIdx, const Scalar& color, int thickness,
1635 int lineType, const vector<Vec4i>& hierarchy,
1636 int maxLevel, Point offset )
1638 CvMat _image = image;
1640 size_t i = 0, first = 0, last = contours.size();
1642 vector<CvSeqBlock> block;
1647 for( i = first; i < last; i++ )
1650 if( contourIdx >= 0 )
1652 CV_Assert( 0 <= contourIdx && contourIdx < (int)last );
1654 last = contourIdx + 1;
1657 for( i = first; i < last; i++ )
1659 const vector<Point>& ci = contours[i];
1660 cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
1661 !ci.empty() ? (void*)&ci[0] : 0, (int)ci.size(), &seq[i], &block[i] );
1664 if( hierarchy.empty() || maxLevel == 0 || maxLevel == INT_MAX )
1665 for( i = first; i < last; i++ )
1667 seq[i].h_next = i < last-1 ? &seq[i+1] : 0;
1668 seq[i].h_prev = i > first ? &seq[i-1] : 0;
1672 size_t count = last - first;
1673 CV_Assert(hierarchy.size() == contours.size());
1674 if( count == contours.size() )
1676 for( i = first; i < last; i++ )
1678 int h_next = hierarchy[i][0], h_prev = hierarchy[i][1],
1679 v_next = hierarchy[i][2], v_prev = hierarchy[i][3];
1680 seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0;
1681 seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0;
1682 seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0;
1683 seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0;
1688 int child = hierarchy[first][2];
1691 addChildContour(contours, hierarchy, child, seq, block);
1692 seq[first].v_next = &seq[child];
1697 cvDrawContours( &_image, &seq[first], color, color, contourIdx >= 0 ?
1698 -maxLevel : maxLevel, thickness, lineType, offset );
1701 void cv::approxPolyDP( const Mat& curve, vector<Point>& approxCurve,
1702 double epsilon, bool closed )
1704 CV_Assert(curve.isContinuous() && curve.depth() == CV_32S &&
1705 ((curve.rows == 1 && curve.channels() == 2) ||
1706 curve.cols*curve.channels() == 2));
1707 CvMat _curve = curve;
1708 MemStorage storage(cvCreateMemStorage());
1709 Seq<Point> seq(cvApproxPoly(&_curve, sizeof(CvContour), storage, CV_POLY_APPROX_DP, epsilon, closed));
1710 seq.copyTo(approxCurve);
1713 void cv::approxPolyDP( const Mat& curve, vector<Point2f>& approxCurve,
1714 double epsilon, bool closed )
1716 CV_Assert(curve.isContinuous() && curve.depth() == CV_32F &&
1717 ((curve.rows == 1 && curve.channels() == 2) ||
1718 curve.cols*curve.channels() == 2));
1719 CvMat _curve = curve;
1720 MemStorage storage(cvCreateMemStorage());
1721 Seq<Point2f> seq(cvApproxPoly(&_curve, sizeof(CvContour), storage, CV_POLY_APPROX_DP, epsilon, closed));
1722 seq.copyTo(approxCurve);
1725 double cv::arcLength( const Mat& curve, bool closed )
1727 CV_Assert(curve.isContinuous() &&
1728 (curve.depth() == CV_32S || curve.depth() == CV_32F) &&
1729 ((curve.rows == 1 && curve.channels() == 2) ||
1730 curve.cols*curve.channels() == 2));
1731 CvMat _curve = curve;
1732 return cvArcLength(&_curve, CV_WHOLE_SEQ, closed);
1736 cv::Rect cv::boundingRect( const Mat& points )
1738 CV_Assert(points.isContinuous() &&
1739 (points.depth() == CV_32S || points.depth() == CV_32F) &&
1740 ((points.rows == 1 && points.channels() == 2) ||
1741 points.cols*points.channels() == 2));
1742 CvMat _points = points;
1743 return cvBoundingRect(&_points, 0);
1747 double cv::contourArea( const Mat& contour )
1749 CV_Assert(contour.isContinuous() &&
1750 (contour.depth() == CV_32S || contour.depth() == CV_32F) &&
1751 ((contour.rows == 1 && contour.channels() == 2) ||
1752 contour.cols*contour.channels() == 2));
1753 CvMat _contour = contour;
1754 return cvContourArea(&_contour);
1758 cv::RotatedRect cv::minAreaRect( const Mat& points )
1760 CV_Assert(points.isContinuous() &&
1761 (points.depth() == CV_32S || points.depth() == CV_32F) &&
1762 ((points.rows == 1 && points.channels() == 2) ||
1763 points.cols*points.channels() == 2));
1764 CvMat _points = points;
1765 return cvMinAreaRect2(&_points, 0);
1769 void cv::minEnclosingCircle( const Mat& points,
1770 Point2f& center, float& radius )
1772 CV_Assert(points.isContinuous() &&
1773 (points.depth() == CV_32S || points.depth() == CV_32F) &&
1774 ((points.rows == 1 && points.channels() == 2) ||
1775 points.cols*points.channels() == 2));
1776 CvMat _points = points;
1777 cvMinEnclosingCircle( &_points, (CvPoint2D32f*)¢er, &radius );
1781 double cv::matchShapes( const Mat& contour1,
1782 const Mat& contour2,
1783 int method, double parameter )
1785 CV_Assert(contour1.isContinuous() && contour2.isContinuous() &&
1786 (contour1.depth() == CV_32S || contour1.depth() == CV_32F) &&
1787 contour1.depth() == contour2.depth() &&
1788 ((contour1.rows == 1 && contour1.channels() == 2 &&
1789 contour2.rows == 1 && contour2.channels() == 2) ||
1790 (contour1.cols*contour1.channels() == 2 &&
1791 contour2.cols*contour2.channels() == 2)));
1793 CvMat c1 = Mat(contour1), c2 = Mat(contour2);
1794 return cvMatchShapes(&c1, &c2, method, parameter);
1798 void cv::convexHull( const Mat& points, vector<int>& hull, bool clockwise )
1800 CV_Assert(points.isContinuous() &&
1801 (points.depth() == CV_32S || points.depth() == CV_32F) &&
1802 ((points.rows == 1 && points.channels() == 2) ||
1803 points.cols*points.channels() == 2));
1804 hull.resize(points.cols*points.rows*points.channels()/2);
1805 CvMat _points = Mat(points), _hull=Mat(hull);
1806 cvConvexHull2(&_points, &_hull, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 0);
1807 hull.resize(_hull.cols + _hull.rows - 1);
1811 void cv::convexHull( const Mat& points,
1812 vector<Point>& hull, bool clockwise )
1814 CV_Assert(points.isContinuous() && points.depth() == CV_32S &&
1815 ((points.rows == 1 && points.channels() == 2) ||
1816 points.cols*points.channels() == 2));
1817 hull.resize(points.cols*points.rows*points.channels()/2);
1818 CvMat _points = Mat(points), _hull=Mat(hull);
1819 cvConvexHull2(&_points, &_hull, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 1);
1820 hull.resize(_hull.cols + _hull.rows - 1);
1824 void cv::convexHull( const Mat& points,
1825 vector<Point2f>& hull, bool clockwise )
1827 CV_Assert(points.isContinuous() && points.depth() == CV_32F &&
1828 ((points.rows == 1 && points.channels() == 2) ||
1829 points.cols*points.channels() == 2));
1830 hull.resize(points.cols*points.rows*points.channels()/2);
1831 CvMat _points = Mat(points), _hull=Mat(hull);
1832 cvConvexHull2(&_points, &_hull, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 1);
1833 hull.resize(_hull.cols + _hull.rows - 1);
1836 bool cv::isContourConvex( const Mat& contour )
1838 CV_Assert(contour.isContinuous() &&
1839 (contour.depth() == CV_32S || contour.depth() == CV_32F) &&
1840 ((contour.rows == 1 && contour.channels() == 2) ||
1841 contour.cols*contour.channels() == 2));
1842 CvMat c = Mat(contour);
1843 return cvCheckContourConvexity(&c) > 0;
1846 cv::RotatedRect cv::fitEllipse( const Mat& points )
1848 CV_Assert(points.isContinuous() &&
1849 (points.depth() == CV_32S || points.depth() == CV_32F) &&
1850 ((points.rows == 1 && points.channels() == 2) ||
1851 points.cols*points.channels() == 2));
1852 CvMat _points = points;
1853 return cvFitEllipse2(&_points);
1857 void cv::fitLine( const Mat& points, Vec4f& line, int distType,
1858 double param, double reps, double aeps )
1860 CV_Assert(points.isContinuous() &&
1861 (points.depth() == CV_32S || points.depth() == CV_32F) &&
1862 ((points.rows == 1 && points.channels() == 2) ||
1863 points.cols*points.channels() == 2));
1864 CvMat _points = points;
1865 cvFitLine(&_points, distType, param, reps, aeps, &line[0]);
1869 void cv::fitLine( const Mat& points, Vec6f& line, int distType,
1870 double param, double reps, double aeps )
1872 CV_Assert(points.isContinuous() &&
1873 (points.depth() == CV_32S || points.depth() == CV_32F) &&
1874 ((points.rows == 1 && points.channels() == 3) ||
1875 points.cols*points.channels() == 3));
1876 CvMat _points = points;
1877 cvFitLine(&_points, distType, param, reps, aeps, &line[0]);
1880 double cv::pointPolygonTest( const Mat& contour,
1881 Point2f pt, bool measureDist )
1883 CV_Assert(contour.isContinuous() &&
1884 (contour.depth() == CV_32S || contour.depth() == CV_32F) &&
1885 ((contour.rows == 1 && contour.channels() == 2) ||
1886 contour.cols*contour.channels() == 2));
1887 CvMat c = Mat(contour);
1888 return cvPointPolygonTest( &c, pt, measureDist );