imagecore 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/.gitignore +24 -0
  2. data/Gemfile +4 -0
  3. data/Rakefile +2 -0
  4. data/ext/imagecore/analyze_image.cxx +58 -0
  5. data/ext/imagecore/analyze_image.h +6 -0
  6. data/ext/imagecore/extconf.rb +9 -0
  7. data/ext/imagecore/imagecore.cxx +34 -0
  8. data/ext/opencv/core/___.c +3 -0
  9. data/ext/opencv/core/alloc.cpp +697 -0
  10. data/ext/opencv/core/array.cpp +3206 -0
  11. data/ext/opencv/core/datastructs.cpp +4064 -0
  12. data/ext/opencv/core/extconf.rb +22 -0
  13. data/ext/opencv/core/matrix.cpp +3777 -0
  14. data/ext/opencv/core/precomp.hpp +216 -0
  15. data/ext/opencv/core/system.cpp +832 -0
  16. data/ext/opencv/core/tables.cpp +3512 -0
  17. data/ext/opencv/highgui/___.c +3 -0
  18. data/ext/opencv/highgui/bitstrm.cpp +582 -0
  19. data/ext/opencv/highgui/bitstrm.hpp +182 -0
  20. data/ext/opencv/highgui/extconf.rb +28 -0
  21. data/ext/opencv/highgui/grfmt_base.cpp +128 -0
  22. data/ext/opencv/highgui/grfmt_base.hpp +113 -0
  23. data/ext/opencv/highgui/grfmt_bmp.cpp +564 -0
  24. data/ext/opencv/highgui/grfmt_bmp.hpp +99 -0
  25. data/ext/opencv/highgui/grfmt_exr.hpp +113 -0
  26. data/ext/opencv/highgui/grfmt_imageio.hpp +56 -0
  27. data/ext/opencv/highgui/grfmt_jpeg.cpp +622 -0
  28. data/ext/opencv/highgui/grfmt_jpeg.hpp +90 -0
  29. data/ext/opencv/highgui/grfmt_jpeg2000.cpp +529 -0
  30. data/ext/opencv/highgui/grfmt_jpeg2000.hpp +95 -0
  31. data/ext/opencv/highgui/grfmt_png.cpp +406 -0
  32. data/ext/opencv/highgui/grfmt_png.hpp +101 -0
  33. data/ext/opencv/highgui/grfmt_pxm.cpp +513 -0
  34. data/ext/opencv/highgui/grfmt_pxm.hpp +92 -0
  35. data/ext/opencv/highgui/grfmt_sunras.cpp +425 -0
  36. data/ext/opencv/highgui/grfmt_sunras.hpp +105 -0
  37. data/ext/opencv/highgui/grfmt_tiff.cpp +718 -0
  38. data/ext/opencv/highgui/grfmt_tiff.hpp +136 -0
  39. data/ext/opencv/highgui/grfmts.hpp +56 -0
  40. data/ext/opencv/highgui/loadsave.cpp +535 -0
  41. data/ext/opencv/highgui/precomp.hpp +223 -0
  42. data/ext/opencv/highgui/utils.cpp +689 -0
  43. data/ext/opencv/highgui/utils.hpp +128 -0
  44. data/ext/opencv/imgproc/___.c +3 -0
  45. data/ext/opencv/imgproc/_geom.h +72 -0
  46. data/ext/opencv/imgproc/color.cpp +3179 -0
  47. data/ext/opencv/imgproc/contours.cpp +1780 -0
  48. data/ext/opencv/imgproc/extconf.rb +11 -0
  49. data/ext/opencv/imgproc/filter.cpp +3063 -0
  50. data/ext/opencv/imgproc/precomp.hpp +159 -0
  51. data/ext/opencv/imgproc/shapedescr.cpp +1306 -0
  52. data/ext/opencv/imgproc/smooth.cpp +1566 -0
  53. data/ext/opencv/imgproc/tables.cpp +214 -0
  54. data/ext/opencv/imgproc/thresh.cpp +636 -0
  55. data/ext/opencv/imgproc/utils.cpp +242 -0
  56. data/ext/opencv/include/opencv2/core/core.hpp +4344 -0
  57. data/ext/opencv/include/opencv2/core/core_c.h +1885 -0
  58. data/ext/opencv/include/opencv2/core/internal.hpp +710 -0
  59. data/ext/opencv/include/opencv2/core/mat.hpp +2557 -0
  60. data/ext/opencv/include/opencv2/core/operations.hpp +3623 -0
  61. data/ext/opencv/include/opencv2/core/types_c.h +1875 -0
  62. data/ext/opencv/include/opencv2/core/version.hpp +58 -0
  63. data/ext/opencv/include/opencv2/highgui/highgui.hpp +198 -0
  64. data/ext/opencv/include/opencv2/highgui/highgui_c.h +506 -0
  65. data/ext/opencv/include/opencv2/imgproc/imgproc.hpp +1139 -0
  66. data/ext/opencv/include/opencv2/imgproc/imgproc_c.h +783 -0
  67. data/ext/opencv/include/opencv2/imgproc/types_c.h +538 -0
  68. data/imagecore.gemspec +20 -0
  69. data/lib/imagecore.rb +16 -0
  70. data/lib/imagecore/version.rb +3 -0
  71. metadata +119 -0
@@ -0,0 +1,1780 @@
1
+ /*M///////////////////////////////////////////////////////////////////////////////////////
2
+ //
3
+ // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4
+ //
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.
8
+ //
9
+ //
10
+ // Intel License Agreement
11
+ // For Open Source Computer Vision Library
12
+ //
13
+ // Copyright (C) 2000, Intel Corporation, all rights reserved.
14
+ // Third party copyrights are property of their respective owners.
15
+ //
16
+ // Redistribution and use in source and binary forms, with or without modification,
17
+ // are permitted provided that the following conditions are met:
18
+ //
19
+ // * Redistribution's of source code must retain the above copyright notice,
20
+ // this list of conditions and the following disclaimer.
21
+ //
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.
25
+ //
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.
28
+ //
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.
39
+ //
40
+ //M*/
41
+ #include "precomp.hpp"
42
+
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))
49
+
50
+ static const CvPoint icvCodeDeltas[8] =
51
+ { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
52
+
53
+ CV_IMPL void
54
+ cvStartReadChainPoints( CvChain * chain, CvChainPtReader * reader )
55
+ {
56
+ int i;
57
+
58
+ if( !chain || !reader )
59
+ CV_Error( CV_StsNullPtr, "" );
60
+
61
+ if( chain->elem_size != 1 || chain->header_size < (int)sizeof(CvChain))
62
+ CV_Error( CV_StsBadSize, "" );
63
+
64
+ cvStartReadSeq( (CvSeq *) chain, (CvSeqReader *) reader, 0 );
65
+
66
+ reader->pt = chain->origin;
67
+ for( i = 0; i < 8; i++ )
68
+ {
69
+ reader->deltas[i][0] = (schar) icvCodeDeltas[i].x;
70
+ reader->deltas[i][1] = (schar) icvCodeDeltas[i].y;
71
+ }
72
+ }
73
+
74
+
75
+ /* retrieves next point of the chain curve and updates reader */
76
+ CV_IMPL CvPoint
77
+ cvReadChainPoint( CvChainPtReader * reader )
78
+ {
79
+ schar *ptr;
80
+ int code;
81
+ CvPoint pt = { 0, 0 };
82
+
83
+ if( !reader )
84
+ CV_Error( CV_StsNullPtr, "" );
85
+
86
+ pt = reader->pt;
87
+
88
+ ptr = reader->ptr;
89
+ if( ptr )
90
+ {
91
+ code = *ptr++;
92
+
93
+ if( ptr >= reader->block_max )
94
+ {
95
+ cvChangeSeqBlock( (CvSeqReader *) reader, 1 );
96
+ ptr = reader->ptr;
97
+ }
98
+
99
+ reader->ptr = ptr;
100
+ reader->code = (schar)code;
101
+ assert( (code & ~7) == 0 );
102
+ reader->pt.x = pt.x + icvCodeDeltas[code].x;
103
+ reader->pt.y = pt.y + icvCodeDeltas[code].y;
104
+ }
105
+
106
+ return pt;
107
+ }
108
+
109
+
110
+ /****************************************************************************************\
111
+ * Raster->Chain Tree (Suzuki algorithms) *
112
+ \****************************************************************************************/
113
+
114
+ typedef struct _CvContourInfo
115
+ {
116
+ int flags;
117
+ struct _CvContourInfo *next; /* next contour with the same mark value */
118
+ struct _CvContourInfo *parent; /* information about parent contour */
119
+ CvSeq *contour; /* corresponding contour (may be 0, if rejected) */
120
+ CvRect rect; /* bounding rectangle */
121
+ CvPoint origin; /* origin point (where the contour was traced from) */
122
+ int is_hole; /* hole flag */
123
+ }
124
+ _CvContourInfo;
125
+
126
+
127
+ /*
128
+ Structure that is used for sequental retrieving contours from the image.
129
+ It supports both hierarchical and plane variants of Suzuki algorithm.
130
+ */
131
+ typedef struct _CvContourScanner
132
+ {
133
+ CvMemStorage *storage1; /* contains fetched contours */
134
+ CvMemStorage *storage2; /* contains approximated contours
135
+ (!=storage1 if approx_method2 != approx_method1) */
136
+ CvMemStorage *cinfo_storage; /* contains _CvContourInfo nodes */
137
+ CvSet *cinfo_set; /* set of _CvContourInfo nodes */
138
+ CvMemStoragePos initial_pos; /* starting storage pos */
139
+ CvMemStoragePos backup_pos; /* beginning of the latest approx. contour */
140
+ CvMemStoragePos backup_pos2; /* ending of the latest approx. contour */
141
+ schar *img0; /* image origin */
142
+ schar *img; /* current image row */
143
+ int img_step; /* image step */
144
+ CvSize img_size; /* ROI size */
145
+ CvPoint offset; /* ROI offset: coordinates, added to each contour point */
146
+ CvPoint pt; /* current scanner position */
147
+ CvPoint lnbd; /* position of the last met contour */
148
+ int nbd; /* current mark val */
149
+ _CvContourInfo *l_cinfo; /* information about latest approx. contour */
150
+ _CvContourInfo cinfo_temp; /* temporary var which is used in simple modes */
151
+ _CvContourInfo frame_info; /* information about frame */
152
+ CvSeq frame; /* frame itself */
153
+ int approx_method1; /* approx method when tracing */
154
+ int approx_method2; /* final approx method */
155
+ int mode; /* contour scanning mode:
156
+ 0 - external only
157
+ 1 - all the contours w/o any hierarchy
158
+ 2 - connected components (i.e. two-level structure -
159
+ external contours and holes) */
160
+ int subst_flag;
161
+ int seq_type1; /* type of fetched contours */
162
+ int header_size1; /* hdr size of fetched contours */
163
+ int elem_size1; /* elem size of fetched contours */
164
+ int seq_type2; /* */
165
+ int header_size2; /* the same for approx. contours */
166
+ int elem_size2; /* */
167
+ _CvContourInfo *cinfo_table[126];
168
+ }
169
+ _CvContourScanner;
170
+
171
+ #define _CV_FIND_CONTOURS_FLAGS_EXTERNAL_ONLY 1
172
+ #define _CV_FIND_CONTOURS_FLAGS_HIERARCHIC 2
173
+
174
+ /*
175
+ Initializes scanner structure.
176
+ Prepare image for scanning ( clear borders and convert all pixels to 0-1.
177
+ */
178
+ CV_IMPL CvContourScanner
179
+ cvStartFindContours( void* _img, CvMemStorage* storage,
180
+ int header_size, int mode,
181
+ int method, CvPoint offset )
182
+ {
183
+ int y;
184
+ int step;
185
+ CvSize size;
186
+ uchar *img = 0;
187
+ CvContourScanner scanner = 0;
188
+
189
+ if( !storage )
190
+ CV_Error( CV_StsNullPtr, "" );
191
+
192
+ CvMat stub, *mat = cvGetMat( _img, &stub );
193
+
194
+ if( !CV_IS_MASK_ARR( mat ))
195
+ CV_Error( CV_StsUnsupportedFormat, "[Start]FindContours support only 8uC1 images" );
196
+
197
+ size = cvSize( mat->width, mat->height );
198
+ step = mat->step;
199
+ img = (uchar*)(mat->data.ptr);
200
+
201
+ if( method < 0 || method > CV_CHAIN_APPROX_TC89_KCOS )
202
+ CV_Error( CV_StsOutOfRange, "" );
203
+
204
+ if( header_size < (int) (method == CV_CHAIN_CODE ? sizeof( CvChain ) : sizeof( CvContour )))
205
+ CV_Error( CV_StsBadSize, "" );
206
+
207
+ scanner = (CvContourScanner)cvAlloc( sizeof( *scanner ));
208
+ memset( scanner, 0, sizeof( *scanner ));
209
+
210
+ scanner->storage1 = scanner->storage2 = storage;
211
+ scanner->img0 = (schar *) img;
212
+ scanner->img = (schar *) (img + step);
213
+ scanner->img_step = step;
214
+ scanner->img_size.width = size.width - 1; /* exclude rightest column */
215
+ scanner->img_size.height = size.height - 1; /* exclude bottomost row */
216
+ scanner->mode = mode;
217
+ scanner->offset = offset;
218
+ scanner->pt.x = scanner->pt.y = 1;
219
+ scanner->lnbd.x = 0;
220
+ scanner->lnbd.y = 1;
221
+ scanner->nbd = 2;
222
+ scanner->mode = (int) mode;
223
+ scanner->frame_info.contour = &(scanner->frame);
224
+ scanner->frame_info.is_hole = 1;
225
+ scanner->frame_info.next = 0;
226
+ scanner->frame_info.parent = 0;
227
+ scanner->frame_info.rect = cvRect( 0, 0, size.width, size.height );
228
+ scanner->l_cinfo = 0;
229
+ scanner->subst_flag = 0;
230
+
231
+ scanner->frame.flags = CV_SEQ_FLAG_HOLE;
232
+
233
+ scanner->approx_method2 = scanner->approx_method1 = method;
234
+
235
+ if( method == CV_CHAIN_APPROX_TC89_L1 || method == CV_CHAIN_APPROX_TC89_KCOS )
236
+ scanner->approx_method1 = CV_CHAIN_CODE;
237
+
238
+ if( scanner->approx_method1 == CV_CHAIN_CODE )
239
+ {
240
+ scanner->seq_type1 = CV_SEQ_CHAIN_CONTOUR;
241
+ scanner->header_size1 = scanner->approx_method1 == scanner->approx_method2 ?
242
+ header_size : sizeof( CvChain );
243
+ scanner->elem_size1 = sizeof( char );
244
+ }
245
+ else
246
+ {
247
+ scanner->seq_type1 = CV_SEQ_POLYGON;
248
+ scanner->header_size1 = scanner->approx_method1 == scanner->approx_method2 ?
249
+ header_size : sizeof( CvContour );
250
+ scanner->elem_size1 = sizeof( CvPoint );
251
+ }
252
+
253
+ scanner->header_size2 = header_size;
254
+
255
+ if( scanner->approx_method2 == CV_CHAIN_CODE )
256
+ {
257
+ scanner->seq_type2 = scanner->seq_type1;
258
+ scanner->elem_size2 = scanner->elem_size1;
259
+ }
260
+ else
261
+ {
262
+ scanner->seq_type2 = CV_SEQ_POLYGON;
263
+ scanner->elem_size2 = sizeof( CvPoint );
264
+ }
265
+
266
+ scanner->seq_type1 = scanner->approx_method1 == CV_CHAIN_CODE ?
267
+ CV_SEQ_CHAIN_CONTOUR : CV_SEQ_POLYGON;
268
+
269
+ scanner->seq_type2 = scanner->approx_method2 == CV_CHAIN_CODE ?
270
+ CV_SEQ_CHAIN_CONTOUR : CV_SEQ_POLYGON;
271
+
272
+ cvSaveMemStoragePos( storage, &(scanner->initial_pos) );
273
+
274
+ if( method > CV_CHAIN_APPROX_SIMPLE )
275
+ {
276
+ scanner->storage1 = cvCreateChildMemStorage( scanner->storage2 );
277
+ }
278
+
279
+ if( mode > CV_RETR_LIST )
280
+ {
281
+ scanner->cinfo_storage = cvCreateChildMemStorage( scanner->storage2 );
282
+ scanner->cinfo_set = cvCreateSet( 0, sizeof( CvSet ), sizeof( _CvContourInfo ),
283
+ scanner->cinfo_storage );
284
+ }
285
+
286
+ /* make zero borders */
287
+ memset( img, 0, size.width );
288
+ memset( img + step * (size.height - 1), 0, size.width );
289
+
290
+ for( y = 1, img += step; y < size.height - 1; y++, img += step )
291
+ {
292
+ img[0] = img[size.width - 1] = 0;
293
+ }
294
+
295
+ /* converts all pixels to 0 or 1 */
296
+ cvThreshold( mat, mat, 0, 1, CV_THRESH_BINARY );
297
+
298
+ return scanner;
299
+ }
300
+
301
+ /*
302
+ Final stage of contour processing.
303
+ Three variants possible:
304
+ 1. Contour, which was retrieved using border following, is added to
305
+ the contour tree. It is the case when the icvSubstituteContour function
306
+ was not called after retrieving the contour.
307
+
308
+ 2. New contour, assigned by icvSubstituteContour function, is added to the
309
+ tree. The retrieved contour itself is removed from the storage.
310
+ Here two cases are possible:
311
+ 2a. If one deals with plane variant of algorithm
312
+ (hierarchical strucutre is not reconstructed),
313
+ the contour is removed completely.
314
+ 2b. In hierarchical case, the header of the contour is not removed.
315
+ It's marked as "link to contour" and h_next pointer of it is set to
316
+ new, substituting contour.
317
+
318
+ 3. The similar to 2, but when NULL pointer was assigned by
319
+ icvSubstituteContour function. In this case, the function removes
320
+ retrieved contour completely if plane case and
321
+ leaves header if hierarchical (but doesn't mark header as "link").
322
+ ------------------------------------------------------------------------
323
+ The 1st variant can be used to retrieve and store all the contours from the image
324
+ (with optional convertion from chains to contours using some approximation from
325
+ restriced set of methods). Some characteristics of contour can be computed in the
326
+ same pass.
327
+
328
+ The usage scheme can look like:
329
+
330
+ icvContourScanner scanner;
331
+ CvMemStorage* contour_storage;
332
+ CvSeq* first_contour;
333
+ CvStatus result;
334
+
335
+ ...
336
+
337
+ icvCreateMemStorage( &contour_storage, block_size/0 );
338
+
339
+ ...
340
+
341
+ cvStartFindContours
342
+ ( img, contour_storage,
343
+ header_size, approx_method,
344
+ [external_only,]
345
+ &scanner );
346
+
347
+ for(;;)
348
+ {
349
+ [CvSeq* contour;]
350
+ result = icvFindNextContour( &scanner, &contour/0 );
351
+
352
+ if( result != CV_OK ) break;
353
+
354
+ // calculate some characteristics
355
+ ...
356
+ }
357
+
358
+ if( result < 0 ) goto error_processing;
359
+
360
+ cvEndFindContours( &scanner, &first_contour );
361
+ ...
362
+
363
+ -----------------------------------------------------------------
364
+
365
+ Second variant is more complex and can be used when someone wants store not
366
+ the retrieved contours but transformed ones. (e.g. approximated with some
367
+ non-default algorithm ).
368
+
369
+ The scheme can be the as following:
370
+
371
+ icvContourScanner scanner;
372
+ CvMemStorage* contour_storage;
373
+ CvMemStorage* temp_storage;
374
+ CvSeq* first_contour;
375
+ CvStatus result;
376
+
377
+ ...
378
+
379
+ icvCreateMemStorage( &contour_storage, block_size/0 );
380
+ icvCreateMemStorage( &temp_storage, block_size/0 );
381
+
382
+ ...
383
+
384
+ icvStartFindContours8uC1R
385
+ ( <img_params>, temp_storage,
386
+ header_size, approx_method,
387
+ [retrival_mode],
388
+ &scanner );
389
+
390
+ for(;;)
391
+ {
392
+ CvSeq* temp_contour;
393
+ CvSeq* new_contour;
394
+ result = icvFindNextContour( scanner, &temp_contour );
395
+
396
+ if( result != CV_OK ) break;
397
+
398
+ <approximation_function>( temp_contour, contour_storage,
399
+ &new_contour, <parameters...> );
400
+
401
+ icvSubstituteContour( scanner, new_contour );
402
+ ...
403
+ }
404
+
405
+ if( result < 0 ) goto error_processing;
406
+
407
+ cvEndFindContours( &scanner, &first_contour );
408
+ ...
409
+
410
+ ----------------------------------------------------------------------------
411
+ Third method to retrieve contours may be applied if contours are irrelevant
412
+ themselves but some characteristics of them are used only.
413
+ The usage is similar to second except slightly different internal loop
414
+
415
+ for(;;)
416
+ {
417
+ CvSeq* temp_contour;
418
+ result = icvFindNextContour( &scanner, &temp_contour );
419
+
420
+ if( result != CV_OK ) break;
421
+
422
+ // calculate some characteristics of temp_contour
423
+
424
+ icvSubstituteContour( scanner, 0 );
425
+ ...
426
+ }
427
+
428
+ new_storage variable is not needed here.
429
+
430
+ Note, that the second and the third methods can interleave. I.e. it is possible to
431
+ retain contours that satisfy with some criteria and reject others.
432
+ In hierarchic case the resulting tree is the part of original tree with
433
+ some nodes absent. But in the resulting tree the contour1 is a child
434
+ (may be indirect) of contour2 iff in the original tree the contour1
435
+ is a child (may be indirect) of contour2.
436
+ */
437
+ static void
438
+ icvEndProcessContour( CvContourScanner scanner )
439
+ {
440
+ _CvContourInfo *l_cinfo = scanner->l_cinfo;
441
+
442
+ if( l_cinfo )
443
+ {
444
+ if( scanner->subst_flag )
445
+ {
446
+ CvMemStoragePos temp;
447
+
448
+ cvSaveMemStoragePos( scanner->storage2, &temp );
449
+
450
+ if( temp.top == scanner->backup_pos2.top &&
451
+ temp.free_space == scanner->backup_pos2.free_space )
452
+ {
453
+ cvRestoreMemStoragePos( scanner->storage2, &scanner->backup_pos );
454
+ }
455
+ scanner->subst_flag = 0;
456
+ }
457
+
458
+ if( l_cinfo->contour )
459
+ {
460
+ cvInsertNodeIntoTree( l_cinfo->contour, l_cinfo->parent->contour,
461
+ &(scanner->frame) );
462
+ }
463
+ scanner->l_cinfo = 0;
464
+ }
465
+ }
466
+
467
+ /* replaces one contour with another */
468
+ CV_IMPL void
469
+ cvSubstituteContour( CvContourScanner scanner, CvSeq * new_contour )
470
+ {
471
+ _CvContourInfo *l_cinfo;
472
+
473
+ if( !scanner )
474
+ CV_Error( CV_StsNullPtr, "" );
475
+
476
+ l_cinfo = scanner->l_cinfo;
477
+ if( l_cinfo && l_cinfo->contour && l_cinfo->contour != new_contour )
478
+ {
479
+ l_cinfo->contour = new_contour;
480
+ scanner->subst_flag = 1;
481
+ }
482
+ }
483
+
484
+
485
+ /*
486
+ marks domain border with +/-<constant> and stores the contour into CvSeq.
487
+ method:
488
+ <0 - chain
489
+ ==0 - direct
490
+ >0 - simple approximation
491
+ */
492
+ static void
493
+ icvFetchContour( schar *ptr,
494
+ int step,
495
+ CvPoint pt,
496
+ CvSeq* contour,
497
+ int _method )
498
+ {
499
+ const schar nbd = 2;
500
+ int deltas[16];
501
+ CvSeqWriter writer;
502
+ schar *i0 = ptr, *i1, *i3, *i4 = 0;
503
+ int prev_s = -1, s, s_end;
504
+ int method = _method - 1;
505
+
506
+ assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE );
507
+
508
+ /* initialize local state */
509
+ CV_INIT_3X3_DELTAS( deltas, step, 1 );
510
+ memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
511
+
512
+ /* initialize writer */
513
+ cvStartAppendToSeq( contour, &writer );
514
+
515
+ if( method < 0 )
516
+ ((CvChain *) contour)->origin = pt;
517
+
518
+ s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4;
519
+
520
+ do
521
+ {
522
+ s = (s - 1) & 7;
523
+ i1 = i0 + deltas[s];
524
+ if( *i1 != 0 )
525
+ break;
526
+ }
527
+ while( s != s_end );
528
+
529
+ if( s == s_end ) /* single pixel domain */
530
+ {
531
+ *i0 = (schar) (nbd | -128);
532
+ if( method >= 0 )
533
+ {
534
+ CV_WRITE_SEQ_ELEM( pt, writer );
535
+ }
536
+ }
537
+ else
538
+ {
539
+ i3 = i0;
540
+ prev_s = s ^ 4;
541
+
542
+ /* follow border */
543
+ for( ;; )
544
+ {
545
+ s_end = s;
546
+
547
+ for( ;; )
548
+ {
549
+ i4 = i3 + deltas[++s];
550
+ if( *i4 != 0 )
551
+ break;
552
+ }
553
+ s &= 7;
554
+
555
+ /* check "right" bound */
556
+ if( (unsigned) (s - 1) < (unsigned) s_end )
557
+ {
558
+ *i3 = (schar) (nbd | -128);
559
+ }
560
+ else if( *i3 == 1 )
561
+ {
562
+ *i3 = nbd;
563
+ }
564
+
565
+ if( method < 0 )
566
+ {
567
+ schar _s = (schar) s;
568
+
569
+ CV_WRITE_SEQ_ELEM( _s, writer );
570
+ }
571
+ else
572
+ {
573
+ if( s != prev_s || method == 0 )
574
+ {
575
+ CV_WRITE_SEQ_ELEM( pt, writer );
576
+ prev_s = s;
577
+ }
578
+
579
+ pt.x += icvCodeDeltas[s].x;
580
+ pt.y += icvCodeDeltas[s].y;
581
+
582
+ }
583
+
584
+ if( i4 == i0 && i3 == i1 )
585
+ break;
586
+
587
+ i3 = i4;
588
+ s = (s + 4) & 7;
589
+ } /* end of border following loop */
590
+ }
591
+
592
+ cvEndWriteSeq( &writer );
593
+
594
+ if( _method != CV_CHAIN_CODE )
595
+ cvBoundingRect( contour, 1 );
596
+
597
+ assert( (writer.seq->total == 0 && writer.seq->first == 0) ||
598
+ writer.seq->total > writer.seq->first->count ||
599
+ (writer.seq->first->prev == writer.seq->first &&
600
+ writer.seq->first->next == writer.seq->first) );
601
+ }
602
+
603
+
604
+
605
+ /*
606
+ trace contour until certain point is met.
607
+ returns 1 if met, 0 else.
608
+ */
609
+ static int
610
+ icvTraceContour( schar *ptr, int step, schar *stop_ptr, int is_hole )
611
+ {
612
+ int deltas[16];
613
+ schar *i0 = ptr, *i1, *i3, *i4;
614
+ int s, s_end;
615
+
616
+ /* initialize local state */
617
+ CV_INIT_3X3_DELTAS( deltas, step, 1 );
618
+ memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
619
+
620
+ assert( (*i0 & -2) != 0 );
621
+
622
+ s_end = s = is_hole ? 0 : 4;
623
+
624
+ do
625
+ {
626
+ s = (s - 1) & 7;
627
+ i1 = i0 + deltas[s];
628
+ if( *i1 != 0 )
629
+ break;
630
+ }
631
+ while( s != s_end );
632
+
633
+ i3 = i0;
634
+
635
+ /* check single pixel domain */
636
+ if( s != s_end )
637
+ {
638
+ /* follow border */
639
+ for( ;; )
640
+ {
641
+ s_end = s;
642
+
643
+ for( ;; )
644
+ {
645
+ i4 = i3 + deltas[++s];
646
+ if( *i4 != 0 )
647
+ break;
648
+ }
649
+
650
+ if( i3 == stop_ptr || (i4 == i0 && i3 == i1) )
651
+ break;
652
+
653
+ i3 = i4;
654
+ s = (s + 4) & 7;
655
+ } /* end of border following loop */
656
+ }
657
+ return i3 == stop_ptr;
658
+ }
659
+
660
+
661
+ static void
662
+ icvFetchContourEx( schar* ptr,
663
+ int step,
664
+ CvPoint pt,
665
+ CvSeq* contour,
666
+ int _method,
667
+ int nbd,
668
+ CvRect* _rect )
669
+ {
670
+ int deltas[16];
671
+ CvSeqWriter writer;
672
+ schar *i0 = ptr, *i1, *i3, *i4;
673
+ CvRect rect;
674
+ int prev_s = -1, s, s_end;
675
+ int method = _method - 1;
676
+
677
+ assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE );
678
+ assert( 1 < nbd && nbd < 128 );
679
+
680
+ /* initialize local state */
681
+ CV_INIT_3X3_DELTAS( deltas, step, 1 );
682
+ memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
683
+
684
+ /* initialize writer */
685
+ cvStartAppendToSeq( contour, &writer );
686
+
687
+ if( method < 0 )
688
+ ((CvChain *)contour)->origin = pt;
689
+
690
+ rect.x = rect.width = pt.x;
691
+ rect.y = rect.height = pt.y;
692
+
693
+ s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4;
694
+
695
+ do
696
+ {
697
+ s = (s - 1) & 7;
698
+ i1 = i0 + deltas[s];
699
+ if( *i1 != 0 )
700
+ break;
701
+ }
702
+ while( s != s_end );
703
+
704
+ if( s == s_end ) /* single pixel domain */
705
+ {
706
+ *i0 = (schar) (nbd | 0x80);
707
+ if( method >= 0 )
708
+ {
709
+ CV_WRITE_SEQ_ELEM( pt, writer );
710
+ }
711
+ }
712
+ else
713
+ {
714
+ i3 = i0;
715
+
716
+ prev_s = s ^ 4;
717
+
718
+ /* follow border */
719
+ for( ;; )
720
+ {
721
+ s_end = s;
722
+
723
+ for( ;; )
724
+ {
725
+ i4 = i3 + deltas[++s];
726
+ if( *i4 != 0 )
727
+ break;
728
+ }
729
+ s &= 7;
730
+
731
+ /* check "right" bound */
732
+ if( (unsigned) (s - 1) < (unsigned) s_end )
733
+ {
734
+ *i3 = (schar) (nbd | 0x80);
735
+ }
736
+ else if( *i3 == 1 )
737
+ {
738
+ *i3 = (schar) nbd;
739
+ }
740
+
741
+ if( method < 0 )
742
+ {
743
+ schar _s = (schar) s;
744
+ CV_WRITE_SEQ_ELEM( _s, writer );
745
+ }
746
+ else if( s != prev_s || method == 0 )
747
+ {
748
+ CV_WRITE_SEQ_ELEM( pt, writer );
749
+ }
750
+
751
+ if( s != prev_s )
752
+ {
753
+ /* update bounds */
754
+ if( pt.x < rect.x )
755
+ rect.x = pt.x;
756
+ else if( pt.x > rect.width )
757
+ rect.width = pt.x;
758
+
759
+ if( pt.y < rect.y )
760
+ rect.y = pt.y;
761
+ else if( pt.y > rect.height )
762
+ rect.height = pt.y;
763
+ }
764
+
765
+ prev_s = s;
766
+ pt.x += icvCodeDeltas[s].x;
767
+ pt.y += icvCodeDeltas[s].y;
768
+
769
+ if( i4 == i0 && i3 == i1 ) break;
770
+
771
+ i3 = i4;
772
+ s = (s + 4) & 7;
773
+ } /* end of border following loop */
774
+ }
775
+
776
+ rect.width -= rect.x - 1;
777
+ rect.height -= rect.y - 1;
778
+
779
+ cvEndWriteSeq( &writer );
780
+
781
+ if( _method != CV_CHAIN_CODE )
782
+ ((CvContour*)contour)->rect = rect;
783
+
784
+ assert( (writer.seq->total == 0 && writer.seq->first == 0) ||
785
+ writer.seq->total > writer.seq->first->count ||
786
+ (writer.seq->first->prev == writer.seq->first &&
787
+ writer.seq->first->next == writer.seq->first) );
788
+
789
+ if( _rect ) *_rect = rect;
790
+ }
791
+
792
+
793
+ CvSeq *
794
+ cvFindNextContour( CvContourScanner scanner )
795
+ {
796
+ schar *img0;
797
+ schar *img;
798
+ int step;
799
+ int width, height;
800
+ int x, y;
801
+ int prev;
802
+ CvPoint lnbd;
803
+ int nbd;
804
+ int mode;
805
+
806
+ if( !scanner )
807
+ CV_Error( CV_StsNullPtr, "" );
808
+ icvEndProcessContour( scanner );
809
+
810
+ /* initialize local state */
811
+ img0 = scanner->img0;
812
+ img = scanner->img;
813
+ step = scanner->img_step;
814
+ x = scanner->pt.x;
815
+ y = scanner->pt.y;
816
+ width = scanner->img_size.width;
817
+ height = scanner->img_size.height;
818
+ mode = scanner->mode;
819
+ lnbd = scanner->lnbd;
820
+ nbd = scanner->nbd;
821
+
822
+ prev = img[x - 1];
823
+
824
+ for( ; y < height; y++, img += step )
825
+ {
826
+ for( ; x < width; x++ )
827
+ {
828
+ int p = img[x];
829
+
830
+ if( p != prev )
831
+ {
832
+ _CvContourInfo *par_info = 0;
833
+ _CvContourInfo *l_cinfo = 0;
834
+ CvSeq *seq = 0;
835
+ int is_hole = 0;
836
+ CvPoint origin;
837
+
838
+ if( !(prev == 0 && p == 1) ) /* if not external contour */
839
+ {
840
+ /* check hole */
841
+ if( p != 0 || prev < 1 )
842
+ goto resume_scan;
843
+
844
+ if( prev & -2 )
845
+ {
846
+ lnbd.x = x - 1;
847
+ }
848
+ is_hole = 1;
849
+ }
850
+
851
+ if( mode == 0 && (is_hole || img0[lnbd.y * step + lnbd.x] > 0) )
852
+ goto resume_scan;
853
+
854
+ origin.y = y;
855
+ origin.x = x - is_hole;
856
+
857
+ /* find contour parent */
858
+ if( mode <= 1 || (!is_hole && mode == 2) || lnbd.x <= 0 )
859
+ {
860
+ par_info = &(scanner->frame_info);
861
+ }
862
+ else
863
+ {
864
+ int lval = img0[lnbd.y * step + lnbd.x] & 0x7f;
865
+ _CvContourInfo *cur = scanner->cinfo_table[lval - 2];
866
+
867
+ assert( lval >= 2 );
868
+
869
+ /* find the first bounding contour */
870
+ while( cur )
871
+ {
872
+ if( (unsigned) (lnbd.x - cur->rect.x) < (unsigned) cur->rect.width &&
873
+ (unsigned) (lnbd.y - cur->rect.y) < (unsigned) cur->rect.height )
874
+ {
875
+ if( par_info )
876
+ {
877
+ if( icvTraceContour( scanner->img0 +
878
+ par_info->origin.y * step +
879
+ par_info->origin.x, step, img + lnbd.x,
880
+ par_info->is_hole ) > 0 )
881
+ break;
882
+ }
883
+ par_info = cur;
884
+ }
885
+ cur = cur->next;
886
+ }
887
+
888
+ assert( par_info != 0 );
889
+
890
+ /* if current contour is a hole and previous contour is a hole or
891
+ current contour is external and previous contour is external then
892
+ the parent of the contour is the parent of the previous contour else
893
+ the parent is the previous contour itself. */
894
+ if( par_info->is_hole == is_hole )
895
+ {
896
+ par_info = par_info->parent;
897
+ /* every contour must have a parent
898
+ (at least, the frame of the image) */
899
+ if( !par_info )
900
+ par_info = &(scanner->frame_info);
901
+ }
902
+
903
+ /* hole flag of the parent must differ from the flag of the contour */
904
+ assert( par_info->is_hole != is_hole );
905
+ if( par_info->contour == 0 ) /* removed contour */
906
+ goto resume_scan;
907
+ }
908
+
909
+ lnbd.x = x - is_hole;
910
+
911
+ cvSaveMemStoragePos( scanner->storage2, &(scanner->backup_pos) );
912
+
913
+ seq = cvCreateSeq( scanner->seq_type1, scanner->header_size1,
914
+ scanner->elem_size1, scanner->storage1 );
915
+ seq->flags |= is_hole ? CV_SEQ_FLAG_HOLE : 0;
916
+
917
+ /* initialize header */
918
+ if( mode <= 1 )
919
+ {
920
+ l_cinfo = &(scanner->cinfo_temp);
921
+ icvFetchContour( img + x - is_hole, step,
922
+ cvPoint( origin.x + scanner->offset.x,
923
+ origin.y + scanner->offset.y),
924
+ seq, scanner->approx_method1 );
925
+ }
926
+ else
927
+ {
928
+ union { _CvContourInfo* ci; CvSetElem* se; } v;
929
+ v.ci = l_cinfo;
930
+ cvSetAdd( scanner->cinfo_set, 0, &v.se );
931
+ l_cinfo = v.ci;
932
+
933
+ icvFetchContourEx( img + x - is_hole, step,
934
+ cvPoint( origin.x + scanner->offset.x,
935
+ origin.y + scanner->offset.y),
936
+ seq, scanner->approx_method1,
937
+ nbd, &(l_cinfo->rect) );
938
+ l_cinfo->rect.x -= scanner->offset.x;
939
+ l_cinfo->rect.y -= scanner->offset.y;
940
+
941
+ l_cinfo->next = scanner->cinfo_table[nbd - 2];
942
+ scanner->cinfo_table[nbd - 2] = l_cinfo;
943
+
944
+ /* change nbd */
945
+ nbd = (nbd + 1) & 127;
946
+ nbd += nbd == 0 ? 3 : 0;
947
+ }
948
+
949
+ l_cinfo->is_hole = is_hole;
950
+ l_cinfo->contour = seq;
951
+ l_cinfo->origin = origin;
952
+ l_cinfo->parent = par_info;
953
+
954
+ if( scanner->approx_method1 != scanner->approx_method2 )
955
+ {
956
+ l_cinfo->contour = icvApproximateChainTC89( (CvChain *) seq,
957
+ scanner->header_size2,
958
+ scanner->storage2,
959
+ scanner->approx_method2 );
960
+ cvClearMemStorage( scanner->storage1 );
961
+ }
962
+
963
+ l_cinfo->contour->v_prev = l_cinfo->parent->contour;
964
+
965
+ if( par_info->contour == 0 )
966
+ {
967
+ l_cinfo->contour = 0;
968
+ if( scanner->storage1 == scanner->storage2 )
969
+ {
970
+ cvRestoreMemStoragePos( scanner->storage1, &(scanner->backup_pos) );
971
+ }
972
+ else
973
+ {
974
+ cvClearMemStorage( scanner->storage1 );
975
+ }
976
+ p = img[x];
977
+ goto resume_scan;
978
+ }
979
+
980
+ cvSaveMemStoragePos( scanner->storage2, &(scanner->backup_pos2) );
981
+ scanner->l_cinfo = l_cinfo;
982
+ scanner->pt.x = x + 1;
983
+ scanner->pt.y = y;
984
+ scanner->lnbd = lnbd;
985
+ scanner->img = (schar *) img;
986
+ scanner->nbd = nbd;
987
+ return l_cinfo->contour;
988
+
989
+ resume_scan:
990
+
991
+ prev = p;
992
+ /* update lnbd */
993
+ if( prev & -2 )
994
+ {
995
+ lnbd.x = x;
996
+ }
997
+ } /* end of prev != p */
998
+ } /* end of loop on x */
999
+
1000
+ lnbd.x = 0;
1001
+ lnbd.y = y + 1;
1002
+ x = 1;
1003
+ prev = 0;
1004
+
1005
+ } /* end of loop on y */
1006
+
1007
+ return 0;
1008
+ }
1009
+
1010
+
1011
+ /*
1012
+ The function add to tree the last retrieved/substituted contour,
1013
+ releases temp_storage, restores state of dst_storage (if needed), and
1014
+ returns pointer to root of the contour tree */
1015
+ CV_IMPL CvSeq *
1016
+ cvEndFindContours( CvContourScanner * _scanner )
1017
+ {
1018
+ CvContourScanner scanner;
1019
+ CvSeq *first = 0;
1020
+
1021
+ if( !_scanner )
1022
+ CV_Error( CV_StsNullPtr, "" );
1023
+ scanner = *_scanner;
1024
+
1025
+ if( scanner )
1026
+ {
1027
+ icvEndProcessContour( scanner );
1028
+
1029
+ if( scanner->storage1 != scanner->storage2 )
1030
+ cvReleaseMemStorage( &(scanner->storage1) );
1031
+
1032
+ if( scanner->cinfo_storage )
1033
+ cvReleaseMemStorage( &(scanner->cinfo_storage) );
1034
+
1035
+ first = scanner->frame.v_next;
1036
+ cvFree( _scanner );
1037
+ }
1038
+
1039
+ return first;
1040
+ }
1041
+
1042
+
1043
+ #define ICV_SINGLE 0
1044
+ #define ICV_CONNECTING_ABOVE 1
1045
+ #define ICV_CONNECTING_BELOW -1
1046
+ #define ICV_IS_COMPONENT_POINT(val) ((val) != 0)
1047
+
1048
+ #define CV_GET_WRITTEN_ELEM( writer ) ((writer).ptr - (writer).seq->elem_size)
1049
+
1050
+ typedef struct CvLinkedRunPoint
1051
+ {
1052
+ struct CvLinkedRunPoint* link;
1053
+ struct CvLinkedRunPoint* next;
1054
+ CvPoint pt;
1055
+ }
1056
+ CvLinkedRunPoint;
1057
+
1058
+
1059
+ static int
1060
+ icvFindContoursInInterval( const CvArr* src,
1061
+ /*int minValue, int maxValue,*/
1062
+ CvMemStorage* storage,
1063
+ CvSeq** result,
1064
+ int contourHeaderSize )
1065
+ {
1066
+ int count = 0;
1067
+ cv::Ptr<CvMemStorage> storage00;
1068
+ cv::Ptr<CvMemStorage> storage01;
1069
+ CvSeq* first = 0;
1070
+
1071
+ int i, j, k, n;
1072
+
1073
+ uchar* src_data = 0;
1074
+ int img_step = 0;
1075
+ CvSize img_size;
1076
+
1077
+ int connect_flag;
1078
+ int lower_total;
1079
+ int upper_total;
1080
+ int all_total;
1081
+
1082
+ CvSeq* runs;
1083
+ CvLinkedRunPoint tmp;
1084
+ CvLinkedRunPoint* tmp_prev;
1085
+ CvLinkedRunPoint* upper_line = 0;
1086
+ CvLinkedRunPoint* lower_line = 0;
1087
+ CvLinkedRunPoint* last_elem;
1088
+
1089
+ CvLinkedRunPoint* upper_run = 0;
1090
+ CvLinkedRunPoint* lower_run = 0;
1091
+ CvLinkedRunPoint* prev_point = 0;
1092
+
1093
+ CvSeqWriter writer_ext;
1094
+ CvSeqWriter writer_int;
1095
+ CvSeqWriter writer;
1096
+ CvSeqReader reader;
1097
+
1098
+ CvSeq* external_contours;
1099
+ CvSeq* internal_contours;
1100
+ CvSeq* prev = 0;
1101
+
1102
+ if( !storage )
1103
+ CV_Error( CV_StsNullPtr, "NULL storage pointer" );
1104
+
1105
+ if( !result )
1106
+ CV_Error( CV_StsNullPtr, "NULL double CvSeq pointer" );
1107
+
1108
+ if( contourHeaderSize < (int)sizeof(CvContour))
1109
+ CV_Error( CV_StsBadSize, "Contour header size must be >= sizeof(CvContour)" );
1110
+
1111
+ storage00 = cvCreateChildMemStorage(storage);
1112
+ storage01 = cvCreateChildMemStorage(storage);
1113
+
1114
+ CvMat stub, *mat;
1115
+
1116
+ mat = cvGetMat( src, &stub );
1117
+ if( !CV_IS_MASK_ARR(mat))
1118
+ CV_Error( CV_StsBadArg, "Input array must be 8uC1 or 8sC1" );
1119
+ src_data = mat->data.ptr;
1120
+ img_step = mat->step;
1121
+ img_size = cvGetMatSize( mat );
1122
+
1123
+ // Create temporary sequences
1124
+ runs = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvLinkedRunPoint), storage00 );
1125
+ cvStartAppendToSeq( runs, &writer );
1126
+
1127
+ cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_ext );
1128
+ cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_int );
1129
+
1130
+ tmp_prev = &(tmp);
1131
+ tmp_prev->next = 0;
1132
+ tmp_prev->link = 0;
1133
+
1134
+ // First line. None of runs is binded
1135
+ tmp.pt.y = 0;
1136
+ i = 0;
1137
+ CV_WRITE_SEQ_ELEM( tmp, writer );
1138
+ upper_line = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1139
+
1140
+ tmp_prev = upper_line;
1141
+ for( j = 0; j < img_size.width; )
1142
+ {
1143
+ for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
1144
+ ;
1145
+ if( j == img_size.width )
1146
+ break;
1147
+
1148
+ tmp.pt.x = j;
1149
+ CV_WRITE_SEQ_ELEM( tmp, writer );
1150
+ tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1151
+ tmp_prev = tmp_prev->next;
1152
+
1153
+ for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
1154
+ ;
1155
+
1156
+ tmp.pt.x = j-1;
1157
+ CV_WRITE_SEQ_ELEM( tmp, writer );
1158
+ tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1159
+ tmp_prev->link = tmp_prev->next;
1160
+ // First point of contour
1161
+ CV_WRITE_SEQ_ELEM( tmp_prev, writer_ext );
1162
+ tmp_prev = tmp_prev->next;
1163
+ }
1164
+ cvFlushSeqWriter( &writer );
1165
+ upper_line = upper_line->next;
1166
+ upper_total = runs->total - 1;
1167
+ last_elem = tmp_prev;
1168
+ tmp_prev->next = 0;
1169
+
1170
+ for( i = 1; i < img_size.height; i++ )
1171
+ {
1172
+ //------// Find runs in next line
1173
+ src_data += img_step;
1174
+ tmp.pt.y = i;
1175
+ all_total = runs->total;
1176
+ for( j = 0; j < img_size.width; )
1177
+ {
1178
+ for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
1179
+ ;
1180
+ if( j == img_size.width ) break;
1181
+
1182
+ tmp.pt.x = j;
1183
+ CV_WRITE_SEQ_ELEM( tmp, writer );
1184
+ tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1185
+ tmp_prev = tmp_prev->next;
1186
+
1187
+ for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
1188
+ ;
1189
+
1190
+ tmp.pt.x = j-1;
1191
+ CV_WRITE_SEQ_ELEM( tmp, writer );
1192
+ tmp_prev = tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1193
+ }//j
1194
+ cvFlushSeqWriter( &writer );
1195
+ lower_line = last_elem->next;
1196
+ lower_total = runs->total - all_total;
1197
+ last_elem = tmp_prev;
1198
+ tmp_prev->next = 0;
1199
+ //------//
1200
+ //------// Find links between runs of lower_line and upper_line
1201
+ upper_run = upper_line;
1202
+ lower_run = lower_line;
1203
+ connect_flag = ICV_SINGLE;
1204
+
1205
+ for( k = 0, n = 0; k < upper_total/2 && n < lower_total/2; )
1206
+ {
1207
+ switch( connect_flag )
1208
+ {
1209
+ case ICV_SINGLE:
1210
+ if( upper_run->next->pt.x < lower_run->next->pt.x )
1211
+ {
1212
+ if( upper_run->next->pt.x >= lower_run->pt.x -1 )
1213
+ {
1214
+ lower_run->link = upper_run;
1215
+ connect_flag = ICV_CONNECTING_ABOVE;
1216
+ prev_point = upper_run->next;
1217
+ }
1218
+ else
1219
+ upper_run->next->link = upper_run;
1220
+ k++;
1221
+ upper_run = upper_run->next->next;
1222
+ }
1223
+ else
1224
+ {
1225
+ if( upper_run->pt.x <= lower_run->next->pt.x +1 )
1226
+ {
1227
+ lower_run->link = upper_run;
1228
+ connect_flag = ICV_CONNECTING_BELOW;
1229
+ prev_point = lower_run->next;
1230
+ }
1231
+ else
1232
+ {
1233
+ lower_run->link = lower_run->next;
1234
+ // First point of contour
1235
+ CV_WRITE_SEQ_ELEM( lower_run, writer_ext );
1236
+ }
1237
+ n++;
1238
+ lower_run = lower_run->next->next;
1239
+ }
1240
+ break;
1241
+ case ICV_CONNECTING_ABOVE:
1242
+ if( upper_run->pt.x > lower_run->next->pt.x +1 )
1243
+ {
1244
+ prev_point->link = lower_run->next;
1245
+ connect_flag = ICV_SINGLE;
1246
+ n++;
1247
+ lower_run = lower_run->next->next;
1248
+ }
1249
+ else
1250
+ {
1251
+ prev_point->link = upper_run;
1252
+ if( upper_run->next->pt.x < lower_run->next->pt.x )
1253
+ {
1254
+ k++;
1255
+ prev_point = upper_run->next;
1256
+ upper_run = upper_run->next->next;
1257
+ }
1258
+ else
1259
+ {
1260
+ connect_flag = ICV_CONNECTING_BELOW;
1261
+ prev_point = lower_run->next;
1262
+ n++;
1263
+ lower_run = lower_run->next->next;
1264
+ }
1265
+ }
1266
+ break;
1267
+ case ICV_CONNECTING_BELOW:
1268
+ if( lower_run->pt.x > upper_run->next->pt.x +1 )
1269
+ {
1270
+ upper_run->next->link = prev_point;
1271
+ connect_flag = ICV_SINGLE;
1272
+ k++;
1273
+ upper_run = upper_run->next->next;
1274
+ }
1275
+ else
1276
+ {
1277
+ // First point of contour
1278
+ CV_WRITE_SEQ_ELEM( lower_run, writer_int );
1279
+
1280
+ lower_run->link = prev_point;
1281
+ if( lower_run->next->pt.x < upper_run->next->pt.x )
1282
+ {
1283
+ n++;
1284
+ prev_point = lower_run->next;
1285
+ lower_run = lower_run->next->next;
1286
+ }
1287
+ else
1288
+ {
1289
+ connect_flag = ICV_CONNECTING_ABOVE;
1290
+ k++;
1291
+ prev_point = upper_run->next;
1292
+ upper_run = upper_run->next->next;
1293
+ }
1294
+ }
1295
+ break;
1296
+ }
1297
+ }// k, n
1298
+
1299
+ for( ; n < lower_total/2; n++ )
1300
+ {
1301
+ if( connect_flag != ICV_SINGLE )
1302
+ {
1303
+ prev_point->link = lower_run->next;
1304
+ connect_flag = ICV_SINGLE;
1305
+ lower_run = lower_run->next->next;
1306
+ continue;
1307
+ }
1308
+ lower_run->link = lower_run->next;
1309
+
1310
+ //First point of contour
1311
+ CV_WRITE_SEQ_ELEM( lower_run, writer_ext );
1312
+
1313
+ lower_run = lower_run->next->next;
1314
+ }
1315
+
1316
+ for( ; k < upper_total/2; k++ )
1317
+ {
1318
+ if( connect_flag != ICV_SINGLE )
1319
+ {
1320
+ upper_run->next->link = prev_point;
1321
+ connect_flag = ICV_SINGLE;
1322
+ upper_run = upper_run->next->next;
1323
+ continue;
1324
+ }
1325
+ upper_run->next->link = upper_run;
1326
+ upper_run = upper_run->next->next;
1327
+ }
1328
+ upper_line = lower_line;
1329
+ upper_total = lower_total;
1330
+ }//i
1331
+
1332
+ upper_run = upper_line;
1333
+
1334
+ //the last line of image
1335
+ for( k = 0; k < upper_total/2; k++ )
1336
+ {
1337
+ upper_run->next->link = upper_run;
1338
+ upper_run = upper_run->next->next;
1339
+ }
1340
+
1341
+ //------//
1342
+ //------//Find end read contours
1343
+ external_contours = cvEndWriteSeq( &writer_ext );
1344
+ internal_contours = cvEndWriteSeq( &writer_int );
1345
+
1346
+ for( k = 0; k < 2; k++ )
1347
+ {
1348
+ CvSeq* contours = k == 0 ? external_contours : internal_contours;
1349
+
1350
+ cvStartReadSeq( contours, &reader );
1351
+
1352
+ for( j = 0; j < contours->total; j++, count++ )
1353
+ {
1354
+ CvLinkedRunPoint* p_temp;
1355
+ CvLinkedRunPoint* p00;
1356
+ CvLinkedRunPoint* p01;
1357
+ CvSeq* contour;
1358
+
1359
+ CV_READ_SEQ_ELEM( p00, reader );
1360
+ p01 = p00;
1361
+
1362
+ if( !p00->link )
1363
+ continue;
1364
+
1365
+ cvStartWriteSeq( CV_SEQ_ELTYPE_POINT | CV_SEQ_POLYLINE | CV_SEQ_FLAG_CLOSED,
1366
+ contourHeaderSize, sizeof(CvPoint), storage, &writer );
1367
+ do
1368
+ {
1369
+ CV_WRITE_SEQ_ELEM( p00->pt, writer );
1370
+ p_temp = p00;
1371
+ p00 = p00->link;
1372
+ p_temp->link = 0;
1373
+ }
1374
+ while( p00 != p01 );
1375
+
1376
+ contour = cvEndWriteSeq( &writer );
1377
+ cvBoundingRect( contour, 1 );
1378
+
1379
+ if( k != 0 )
1380
+ contour->flags |= CV_SEQ_FLAG_HOLE;
1381
+
1382
+ if( !first )
1383
+ prev = first = contour;
1384
+ else
1385
+ {
1386
+ contour->h_prev = prev;
1387
+ prev = prev->h_next = contour;
1388
+ }
1389
+ }
1390
+ }
1391
+
1392
+ if( !first )
1393
+ count = -1;
1394
+
1395
+ if( result )
1396
+ *result = first;
1397
+
1398
+ return count;
1399
+ }
1400
+
1401
+
1402
+
1403
+ /*F///////////////////////////////////////////////////////////////////////////////////////
1404
+ // Name: cvFindContours
1405
+ // Purpose:
1406
+ // Finds all the contours on the bi-level image.
1407
+ // Context:
1408
+ // Parameters:
1409
+ // img - source image.
1410
+ // Non-zero pixels are considered as 1-pixels
1411
+ // and zero pixels as 0-pixels.
1412
+ // step - full width of source image in bytes.
1413
+ // size - width and height of the image in pixels
1414
+ // storage - pointer to storage where will the output contours be placed.
1415
+ // header_size - header size of resulting contours
1416
+ // mode - mode of contour retrieval.
1417
+ // method - method of approximation that is applied to contours
1418
+ // first_contour - pointer to first contour pointer
1419
+ // Returns:
1420
+ // CV_OK or error code
1421
+ // Notes:
1422
+ //F*/
1423
+ CV_IMPL int
1424
+ cvFindContours( void* img, CvMemStorage* storage,
1425
+ CvSeq** firstContour, int cntHeaderSize,
1426
+ int mode,
1427
+ int method, CvPoint offset )
1428
+ {
1429
+ CvContourScanner scanner = 0;
1430
+ CvSeq *contour = 0;
1431
+ int count = -1;
1432
+
1433
+ if( !firstContour )
1434
+ CV_Error( CV_StsNullPtr, "NULL double CvSeq pointer" );
1435
+
1436
+ *firstContour = 0;
1437
+
1438
+ if( method == CV_LINK_RUNS )
1439
+ {
1440
+ if( offset.x != 0 || offset.y != 0 )
1441
+ CV_Error( CV_StsOutOfRange,
1442
+ "Nonzero offset is not supported in CV_LINK_RUNS yet" );
1443
+
1444
+ count = icvFindContoursInInterval( img, storage, firstContour, cntHeaderSize );
1445
+ }
1446
+ else
1447
+ {
1448
+ try
1449
+ {
1450
+ scanner = cvStartFindContours( img, storage, cntHeaderSize, mode, method, offset );
1451
+
1452
+ do
1453
+ {
1454
+ count++;
1455
+ contour = cvFindNextContour( scanner );
1456
+ }
1457
+ while( contour != 0 );
1458
+ }
1459
+ catch(...)
1460
+ {
1461
+ if( scanner )
1462
+ cvEndFindContours(&scanner);
1463
+ throw;
1464
+ }
1465
+
1466
+ *firstContour = cvEndFindContours( &scanner );
1467
+ }
1468
+
1469
+ return count;
1470
+ }
1471
+
1472
+ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours,
1473
+ OutputArray _hierarchy, int mode, int method, Point offset )
1474
+ {
1475
+ Mat image = _image.getMat();
1476
+ MemStorage storage(cvCreateMemStorage());
1477
+ CvMat _cimage = image;
1478
+ CvSeq* _ccontours = 0;
1479
+ if( _hierarchy.needed() )
1480
+ _hierarchy.clear();
1481
+ cvFindContours(&_cimage, storage, &_ccontours, sizeof(CvContour), mode, method, offset);
1482
+ if( !_ccontours )
1483
+ {
1484
+ _contours.clear();
1485
+ return;
1486
+ }
1487
+ Seq<CvSeq*> all_contours(cvTreeToNodeSeq( _ccontours, sizeof(CvSeq), storage ));
1488
+ int i, total = (int)all_contours.size();
1489
+ _contours.create(total, 1, 0, -1, true);
1490
+ SeqIterator<CvSeq*> it = all_contours.begin();
1491
+ for( i = 0; i < total; i++, ++it )
1492
+ {
1493
+ CvSeq* c = *it;
1494
+ ((CvContour*)c)->color = (int)i;
1495
+ _contours.create((int)c->total, 1, CV_32SC2, i, true);
1496
+ Mat ci = _contours.getMat(i);
1497
+ CV_Assert( ci.isContinuous() );
1498
+ cvCvtSeqToArray(c, ci.data);
1499
+ }
1500
+
1501
+ if( _hierarchy.needed() )
1502
+ {
1503
+ _hierarchy.create(1, total, CV_32SC4, -1, true);
1504
+ Vec4i* hierarchy = _hierarchy.getMat().ptr<Vec4i>();
1505
+
1506
+ it = all_contours.begin();
1507
+ for( i = 0; i < total; i++, ++it )
1508
+ {
1509
+ CvSeq* c = *it;
1510
+ int h_next = c->h_next ? ((CvContour*)c->h_next)->color : -1;
1511
+ int h_prev = c->h_prev ? ((CvContour*)c->h_prev)->color : -1;
1512
+ int v_next = c->v_next ? ((CvContour*)c->v_next)->color : -1;
1513
+ int v_prev = c->v_prev ? ((CvContour*)c->v_prev)->color : -1;
1514
+ hierarchy[i] = Vec4i(h_next, h_prev, v_next, v_prev);
1515
+ }
1516
+ }
1517
+ }
1518
+
1519
+ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours,
1520
+ int mode, int method, Point offset)
1521
+ {
1522
+ findContours(_image, _contours, noArray(), mode, method, offset);
1523
+ }
1524
+
1525
+ namespace cv
1526
+ {
1527
+
1528
+ static void addChildContour(InputArrayOfArrays contours,
1529
+ size_t ncontours,
1530
+ const Vec4i* hierarchy,
1531
+ int i, vector<CvSeq>& seq,
1532
+ vector<CvSeqBlock>& block)
1533
+ {
1534
+ for( ; i >= 0; i = hierarchy[i][0] )
1535
+ {
1536
+ Mat ci = contours.getMat(i);
1537
+ cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
1538
+ !ci.empty() ? (void*)ci.data : 0, (int)ci.total(),
1539
+ &seq[i], &block[i] );
1540
+
1541
+ int h_next = hierarchy[i][0], h_prev = hierarchy[i][1],
1542
+ v_next = hierarchy[i][2], v_prev = hierarchy[i][3];
1543
+ seq[i].h_next = (size_t)h_next < ncontours ? &seq[h_next] : 0;
1544
+ seq[i].h_prev = (size_t)h_prev < ncontours ? &seq[h_prev] : 0;
1545
+ seq[i].v_next = (size_t)v_next < ncontours ? &seq[v_next] : 0;
1546
+ seq[i].v_prev = (size_t)v_prev < ncontours ? &seq[v_prev] : 0;
1547
+
1548
+ if( v_next >= 0 )
1549
+ addChildContour(contours, ncontours, hierarchy, v_next, seq, block);
1550
+ }
1551
+ }
1552
+
1553
+ }
1554
+
1555
+ void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours,
1556
+ int contourIdx, const Scalar& color, int thickness,
1557
+ int lineType, InputArray _hierarchy,
1558
+ int maxLevel, Point offset )
1559
+ {
1560
+ Mat image = _image.getMat(), hierarchy = _hierarchy.getMat();
1561
+ CvMat _cimage = image;
1562
+
1563
+ size_t ncontours = _contours.total();
1564
+ size_t i = 0, first = 0, last = ncontours;
1565
+ vector<CvSeq> seq;
1566
+ vector<CvSeqBlock> block;
1567
+
1568
+ if( !last )
1569
+ return;
1570
+
1571
+ seq.resize(last);
1572
+ block.resize(last);
1573
+
1574
+ for( i = first; i < last; i++ )
1575
+ seq[i].first = 0;
1576
+
1577
+ if( contourIdx >= 0 )
1578
+ {
1579
+ CV_Assert( 0 <= contourIdx && contourIdx < (int)last );
1580
+ first = contourIdx;
1581
+ last = contourIdx + 1;
1582
+ }
1583
+
1584
+ for( i = first; i < last; i++ )
1585
+ {
1586
+ Mat ci = _contours.getMat((int)i);
1587
+ if( ci.empty() )
1588
+ continue;
1589
+ int npoints = ci.checkVector(2, CV_32S);
1590
+ CV_Assert( npoints > 0 );
1591
+ cvMakeSeqHeaderForArray( CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
1592
+ ci.data, npoints, &seq[i], &block[i] );
1593
+ }
1594
+
1595
+ if( hierarchy.empty() || maxLevel == 0 )
1596
+ for( i = first; i < last; i++ )
1597
+ {
1598
+ seq[i].h_next = i < last-1 ? &seq[i+1] : 0;
1599
+ seq[i].h_prev = i > first ? &seq[i-1] : 0;
1600
+ }
1601
+ else
1602
+ {
1603
+ size_t count = last - first;
1604
+ CV_Assert(hierarchy.total() == ncontours && hierarchy.type() == CV_32SC4 );
1605
+ const Vec4i* h = hierarchy.ptr<Vec4i>();
1606
+
1607
+ if( count == ncontours )
1608
+ {
1609
+ for( i = first; i < last; i++ )
1610
+ {
1611
+ int h_next = h[i][0], h_prev = h[i][1],
1612
+ v_next = h[i][2], v_prev = h[i][3];
1613
+ seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0;
1614
+ seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0;
1615
+ seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0;
1616
+ seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0;
1617
+ }
1618
+ }
1619
+ else
1620
+ {
1621
+ int child = h[first][2];
1622
+ if( child >= 0 )
1623
+ {
1624
+ addChildContour(_contours, ncontours, h, child, seq, block);
1625
+ seq[first].v_next = &seq[child];
1626
+ }
1627
+ }
1628
+ }
1629
+
1630
+ cvDrawContours( &_cimage, &seq[first], color, color, contourIdx >= 0 ?
1631
+ -maxLevel : maxLevel, thickness, lineType, offset );
1632
+ }
1633
+
1634
+
1635
+ void cv::approxPolyDP( InputArray _curve, OutputArray _approxCurve,
1636
+ double epsilon, bool closed )
1637
+ {
1638
+ Mat curve = _curve.getMat();
1639
+ int npoints = curve.checkVector(2), depth = curve.depth();
1640
+ CV_Assert( npoints >= 0 && (depth == CV_32S || depth == CV_32F));
1641
+ CvMat _ccurve = curve;
1642
+ MemStorage storage(cvCreateMemStorage());
1643
+ CvSeq* result = cvApproxPoly(&_ccurve, sizeof(CvContour), storage, CV_POLY_APPROX_DP, epsilon, closed);
1644
+ if( result->total > 0 )
1645
+ {
1646
+ _approxCurve.create(result->total, 1, CV_MAKETYPE(curve.depth(), 2), -1, true);
1647
+ cvCvtSeqToArray(result, _approxCurve.getMat().data );
1648
+ }
1649
+ }
1650
+
1651
+
1652
+ double cv::arcLength( InputArray _curve, bool closed )
1653
+ {
1654
+ Mat curve = _curve.getMat();
1655
+ CV_Assert(curve.checkVector(2) >= 0 && (curve.depth() == CV_32F || curve.depth() == CV_32S));
1656
+ CvMat _ccurve = curve;
1657
+ return cvArcLength(&_ccurve, CV_WHOLE_SEQ, closed);
1658
+ }
1659
+
1660
+
1661
+ cv::Rect cv::boundingRect( InputArray _points )
1662
+ {
1663
+ Mat points = _points.getMat();
1664
+ CV_Assert(points.checkVector(2) >= 0 && (points.depth() == CV_32F || points.depth() == CV_32S));
1665
+ CvMat _cpoints = points;
1666
+ return cvBoundingRect(&_cpoints, 0);
1667
+ }
1668
+
1669
+
1670
+ double cv::contourArea( InputArray _contour, bool oriented )
1671
+ {
1672
+ Mat contour = _contour.getMat();
1673
+ CV_Assert(contour.checkVector(2) >= 0 && (contour.depth() == CV_32F || contour.depth() == CV_32S));
1674
+ CvMat _ccontour = contour;
1675
+ return cvContourArea(&_ccontour, CV_WHOLE_SEQ, oriented);
1676
+ }
1677
+
1678
+
1679
+ cv::RotatedRect cv::minAreaRect( InputArray _points )
1680
+ {
1681
+ Mat points = _points.getMat();
1682
+ CV_Assert(points.checkVector(2) >= 0 && (points.depth() == CV_32F || points.depth() == CV_32S));
1683
+ CvMat _cpoints = points;
1684
+ return cvMinAreaRect2(&_cpoints, 0);
1685
+ }
1686
+
1687
+
1688
+ void cv::minEnclosingCircle( InputArray _points,
1689
+ Point2f& center, float& radius )
1690
+ {
1691
+ Mat points = _points.getMat();
1692
+ CV_Assert(points.checkVector(2) >= 0 && (points.depth() == CV_32F || points.depth() == CV_32S));
1693
+ CvMat _cpoints = points;
1694
+ cvMinEnclosingCircle( &_cpoints, (CvPoint2D32f*)&center, &radius );
1695
+ }
1696
+
1697
+
1698
+ double cv::matchShapes( InputArray _contour1,
1699
+ InputArray _contour2,
1700
+ int method, double parameter )
1701
+ {
1702
+ Mat contour1 = _contour1.getMat(), contour2 = _contour2.getMat();
1703
+ CV_Assert(contour1.checkVector(2) >= 0 && contour2.checkVector(2) >= 0 &&
1704
+ (contour1.depth() == CV_32F || contour1.depth() == CV_32S) &&
1705
+ contour1.depth() == contour2.depth());
1706
+
1707
+ CvMat c1 = Mat(contour1), c2 = Mat(contour2);
1708
+ return cvMatchShapes(&c1, &c2, method, parameter);
1709
+ }
1710
+
1711
+
1712
+ void cv::convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool returnPoints )
1713
+ {
1714
+ Mat points = _points.getMat();
1715
+ int nelems = points.checkVector(2), depth = points.depth();
1716
+ CV_Assert(nelems >= 0 && (depth == CV_32F || depth == CV_32S));
1717
+
1718
+ if( nelems == 0 )
1719
+ {
1720
+ _hull.release();
1721
+ return;
1722
+ }
1723
+
1724
+ returnPoints = !_hull.fixedType() ? returnPoints : _hull.type() != CV_32S;
1725
+ Mat hull(nelems, 1, returnPoints ? CV_MAKETYPE(depth, 2) : CV_32S);
1726
+ CvMat _cpoints = points, _chull = hull;
1727
+ cvConvexHull2(&_cpoints, &_chull, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, returnPoints);
1728
+ _hull.create(_chull.rows, 1, hull.type(), -1, true);
1729
+ Mat dhull = _hull.getMat(), shull(dhull.size(), dhull.type(), hull.data);
1730
+ shull.copyTo(dhull);
1731
+ }
1732
+
1733
+ bool cv::isContourConvex( InputArray _contour )
1734
+ {
1735
+ Mat contour = _contour.getMat();
1736
+ CV_Assert(contour.checkVector(2) >= 0 &&
1737
+ (contour.depth() == CV_32F || contour.depth() == CV_32S));
1738
+ CvMat c = Mat(contour);
1739
+ return cvCheckContourConvexity(&c) > 0;
1740
+ }
1741
+
1742
+ cv::RotatedRect cv::fitEllipse( InputArray _points )
1743
+ {
1744
+ Mat points = _points.getMat();
1745
+ CV_Assert(points.checkVector(2) >= 0 &&
1746
+ (points.depth() == CV_32F || points.depth() == CV_32S));
1747
+ CvMat _cpoints = points;
1748
+ return cvFitEllipse2(&_cpoints);
1749
+ }
1750
+
1751
+
1752
+ void cv::fitLine( InputArray _points, OutputArray _line, int distType,
1753
+ double param, double reps, double aeps )
1754
+ {
1755
+ Mat points = _points.getMat();
1756
+ bool is3d = points.checkVector(3) >= 0, is2d = is3d ? false : points.checkVector(2) >= 0;
1757
+
1758
+ CV_Assert((is2d || is3d) && (points.depth() == CV_32F || points.depth() == CV_32S));
1759
+ CvMat _cpoints = points;
1760
+ float line[6];
1761
+ cvFitLine(&_cpoints, distType, param, reps, aeps, &line[0]);
1762
+
1763
+ _line.create(is2d ? 4 : 6, 1, CV_32F, -1, true);
1764
+ Mat l = _line.getMat();
1765
+ CV_Assert( l.isContinuous() );
1766
+ memcpy( l.data, line, (is2d ? 4 : 6)*sizeof(line[0]) );
1767
+ }
1768
+
1769
+
1770
+ double cv::pointPolygonTest( InputArray _contour,
1771
+ Point2f pt, bool measureDist )
1772
+ {
1773
+ Mat contour = _contour.getMat();
1774
+ CV_Assert(contour.checkVector(2) >= 0 &&
1775
+ (contour.depth() == CV_32F || contour.depth() == CV_32S));
1776
+ CvMat c = Mat(contour);
1777
+ return cvPointPolygonTest( &c, pt, measureDist );
1778
+ }
1779
+
1780
+ /* End of file. */