Move the sources to trunk
[opencv] / interfaces / matlab / src / wrmacro.h
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
42 #ifndef CV_WRAP_MACRO
43 #define CV_WRAP_MACRO
44
45 #include "cv.h"
46 #include <mex.h>
47
48 #include "tmacro.h"
49
50 #ifndef IPL_DEPTH_MASK
51 #define IPL_DEPTH_MASK 255
52 #endif
53
54 //----------------------------------- Classes ---------------------------------
55 template <class T>
56 class CArr
57 {
58 public:
59         T *pData;
60         bool ToClearData;
61         
62         CArr();
63         ~CArr();
64         inline void  Create( int num, bool tocleardata);
65         inline operator T*()
66         {
67                 return pData;
68         }
69
70         inline operator void*()
71         {
72                 return pData;
73         }
74
75         inline operator T()
76         {
77                 return pData[0];
78         }
79
80         inline T operator[](int n) const
81         {
82                 return pData[n];
83         }
84         
85         inline T* operator+(int n) const
86         {
87                 return pData + n;
88         }
89 };
90
91 template <class T>
92 inline CArr<T>::CArr()  
93 {
94         pData = NULL;
95         ToClearData = false;
96 }
97
98 template <class T>
99 inline CArr<T>::~CArr() 
100 {
101         if (ToClearData && pData)
102                 free(pData);
103 }
104
105 template <class T>
106 void  inline CArr<T>::Create( int num, bool tocleardata)
107 {
108         pData = (T*) calloc(1,sizeof(T)*num);
109         ToClearData = tocleardata;
110 }
111
112 //-------------------------------------------------
113 class CIplImage
114 {
115 public:
116         IplImage *pHeader;
117         void *pData;
118         bool ToClearData;
119         
120         CIplImage();
121         ~CIplImage();
122         void  CreateImageHeader( CvSize size, int depth, int channels );
123         void  SetImageData( void* data, int step , bool tocleardata);
124         inline operator IplImage*() const
125         {
126                 return pHeader;
127         }
128 };
129
130 inline CIplImage::CIplImage() 
131 {
132         pHeader = NULL;
133         pData = NULL;
134         ToClearData = false;
135 }
136
137 inline CIplImage::~CIplImage() 
138 {
139         if (ToClearData && pData)
140                 free(pData);
141         
142         if (pHeader)
143                 cvReleaseImageHeader(&pHeader);
144 }
145
146 inline void CIplImage::CreateImageHeader( CvSize size, int depth, int channels )
147 {
148         if (!pHeader)
149                 pHeader = cvCreateImageHeader( size, depth, channels );
150         return;
151 }
152
153 inline void CIplImage::SetImageData( void* data, int step, bool tocleardata )
154 {
155         if (pHeader && !pData)
156         {
157                 pData = data;
158                 ToClearData = tocleardata;
159                 cvSetImageData( pHeader, data, step );
160         }
161         return;
162 }
163
164 //----------------------------------- Macroses---------------------------------
165
166 /*#define WRAPPER( nargin , nargout, wrapper_name ) \
167 void  wrapper_name (const CV::FrontEnd::ArgValType& arginhandle, CV::FrontEnd::ReturnValType& argouthandle){ \
168                 arginhandle.verify_nargin(nargin); \
169                 argouthandle.verify_nargout(nargout)*/
170
171 #define WRAPPER( nargin , nargout, wrapper_name ) \
172 void  wrapper_name (int nlhs, mxArray* plhs[], int nrhs, mxArray* prhs[]) { \
173         if (nrhs != nargin) \
174         { \
175         std::ostringstream ostr; \
176                 ostr << "Function expected " << nargin << " input argument"; \
177                 if (nargin != 1) \
178                         ostr << "s"; \
179                 throw_error(ostr.str()); \
180         } \
181         if (nlhs != nargout) \
182         { \
183         std::ostringstream ostr; \
184                 ostr << "Function expected " << nargout << " output argument"; \
185                 if (nargout != 1) \
186                         ostr << "s"; \
187                 throw_error(ostr.str()); \
188         }
189
190 #define RET \
191         return; \
192         }
193
194 #define PARAM( name, param ) name##_##param
195
196 // {{ Macros for row or column vector of numbers
197 #define VECTOR_IN( n, type, name, size, cond ) \
198         int  name##_num        = size;  \
199         bool name##_anyClass   = true;  \
200         bool name##_allowEmpty = false; \
201         bool name##_inPlace    = false; /* use matlab data directly */ \
202         mxClassID name##_class = mxDOUBLE_CLASS; \
203         VecType name##_vecType = any; /* type of vector */ \
204          \
205         CArray< type > name; \
206          \
207         cond; \
208          \
209         _ENHANCE_ERROR( \
210                 verifyVector( prhs[n], name##_num, name##_vecType, name##_allowEmpty, \
211                         name##_anyClass, name##_class ); \
212                 if( !mxIsEmpty( prhs[n] ) ) \
213                 { \
214                         if( !name##_inPlace ) \
215                         { \
216                                 name.create( name##_num ); \
217                                 MXTYPE_DATAPTR( name##_class, ;, _srcData, \
218                                         mxGetData( prhs[n] ); \
219                                         castCopy( _srcData, (type *)name, 1, name##_num, \
220                                                 1, 1, 1, 1 ) ); \
221                         } \
222                         else \
223                         { \
224                                 name.set( (type *)mxGetData( prhs[n]) ); \
225                         } \
226                 } \
227                 , \
228                 name ) 
229
230 #define VECTOR_OUT( n, type, name, size, cond ) \
231         int  name##_num        = size;  \
232         bool name##_anyClass   = true;  \
233         bool name##_inPlace    = false; /* use matlab data directly */ \
234         mxClassID name##_class = mxDOUBLE_CLASS; \
235         int  name##_n          = n; \
236         VecType name##_vecType = any; /* type of vector */ \
237          \
238         CArray< type > name; \
239          \
240         cond; \
241          \
242         _ENHANCE_ERROR( \
243                         if( !name##_inPlace ) \
244                         { \
245                                 name.create( name##_num ); \
246                         } \
247                         else \
248                         { \
249                                 _CREATE_VECTOR( name ); \
250                                 name.set( (type *)mxGetData( plhs[n]) ); \
251                         } \
252                         , \
253                         name ) 
254
255
256
257 #define PUT_VECTOR( name ) \
258         if( !name##_inPlace ) \
259         { \
260                 _CREATE_VECTOR( name ); \
261                 MXTYPE_DATAPTR( name##_class, ;, _dstData, \
262                         mxGetData( plhs[name##_n] ); \
263                         castCopy( name.getData(), _dstData, 1, name##_num, \
264                                         1, 1, 1, 1 ) ); \
265         }
266
267 // }} Macros for row or column vector of numbers
268
269 // {{ Macros for single number
270 #define NUM_IN( n, type, name ) \
271         mxClassID name##_class = mxDOUBLE_CLASS; \
272         type name; \
273         _ENHANCE_ERROR( \
274                 int _num = 1; \
275                 verifyMatrix( prhs[n], _num, _num, false, \
276                         true, name##_class ); \
277                 MXTYPE_DATAPTR( name##_class, ;,  _srcData, mxGetData( prhs[n] ); \
278                         castCopy( _srcData, (type *)&name, 1, 1, 1, 1, 1, 1 ) ); \
279                 , \
280                 name ) 
281
282 #define NUM_OUT( n, type, name, cond ) \
283         mxClassID name##_class = mxDOUBLE_CLASS; \
284         int  name##_n          = n; \
285          \
286         type name; \
287          \
288         cond; \
289
290 #define PUT_NUM( name ) \
291         _CREATE_MATRIX( name##_n, 1, 1, name##_class ); \
292         MXTYPE_DATAPTR( name##_class, ;, _dstData, mxGetData( plhs[name##_n] ); \
293                 castCopy( &name, _dstData, 1, 1, 1, 1, 1, 1 ) );
294 // }} Macros for single number
295
296 // {{ Macros for C array of struct
297 #define ARRAY_IN( n, type, name, size, cond ) \
298         int  name##_num        = size;  \
299         bool name##_anyClass   = true;  \
300         bool name##_allowEmpty = false; \
301         bool name##_inPlace    = false; /* use matlab data directly */ \
302         mxClassID name##_class = mxDOUBLE_CLASS; \
303          \
304         CArray< type > name; \
305         \
306         cond; \
307         \
308         _ENHANCE_ERROR( \
309                 int _numFields = type##NUMFIELDS; \
310                 verifyMatrix( prhs[n], name##_num, _numFields, name##_allowEmpty, \
311                         name##_anyClass, name##_class ); \
312                  \
313                 if( !mxIsEmpty( prhs[n] ) ) \
314                 { \
315                         if( !name##_inPlace ) \
316                         { \
317                                 name.create( name##_num ); \
318                                 MXTYPE_DATAPTR( name##_class, ;,  _srcData, mxGetData( prhs[n] ); \
319                                         convert( _srcData, (type *)name, name##_num ) ); \
320                         } \
321                         else \
322                         { \
323                                 name.set( (type *)mxGetData( prhs[n]) ); \
324                         } \
325                 } \
326                 , \
327                 name ) 
328
329 #define ARRAY_OUT( n, type, name, size, cond ) \
330         int  name##_num        = size;  \
331         bool name##_anyClass   = true;  \
332         bool name##_inPlace    = false; /* use matlab data directly */ \
333         mxClassID name##_class = mxDOUBLE_CLASS; \
334         int  name##_n          = n; \
335         int  name##_numFields  = type##NUMFIELDS; \
336          \
337         CArray< type > name; \
338          \
339         cond; \
340          \
341         _ENHANCE_ERROR( \
342                 mxDestroyArray( plhs[n] ); \
343                 if( !name##_inPlace ) \
344                 { \
345                         name.create( name##_num ); \
346                 } \
347                 else \
348                 { \
349                         _CREATE_MATRIX( n, name##_num, name##_numFields, name##_class ); \
350                         name.set( (type *)mxGetData( plhs[n]) ); \
351                 } \
352                 , \
353                 name ) 
354
355 #define PUT_ARRAY( name ) \
356         if( !name##_inPlace ) \
357         { \
358                 _CREATE_MATRIX( name##_n, name##_num, name##_numFields, name##_class ); \
359                 MXTYPE_DATAPTR( name##_class, ;, _dstData, mxGetData( plhs[name##_n] ); \
360                         convert( name.getData(), _dstData, name##_num ) ); \
361         }
362
363 // create temporary array
364 #define TEMP_ARRAY( type, name, size ) \
365         CArray< type > name; \
366         name.create( size );
367 // }} Macros for C array of struct
368
369 // {{ Macros for image
370 #define IMG_IN( n, name, cond ) \
371         CvSize    name##_size        = cvSize( -1, -1 ); \
372         int       name##_channels    = -1; \
373         bool      name##_anyClass    = true; \
374         mxClassID name##_class       = mxDOUBLE_CLASS; \
375         bool      name##_anyDepth    = true; \
376         int       name##_depth       = IPL_DEPTH_8U; \
377         bool      name##_allowEmpty  = false; \
378         bool      name##_inPlace     = true; \
379          \
380         cond; \
381          \
382     CImage name; \
383          \
384         _ENHANCE_ERROR( \
385                 int dims[3]; \
386                 dims[0] = name##_size.width; \
387                 dims[1] = name##_size.height; \
388                 dims[2] = name##_channels; \
389                 int ndim = ( name##_channels < 1 ) ? -1 : \
390                         ( ( name##_channels != 1 ) ? 3 : 2 ); \
391                 verifyArray( prhs[n], dims, ndim, \
392                         name##_allowEmpty, name##_anyClass, name##_class ); \
393                 name##_size.width  = dims[0]; \
394                 name##_size.height = dims[1]; \
395                 name##_channels    = ( ndim == 2 ) ? 1 : dims[2]; \
396                  \
397                 if( !mxIsEmpty( prhs[n] ) ) \
398                 { \
399                         verifyDepth( name##_class, name##_anyDepth, name##_depth ); \
400                          \
401                                 void *name##_data      = mxGetData( prhs[n] ); \
402                                 int name##_typeSize    = \
403                                         ( IPL_DEPTH_MASK & name##_depth ) / 8; \
404                                 int name##_step        = name##_typeSize * name##_size.width; \
405                                 int name##_channelSize = name##_step * name##_size.height; \
406                          \
407                         name.createHeader( name##_size, name##_depth, name##_channels ); \
408                         if( name##_channels == 3 ) \
409                         { \
410                                 CImage name##_r; \
411                                 name##_r.createHeader( name##_size, name##_depth, 1 ); \
412                                 name##_r.setData( name##_data, name##_step ); \
413                                 CImage name##_g; \
414                                 name##_g.createHeader( name##_size, name##_depth, 1 ); \
415                                 name##_g.setData( (char *)name##_data + name##_channelSize, \
416                                         name##_step ); \
417                                 CImage name##_b; \
418                                 name##_b.createHeader( name##_size, name##_depth, 1 ); \
419                                 name##_b.setData( \
420                                         (char *)name##_data + 2 * name##_channelSize, \
421                                         name##_step ); \
422                                 name.createData(); \
423                                 cvCvtPlaneToPix( (IplImage *)name##_r, (IplImage *)name##_g, \
424                                         (IplImage *)name##_b, 0, (IplImage *)name ); \
425                         } \
426                         else \
427                         { /* single channel */ \
428                                 if( name##_inPlace ) \
429                                 { \
430                                         name.setData( name##_data, name##_step ); \
431                                 } \
432                                 else \
433                                 { \
434                                         CImage tmpImage; \
435                                         tmpImage.createHeader( name##_size, \
436                                                 name##_depth, name##_channels ); \
437                                         tmpImage.setData( name##_data, name##_step ); \
438                                         name.createData(); \
439                                         cvCopy( (IplImage *)tmpImage, (IplImage *)name ); \
440                                 } \
441                         } \
442                 } \
443                 , \
444                 name ) 
445
446 #define IMG_OUT( n, name, cond ) \
447         CvSize    name##_size        = cvSize( -1, -1 ); \
448         int       name##_channels    = -1; \
449         mxClassID name##_class       = mxDOUBLE_CLASS; \
450         int       name##_depth       = IPL_DEPTH_8U; \
451         bool      name##_inPlace     = true; \
452         int       name##_n           = n; \
453          \
454         cond; \
455          \
456     CImage name; \
457          \
458         _ENHANCE_ERROR( \
459                 verifyDepth( name##_class, true, name##_depth ); \
460                 name.createHeader( name##_size, name##_depth, name##_channels ); \
461                 if( name##_channels == 3 || !name##_inPlace ) \
462                 { \
463                         name.createData(); \
464                 } \
465                 else \
466                 { /* single channel */ \
467                         if( name##_inPlace ) \
468                         { \
469                                 _CREATE_IMAGE( name ); \
470                                 void *name##_data      = mxGetData( plhs[name##_n] ); \
471                                 int name##_typeSize    = \
472                                         ( IPL_DEPTH_MASK & name##_depth ) / 8; \
473                                 int name##_step        = name##_typeSize * name##_size.width; \
474                                 int name##_channelSize = name##_step * name##_size.height; \
475                                 name.setData( name##_data, name##_step ); \
476                         } \
477                 } \
478                 , \
479                 name ) 
480
481 #define PUT_IMG( name ) \
482         if( name##_channels == 3 || !name##_inPlace ) \
483         { \
484                 _CREATE_IMAGE( name ); \
485                 void *name##_data      = mxGetData( plhs[name##_n] ); \
486                 int name##_typeSize    = ( IPL_DEPTH_MASK & name##_depth ) / 8; \
487                 int name##_step        = name##_typeSize * name##_size.width; \
488                 int name##_channelSize = name##_step * name##_size.height; \
489                 if( name##_channels == 3 ) \
490                 { \
491                         CImage name##_r; \
492                         name##_r.createHeader( name##_size, name##_depth, 1 ); \
493                         name##_r.setData( name##_data, name##_step ); \
494                         CImage name##_g; \
495                         name##_g.createHeader( name##_size, name##_depth, 1 ); \
496                         name##_g.setData( (char *)name##_data + name##_channelSize, \
497                                 name##_step ); \
498                         CImage name##_b; \
499                         name##_b.createHeader( name##_size, name##_depth, 1 ); \
500                         name##_b.setData( (char *)name##_data + 2 * name##_channelSize, \
501                                 name##_step ); \
502                         cvCvtPixToPlane( (IplImage *)name, \
503                                 (IplImage *)name##_r, \
504                                 (IplImage *)name##_g, \
505                                 (IplImage *)name##_b, \
506                                 0 ); \
507                 } \
508                 else \
509                 { \
510                         CImage tmpImage; \
511                         tmpImage.createHeader( name##_size, name##_depth, \
512                             name##_channels ); \
513                         tmpImage.setData( name##_data, name##_step ); \
514                         cvCopy( (IplImage *)name, (IplImage *)tmpImage ); \
515                 } \
516         }
517
518 // create temporary image and allocate image data
519 #define TEMP_IMAGE( name, size, depth, channels ) \
520         CImage name; \
521         name.createHeader( size, depth, channels ); \
522         name.createData();
523
524 // }} Macros for image
525
526 // {{ Macros for sequences
527 #define SEQ_IN( n, first, name, pointType, rectType, cond ) \
528         bool name##_recursive  = true; \
529         int  name##_maxLevel   = 0; \
530         bool name##_allowEmpty = false; \
531         int  name##_num        = -1; /* number of sequences */ \
532         int  name##_headerSize = sizeof( CvContour ); \
533          \
534         cond; \
535          \
536         CStorage   name##_storage; \
537         CvContour *name = 0; \
538          \
539         _ENHANCE_ERROR( \
540                 int _rows = 1; \
541                 mxClassID mxClass = mxSTRUCT_CLASS; \
542                 verifyMatrix( prhs[n], _rows, name##_num, name##_allowEmpty, false, \
543                         mxClass ); \
544                 if( name##_num > 0 ) \
545                 { \
546                         int icur = 0; /* current index (1 based) */ \
547                          \
548                         CvSeq *prev_contour = 0; \
549                         CvSeq *parent = 0; \
550                         CvSeq *cur   = 0; \
551                         int isrc_seq = first; /* starting point */ \
552                         int level    = 1; \
553                         int maxLevel = name##_maxLevel; \
554                         mxClassID   dataClass; \
555                         void       *dataPtr = 0; \
556                         int         dataNum = 0; \
557                         CvRect      rect; \
558                         int         type  = 0; \
559                         int         flags = 0; \
560                         CvSeqWriter writer; \
561                         int         nelem = 0; \
562                          \
563                         TEMP_ARRAY( int, h_prev, name##_num ); \
564                         TEMP_ARRAY( int, h_next, name##_num ); \
565                         TEMP_ARRAY( int, v_prev, name##_num ); \
566                         TEMP_ARRAY( int, v_next, name##_num ); \
567                          \
568                         while( isrc_seq != 0 ) \
569                         { \
570                                 icur++; \
571                                 verifySeq( prhs[n], name##_num, isrc_seq-1, \
572                                         dataClass, dataPtr, dataNum, rect, \
573                                         type, h_prev[isrc_seq-1], h_next[isrc_seq-1], \
574                                         v_prev[isrc_seq-1], v_next[isrc_seq-1] ); \
575                                 flags = CV_SEQ_CONTOUR | \
576                                         ( ( type == 1 ) ? CV_SEQ_FLAG_HOLE : 0 ); \
577                                 cvStartWriteSeq( flags, name##_headerSize, sizeof( CvPoint ), \
578                                         name##_storage, &writer ); \
579                                 TEMP_ARRAY( pointType, tmpData, dataNum ); \
580                                 MXTYPE_DATAPTR( dataClass, ;, dataData, dataPtr; \
581                                         convert( dataData, tmpData, dataNum ); ); \
582                                 for( nelem = 0; nelem < dataNum; nelem++ ) \
583                                 { \
584                                         CV_WRITE_SEQ_ELEM( (tmpData[nelem]), writer ); \
585                                 } /* for each elem in arr */ \
586                                 cur = (CvSeq *)cvEndWriteSeq( &writer ); \
587                                 if( !name ) name = (CvContour *)cur; \
588                                 convert( (int *)&rect, \
589                                         (rectType *)&(((CvContour *)cur)->rect), 1 ); \
590                                  \
591                                 if( maxLevel < 0 && !name##_recursive ) \
592                                 { \
593                                         h_next[isrc_seq-1] = 0; \
594                                         maxLevel = -maxLevel; \
595                                 } \
596                                  \
597                                 cur->v_prev = parent; \
598                                 cur->h_prev = prev_contour; \
599                                  \
600                                 cur->v_next = 0; \
601                                 cur->h_next = 0; \
602                                  \
603                                 if( maxLevel == 0 && !name##_recursive ) \
604                                 { \
605                                         break; \
606                                 } \
607                                  \
608                                 if( prev_contour ) \
609                                 { \
610                                         prev_contour->h_next = cur; \
611                                 } \
612                                 else if( parent ) \
613                                 { \
614                                         parent->v_next = cur; \
615                                 } \
616                                 prev_contour = cur; \
617                                  \
618                                 if( v_next[isrc_seq-1] != 0 && \
619                                         ( level < maxLevel || name##_recursive ) ) \
620                                 { \
621                                         assert( prev_contour != 0 ); \
622                                         parent = prev_contour; \
623                                         prev_contour = 0; \
624                                         isrc_seq = v_next[isrc_seq-1]; \
625                                         level++; \
626                                 } \
627                                 else \
628                                 { \
629                                         while( h_next[isrc_seq-1] == 0 ) \
630                                         { \
631                                                 isrc_seq = v_prev[isrc_seq-1]; \
632                                                 level--; \
633                                                 if( level == 0 && !name##_recursive ) \
634                                                 { \
635                                                         isrc_seq = 0; \
636                                                 } \
637                                                 if( isrc_seq == 0 ) \
638                                                 { \
639                                                         break; \
640                                                 } \
641                                                 prev_contour = parent; \
642                                                 if( parent ) \
643                                                 { \
644                                                         parent = parent->v_prev; \
645                                                 } \
646                                         } \
647                                         if( isrc_seq ) \
648                                         { \
649                                                 isrc_seq = h_next[isrc_seq-1]; \
650                                         } \
651                                 } \
652                         } \
653                         name##_num = icur; \
654                 } /* not empty */ \
655                 , \
656                 name )
657 /* end SEQ_IN( ... ) */
658
659 #define SEQ_OUT( n, name, cond ) \
660         int       name##_n          = n; \
661         int       name##_num        = 0; /* number of sequences */ \
662         mxClassID name##_pointClass = mxDOUBLE_CLASS; \
663         int       name##_headerSize = sizeof( CvContour ); \
664          \
665         cond; \
666          \
667         CStorage   name##_storage; \
668         CvContour *name = 0;
669
670 #define PUT_SEQ( name, pointType, rectType ) \
671         _ENHANCE_ERROR( \
672                 mxDestroyArray( plhs[name##_n] ); \
673                 const char *fieldnames[7]; \
674                 fieldnames[0] = "data"; \
675                 fieldnames[1] = "rect"; \
676                 fieldnames[2] = "type"; \
677                 fieldnames[3] = "h_prev"; \
678                 fieldnames[4] = "h_next"; \
679                 fieldnames[5] = "v_prev"; \
680                 fieldnames[6] = "v_next"; \
681                  \
682                 plhs[name##_n] = mxCreateStructMatrix( (name##_num > 0) ? 1 : 0, \
683                         name##_num, \
684                         sizeof( fieldnames ) / sizeof( fieldnames[0] ), \
685                         fieldnames ); \
686                 if( name##_num > 0 ) \
687                 { \
688                         TEMP_ARRAY( int,     h_prev, name##_num ); \
689                         TEMP_ARRAY( int,     h_next, name##_num ); \
690                         TEMP_ARRAY( int,     v_prev, name##_num ); \
691                         TEMP_ARRAY( int,     v_next, name##_num ); \
692                         TEMP_ARRAY( CvSeq *, seq,    name##_num ); \
693                          \
694                         /* indexes of the previous and parent sequences (1 based) */ \
695                         int iprev_contour = 0; \
696                         int iparent = 0; \
697                         int icur = 0; /* current index (1 based) */ \
698                         CvSeq *src_seq = (CvSeq *)name; /* starting point */ \
699                          \
700                         while( src_seq != 0 ) \
701                         { \
702                                 icur++; \
703                                 if( icur > name##_num ) \
704                                 { \
705                                         throw_error( "Too many sequences. May be broken links." ); \
706                                         return; \
707                                 } \
708                                 /* put src_seq into StructArray[icur] */ \
709                                 seq[icur-1] = (CvSeq *)src_seq; \
710                                  \
711                                 v_prev[icur-1] = iparent; \
712                                 h_prev[icur-1] = iprev_contour; \
713                                 v_next[icur-1] = 0; \
714                                 h_next[icur-1] = 0; \
715                                  \
716                                 if( iprev_contour ) \
717                                 { \
718                                         h_next[iprev_contour-1] = icur; \
719                                 } \
720                                 else if( iparent ) \
721                                 { \
722                                         v_next[iparent-1] = icur; \
723                                 } \
724                                 iprev_contour = icur; \
725                                  \
726                                 if( src_seq->v_next ) \
727                                 { \
728                                         assert( iprev_contour != 0 ); \
729                                         iparent = iprev_contour; \
730                                         iprev_contour = 0; \
731                                         src_seq = src_seq->v_next; \
732                                 } \
733                                 else \
734                                 { \
735                                         while( src_seq->h_next == 0 ) \
736                                         { \
737                                                 src_seq = src_seq->v_prev; \
738                                                 if( src_seq == 0 ) \
739                                                 { \
740                                                         break; \
741                                                 } \
742                                                 iprev_contour = iparent; \
743                                                 if( iparent ) \
744                                                 { \
745                                                         /* iparent = parent->v_prev */ \
746                                                         iparent = v_prev[iparent-1]; \
747                                                 } \
748                                         } \
749                                         if( src_seq ) \
750                                         { \
751                                                 src_seq = src_seq->h_next; \
752                                         } \
753                                 } \
754                         } \
755                         if( icur < name##_num ) \
756                         { \
757                                 /* shorten struct array if there are */ \
758                                 /* less than name##_num  seqences */ \
759                                 name##_num = icur; \
760                                 mxSetM( plhs[name##_n], icur ); \
761                                 mxSetN( plhs[name##_n], (icur == 0) ? 0 : 1 ); \
762                         } \
763                         /* copy data into MATLAB */ \
764                         /* data */ \
765                         MXTYPE_DATAPTR( name##_pointClass, \
766                                 mxArray     *mxFdata = 0; \
767                                 for( icur = 0; icur < name##_num; icur++ ) \
768                                 { \
769                                         mxFdata = mxCreateNumericMatrix( seq[icur]->total, \
770                                                 pointType##NUMFIELDS, name##_pointClass, mxREAL );, \
771                                         dataData, mxGetData( mxFdata ); \
772                                         TEMP_ARRAY( pointType, tmpArr, seq[icur]->total ); \
773                                         cvCvtSeqToArray( (CvSeq *)seq[icur], \
774                                                 (void *)(pointType *)tmpArr ); \
775                                         convert( (pointType *)tmpArr, dataData, seq[icur]->total );\
776                                         mxSetField( plhs[name##_n], icur, "data", mxFdata ); \
777                                 } \
778                                 ); \
779                          \
780                         /* rect, type, references */ \
781                         mxArray *mxFrect   = 0; \
782                         mxArray *mxFtype   = 0; \
783                         mxArray *mxFh_prev = 0; \
784                         mxArray *mxFh_next = 0; \
785                         mxArray *mxFv_prev = 0; \
786                         mxArray *mxFv_next = 0; \
787                          \
788                         double *rectData   = 0; \
789                         double *typeData   = 0; \
790                         double *h_prevData = 0; \
791                         double *h_nextData = 0; \
792                         double *v_prevData = 0; \
793                         double *v_nextData = 0; \
794                         int     type       = 0; \
795                         for( icur = 0; icur < name##_num; icur++ ) \
796                         { \
797                                 /* rect */ \
798                                 mxFrect = mxCreateNumericMatrix( \
799                                         1, rectType##NUMFIELDS, mxDOUBLE_CLASS, mxREAL ); \
800                                 rectData = (double *) mxGetData( mxFrect ); \
801                                 convert( (rectType *)&(((CvContour *)seq[icur])->rect), \
802                                                  rectData, 1 ); \
803                                 mxSetField( plhs[name##_n], icur, "rect", mxFrect ); \
804                                 /* type */ \
805                                 type = ( CV_IS_SEQ_HOLE( seq[icur] ) ) ? 1 : 0; \
806                                 mxFtype = mxCreateNumericMatrix( \
807                                         1, 1, mxDOUBLE_CLASS, mxREAL ); \
808                                 typeData = (double *)mxGetData( mxFtype ); \
809                                 castCopy( &type, typeData, 1, 1, 1, 1, 1, 1 ); \
810                                 mxSetField( plhs[name##_n], icur, "type", mxFtype ); \
811                                 /* h_prev */ \
812                                 mxFh_prev = mxCreateNumericMatrix( \
813                                         1, 1, mxDOUBLE_CLASS, mxREAL ); \
814                                 h_prevData = (double *)mxGetData( mxFh_prev ); \
815                                 castCopy( &(h_prev[icur]), h_prevData, \
816                                         1, 1, 1, 1, 1, 1 ); \
817                                 mxSetField( plhs[name##_n], icur, "h_prev", mxFh_prev ); \
818                                 /* h_next */ \
819                                 mxFh_next = mxCreateNumericMatrix( \
820                                         1, 1, mxDOUBLE_CLASS, mxREAL ); \
821                                 h_nextData = (double *)mxGetData( mxFh_next ); \
822                                 castCopy( &(h_next[icur]), h_nextData, \
823                                         1, 1, 1, 1, 1, 1 ); \
824                                 mxSetField( plhs[name##_n], icur, "h_next", mxFh_next ); \
825                                 /* v_prev */ \
826                                 mxFv_prev = mxCreateNumericMatrix( \
827                                         1, 1, mxDOUBLE_CLASS, mxREAL ); \
828                                 v_prevData = (double *)mxGetData( mxFv_prev ); \
829                                 castCopy( &(v_prev[icur]), v_prevData, \
830                                         1, 1, 1, 1, 1, 1 ); \
831                                 mxSetField( plhs[name##_n], icur, "v_prev", mxFv_prev ); \
832                                 /* v_next */ \
833                                 mxFv_next = mxCreateNumericMatrix( \
834                                         1, 1, mxDOUBLE_CLASS, mxREAL ); \
835                                 v_nextData = (double *)mxGetData( mxFv_next ); \
836                                 castCopy( &(v_next[icur]), v_nextData, \
837                                         1, 1, 1, 1, 1, 1 ); \
838                                 mxSetField( plhs[name##_n], icur, "v_next", mxFv_next ); \
839                         } \
840                 } /* if name##_num > 0 */ \
841                 , \
842                 name )
843 /* end PUT_SEQ( ... ) */
844 // }} Macros for sequences
845
846 // {{ Macros for structuring element
847 #define STRUCTELEM_IN( n1, n2, name, cond ) \
848         int            name##_nCols      = 0; \
849         int            name##_nRows      = 0; \
850         int            name##_anchorX    = 0; \
851         int            name##_anchorY    = 0; \
852         CvElementShape name##_shape      = CV_SHAPE_CUSTOM; \
853         int           *_name##_values    = 0; \
854         bool           name##_allowEmpty = false; \
855          \
856         CStructElem    name; \
857          \
858         cond; \
859          \
860         _ENHANCE_ERROR( \
861                 MATRIX_IN( n1, int, name##Values, -1, -1, \
862                         PARAM( name##Values, transpose )  = false; \
863                         PARAM( name##Values, allowEmpty ) = name##_allowEmpty; ); \
864                 if( (int *)name##Values ) \
865                 { \
866                         /* not empty */ \
867                         if( PARAM( name##Values, nRows ) == 1 && \
868                                 PARAM( name##Values, nCols ) == 1 ) \
869                         { \
870                                 /* predefined kernel */ \
871                                 name##_shape = (CvElementShape)(int)name##Values[0]; \
872                                 VECTOR_IN( n2, int, name##Size, 4, ; ); \
873                                 name##_nCols   = name##Size[0]; \
874                                 name##_nRows   = name##Size[1]; \
875                                 name##_anchorX = name##Size[2] - 1; \
876                                 name##_anchorY = name##Size[3] - 1; \
877                         } \
878                         else \
879                         { \
880                                 /* user-defined kernel */ \
881                                 name##_nCols   = PARAM( name##Values, nRows ); \
882                                 name##_nRows   = PARAM( name##Values, nCols ); \
883                                 VECTOR_IN( n2, int, name##Size, 2, ; ); \
884                                 name##_anchorX = name##Size[0] - 1; \
885                                 name##_anchorY = name##Size[1] - 1; \
886                                 _name##_values = (int *)name##Values; \
887                         } \
888                         name.create( name##_nRows, name##_nCols, \
889                                 name##_anchorY, name##_anchorX, name##_shape, _name##_values );\
890                 } \
891                 , \
892                 name )
893 // }} Macros for structuring element
894
895 // {{ Macros for matrix
896 #define MATRIX_IN( n, type, name, nRows, nCols, cond ) \
897         int  name##_nRows      = nRows;  \
898         int  name##_nCols      = nCols;  \
899         bool name##_anyClass   = true;  \
900         bool name##_allowEmpty = false; \
901         bool name##_inPlace    = false; /* use matlab data directly */ \
902         bool name##_transpose  = true; \
903         mxClassID name##_class = mxDOUBLE_CLASS; \
904          \
905         CArray< type > name; \
906         \
907         cond; \
908         \
909         _ENHANCE_ERROR( \
910                 verifyMatrix( prhs[n], name##_nRows, name##_nCols, name##_allowEmpty, \
911                         name##_anyClass, name##_class ); \
912                  \
913                 if( !mxIsEmpty( prhs[n] ) ) \
914                 { \
915                         if( !name##_inPlace ) \
916                         { \
917                                 name.create( name##_nRows * name##_nCols ); \
918                                 MXTYPE_DATAPTR( name##_class, ;,\
919                                         _srcData, mxGetData( prhs[n] ); \
920                                         if( name##_transpose ) \
921                                         { \
922                                                 castCopy( _srcData, (type *)name, \
923                                                         name##_nRows, name##_nCols, 1, name##_nRows, \
924                                                         name##_nCols, 1 ); \
925                                         } \
926                                         else \
927                                         { \
928                                                 castCopy( _srcData, (type *)name, \
929                                                         1, name##_nRows * name##_nCols, 1, 1, \
930                                                         1, 1 ); \
931                                         } \
932                                         ); \
933                         } \
934                         else \
935                         { \
936                                 name.set( (type *)mxGetData( prhs[n]) ); \
937                         } \
938                 } \
939                 , \
940                 name ) 
941
942 // }} Macros for matrix
943
944 #endif // CV_WRAP_MACRO