]> rtime.felk.cvut.cz Git - opencv.git/blob - opencv/src/cxcore/cxarray.cpp
moved matrix-related operations from cxoperations.hpp to separate cxmat.hpp. removed...
[opencv.git] / opencv / src / cxcore / cxarray.cpp
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 /* ////////////////////////////////////////////////////////////////////
43 //
44 //  CvMat, CvMatND, CvSparceMat and IplImage support functions
45 //  (creation, deletion, copying, retrieving and setting elements etc.)
46 //
47 // */
48
49 #include "_cxcore.h"
50
51
52 static struct
53 {
54     Cv_iplCreateImageHeader  createHeader;
55     Cv_iplAllocateImageData  allocateData;
56     Cv_iplDeallocate  deallocate;
57     Cv_iplCreateROI  createROI;
58     Cv_iplCloneImage  cloneImage;
59 }
60 CvIPL;
61
62 // Makes the library use native IPL image allocators
63 CV_IMPL void
64 cvSetIPLAllocators( Cv_iplCreateImageHeader createHeader,
65                     Cv_iplAllocateImageData allocateData,
66                     Cv_iplDeallocate deallocate,
67                     Cv_iplCreateROI createROI,
68                     Cv_iplCloneImage cloneImage )
69 {
70     if( !createHeader || !allocateData || !deallocate || !createROI || !cloneImage )
71     {
72         if( createHeader || allocateData || deallocate || createROI || cloneImage )
73             CV_Error( CV_StsBadArg, "Either all the pointers should be null or "
74                                     "they all should be non-null" );
75     }
76
77     CvIPL.createHeader = createHeader;
78     CvIPL.allocateData = allocateData;
79     CvIPL.deallocate = deallocate;
80     CvIPL.createROI = createROI;
81     CvIPL.cloneImage = cloneImage;
82 }
83
84
85 /****************************************************************************************\
86 *                               CvMat creation and basic operations                      *
87 \****************************************************************************************/
88
89 // Creates CvMat and underlying data
90 CV_IMPL CvMat*
91 cvCreateMat( int height, int width, int type )
92 {
93     CvMat* arr = cvCreateMatHeader( height, width, type );
94     cvCreateData( arr );
95
96     return arr;
97 }
98
99
100 static void icvCheckHuge( CvMat* arr )
101 {
102     if( (int64)arr->step*arr->rows > INT_MAX )
103         arr->type &= ~CV_MAT_CONT_FLAG;
104 }
105
106 // Creates CvMat header only
107 CV_IMPL CvMat*
108 cvCreateMatHeader( int rows, int cols, int type )
109 {
110     type = CV_MAT_TYPE(type);
111
112     if( rows <= 0 || cols <= 0 )
113         CV_Error( CV_StsBadSize, "Non-positive width or height" );
114
115     int min_step = CV_ELEM_SIZE(type)*cols;
116     if( min_step <= 0 )
117         CV_Error( CV_StsUnsupportedFormat, "Invalid matrix type" );
118
119     CvMat* arr = (CvMat*)cvAlloc( sizeof(*arr));
120
121     arr->step = min_step;
122     arr->type = CV_MAT_MAGIC_VAL | type | CV_MAT_CONT_FLAG;
123     arr->rows = rows;
124     arr->cols = cols;
125     arr->data.ptr = 0;
126     arr->refcount = 0;
127     arr->hdr_refcount = 1;
128
129     icvCheckHuge( arr );
130     return arr;
131 }
132
133
134 // Initializes CvMat header, allocated by the user
135 CV_IMPL CvMat*
136 cvInitMatHeader( CvMat* arr, int rows, int cols,
137                  int type, void* data, int step )
138 {
139     if( !arr )
140         CV_Error( CV_StsNullPtr, "" );
141
142     if( (unsigned)CV_MAT_DEPTH(type) > CV_DEPTH_MAX )
143         CV_Error( CV_BadNumChannels, "" );
144
145     if( rows <= 0 || cols <= 0 )
146         CV_Error( CV_StsBadSize, "Non-positive cols or rows" );
147  
148     type = CV_MAT_TYPE( type );
149     arr->type = type | CV_MAT_MAGIC_VAL;
150     arr->rows = rows;
151     arr->cols = cols;
152     arr->data.ptr = (uchar*)data;
153     arr->refcount = 0;
154     arr->hdr_refcount = 0;
155
156     int pix_size = CV_ELEM_SIZE(type);
157     int min_step = arr->cols*pix_size;
158
159     if( step != CV_AUTOSTEP && step != 0 )
160     {
161         if( step < min_step )
162             CV_Error( CV_BadStep, "" );
163         arr->step = step;
164     }
165     else
166     {
167         arr->step = min_step;
168     }
169
170     arr->type = CV_MAT_MAGIC_VAL | type |
171         (arr->rows == 1 || arr->step == min_step ? CV_MAT_CONT_FLAG : 0);
172
173     icvCheckHuge( arr );
174     return arr;
175 }
176
177
178 // Deallocates the CvMat structure and underlying data
179 CV_IMPL void
180 cvReleaseMat( CvMat** array )
181 {
182     if( !array )
183         CV_Error( CV_HeaderIsNull, "" );
184
185     if( *array )
186     {
187         CvMat* arr = *array;
188         
189         if( !CV_IS_MAT_HDR(arr) && !CV_IS_MATND_HDR(arr) )
190             CV_Error( CV_StsBadFlag, "" );
191
192         *array = 0;
193
194         cvDecRefData( arr );
195         cvFree( &arr );
196     }
197 }
198
199
200 // Creates a copy of matrix
201 CV_IMPL CvMat*
202 cvCloneMat( const CvMat* src )
203 {
204     if( !CV_IS_MAT_HDR( src ))
205         CV_Error( CV_StsBadArg, "Bad CvMat header" );
206
207     CvMat* dst = cvCreateMatHeader( src->rows, src->cols, src->type );
208
209     if( src->data.ptr )
210     {
211         cvCreateData( dst );
212         cvCopy( src, dst );
213     }
214
215     return dst;
216 }
217
218
219 /****************************************************************************************\
220 *                               CvMatND creation and basic operations                    *
221 \****************************************************************************************/
222
223 CV_IMPL CvMatND*
224 cvInitMatNDHeader( CvMatND* mat, int dims, const int* sizes,
225                    int type, void* data )
226 {
227     type = CV_MAT_TYPE(type);
228     int64 step = CV_ELEM_SIZE(type);
229
230     if( !mat )
231         CV_Error( CV_StsNullPtr, "NULL matrix header pointer" );
232
233     if( step == 0 )
234         CV_Error( CV_StsUnsupportedFormat, "invalid array data type" );
235
236     if( !sizes )
237         CV_Error( CV_StsNullPtr, "NULL <sizes> pointer" );
238
239     if( dims <= 0 || dims > CV_MAX_DIM )
240         CV_Error( CV_StsOutOfRange,
241         "non-positive or too large number of dimensions" );
242
243     for( int i = dims - 1; i >= 0; i-- )
244     {
245         if( sizes[i] <= 0 )
246             CV_Error( CV_StsBadSize, "one of dimesion sizes is non-positive" );
247         mat->dim[i].size = sizes[i];
248         if( step > INT_MAX )
249             CV_Error( CV_StsOutOfRange, "The array is too big" );
250         mat->dim[i].step = (int)step;
251         step *= sizes[i];
252     }
253
254     mat->type = CV_MATND_MAGIC_VAL | (step <= INT_MAX ? CV_MAT_CONT_FLAG : 0) | type;
255     mat->dims = dims;
256     mat->data.ptr = (uchar*)data;
257     mat->refcount = 0;
258     mat->hdr_refcount = 0;
259     return mat;
260 }
261
262
263 // Creates CvMatND and underlying data
264 CV_IMPL CvMatND*
265 cvCreateMatND( int dims, const int* sizes, int type )
266 {
267     CvMatND* arr = cvCreateMatNDHeader( dims, sizes, type );
268     cvCreateData( arr );
269
270     return arr;
271 }
272
273
274 // Creates CvMatND header only
275 CV_IMPL CvMatND*
276 cvCreateMatNDHeader( int dims, const int* sizes, int type )
277 {
278     if( dims <= 0 || dims > CV_MAX_DIM )
279         CV_Error( CV_StsOutOfRange,
280         "non-positive or too large number of dimensions" );
281
282     CvMatND* arr = (CvMatND*)cvAlloc( sizeof(*arr) );
283     
284     cvInitMatNDHeader( arr, dims, sizes, type, 0 );
285     arr->hdr_refcount = 1;
286     return arr;
287 }
288
289
290 // Creates a copy of nD array
291 CV_IMPL CvMatND*
292 cvCloneMatND( const CvMatND* src )
293 {
294     if( !CV_IS_MATND_HDR( src ))
295         CV_Error( CV_StsBadArg, "Bad CvMatND header" );
296
297     int* sizes = (int*)cvStackAlloc( src->dims*sizeof(sizes[0]) );
298
299     for( int i = 0; i < src->dims; i++ )
300         sizes[i] = src->dim[i].size;
301
302     CvMatND* dst = cvCreateMatNDHeader( src->dims, sizes, src->type );
303
304     if( src->data.ptr )
305     {
306         cvCreateData( dst );
307         cvCopy( src, dst );
308     }
309
310     return dst;
311 }
312
313
314 static CvMatND*
315 cvGetMatND( const CvArr* arr, CvMatND* matnd, int* coi )
316 {
317     CvMatND* result = 0;
318
319     if( coi )
320         *coi = 0;
321
322     if( !matnd || !arr )
323         CV_Error( CV_StsNullPtr, "NULL array pointer is passed" );
324
325     if( CV_IS_MATND_HDR(arr))
326     {
327         if( !((CvMatND*)arr)->data.ptr )
328             CV_Error( CV_StsNullPtr, "The matrix has NULL data pointer" );
329         
330         result = (CvMatND*)arr;
331     }
332     else
333     {
334         CvMat stub, *mat = (CvMat*)arr;
335         
336         if( CV_IS_IMAGE_HDR( mat ))
337             mat = cvGetMat( mat, &stub, coi );
338
339         if( !CV_IS_MAT_HDR( mat ))
340             CV_Error( CV_StsBadArg, "Unrecognized or unsupported array type" );
341         
342         if( !mat->data.ptr )
343             CV_Error( CV_StsNullPtr, "Input array has NULL data pointer" );
344
345         matnd->data.ptr = mat->data.ptr;
346         matnd->refcount = 0;
347         matnd->hdr_refcount = 0;
348         matnd->type = mat->type;
349         matnd->dims = 2;
350         matnd->dim[0].size = mat->rows;
351         matnd->dim[0].step = mat->step;
352         matnd->dim[1].size = mat->cols;
353         matnd->dim[1].step = CV_ELEM_SIZE(mat->type);
354         result = matnd;
355     }
356
357     return result;
358 }
359
360
361 // returns number of dimensions to iterate.
362 /*
363 Checks whether <count> arrays have equal type, sizes (mask is optional array
364 that needs to have the same size, but 8uC1 or 8sC1 type).
365 Returns number of dimensions to iterate through:
366 0 means that all arrays are continuous,
367 1 means that all arrays are vectors of continuous arrays etc.
368 and the size of largest common continuous part of the arrays 
369 */
370 CV_IMPL int
371 cvInitNArrayIterator( int count, CvArr** arrs,
372                       const CvArr* mask, CvMatND* stubs,
373                       CvNArrayIterator* iterator, int flags )
374 {
375     int dims = -1;
376     int i, j, size, dim0 = -1;
377     int64 step;
378     CvMatND* hdr0 = 0;
379
380     if( count < 1 || count > CV_MAX_ARR )
381         CV_Error( CV_StsOutOfRange, "Incorrect number of arrays" );
382
383     if( !arrs || !stubs )
384         CV_Error( CV_StsNullPtr, "Some of required array pointers is NULL" );
385
386     if( !iterator )
387         CV_Error( CV_StsNullPtr, "Iterator pointer is NULL" );
388
389     for( i = 0; i <= count; i++ )
390     {
391         const CvArr* arr = i < count ? arrs[i] : mask;
392         CvMatND* hdr;
393         
394         if( !arr )
395         {
396             if( i < count )
397                 CV_Error( CV_StsNullPtr, "Some of required array pointers is NULL" );
398             break;
399         }
400
401         if( CV_IS_MATND( arr ))
402             hdr = (CvMatND*)arr;
403         else
404         {
405             int coi = 0;
406             hdr = cvGetMatND( arr, stubs + i, &coi );
407             if( coi != 0 )
408                 CV_Error( CV_BadCOI, "COI set is not allowed here" );
409         }
410
411         iterator->hdr[i] = hdr;
412
413         if( i > 0 )
414         {
415             if( hdr->dims != hdr0->dims )
416                 CV_Error( CV_StsUnmatchedSizes,
417                           "Number of dimensions is the same for all arrays" );
418             
419             if( i < count )
420             {
421                 switch( flags & (CV_NO_DEPTH_CHECK|CV_NO_CN_CHECK))
422                 {
423                 case 0:
424                     if( !CV_ARE_TYPES_EQ( hdr, hdr0 ))
425                         CV_Error( CV_StsUnmatchedFormats,
426                                   "Data type is not the same for all arrays" );
427                     break;
428                 case CV_NO_DEPTH_CHECK:
429                     if( !CV_ARE_CNS_EQ( hdr, hdr0 ))
430                         CV_Error( CV_StsUnmatchedFormats,
431                                   "Number of channels is not the same for all arrays" );
432                     break;
433                 case CV_NO_CN_CHECK:
434                     if( !CV_ARE_CNS_EQ( hdr, hdr0 ))
435                         CV_Error( CV_StsUnmatchedFormats,
436                                   "Depth is not the same for all arrays" );
437                     break;
438                 }
439             }
440             else
441             {
442                 if( !CV_IS_MASK_ARR( hdr ))
443                     CV_Error( CV_StsBadMask, "Mask should have 8uC1 or 8sC1 data type" );
444             }
445
446             if( !(flags & CV_NO_SIZE_CHECK) )
447             {
448                 for( j = 0; j < hdr->dims; j++ )
449                     if( hdr->dim[j].size != hdr0->dim[j].size )
450                         CV_Error( CV_StsUnmatchedSizes,
451                                   "Dimension sizes are the same for all arrays" );
452             }
453         }
454         else
455             hdr0 = hdr;
456
457         step = CV_ELEM_SIZE(hdr->type);
458         for( j = hdr->dims - 1; j > dim0; j-- )
459         {
460             if( step != hdr->dim[j].step )
461                 break;
462             step *= hdr->dim[j].size;
463         }
464
465         if( j == dim0 && step > INT_MAX )
466             j++;
467
468         if( j > dim0 )
469             dim0 = j;
470
471         iterator->hdr[i] = (CvMatND*)hdr;
472         iterator->ptr[i] = (uchar*)hdr->data.ptr;
473     }
474
475     size = 1;
476     for( j = hdr0->dims - 1; j > dim0; j-- )
477         size *= hdr0->dim[j].size;
478
479     dims = dim0 + 1;
480     iterator->dims = dims;
481     iterator->count = count;
482     iterator->size = cvSize(size,1);
483
484     for( i = 0; i < dims; i++ )
485         iterator->stack[i] = hdr0->dim[i].size;
486
487     return dims;
488 }
489
490
491 // returns zero value if iteration is finished, non-zero otherwise
492 CV_IMPL int cvNextNArraySlice( CvNArrayIterator* iterator )
493 {
494     assert( iterator != 0 );
495     int i, dims, size = 0;
496
497     for( dims = iterator->dims; dims > 0; dims-- )
498     {
499         for( i = 0; i < iterator->count; i++ )
500             iterator->ptr[i] += iterator->hdr[i]->dim[dims-1].step;
501
502         if( --iterator->stack[dims-1] > 0 )
503             break;
504
505         size = iterator->hdr[0]->dim[dims-1].size;
506
507         for( i = 0; i < iterator->count; i++ )
508             iterator->ptr[i] -= (size_t)size*iterator->hdr[i]->dim[dims-1].step;
509
510         iterator->stack[dims-1] = size;
511     }
512
513     return dims > 0;
514 }
515
516
517 /****************************************************************************************\
518 *                            CvSparseMat creation and basic operations                   *
519 \****************************************************************************************/
520
521
522 // Creates CvMatND and underlying data
523 CV_IMPL CvSparseMat*
524 cvCreateSparseMat( int dims, const int* sizes, int type )
525 {
526     type = CV_MAT_TYPE( type );
527     int pix_size1 = CV_ELEM_SIZE1(type);
528     int pix_size = pix_size1*CV_MAT_CN(type);
529     int i, size;
530     CvMemStorage* storage;
531
532     if( pix_size == 0 )
533         CV_Error( CV_StsUnsupportedFormat, "invalid array data type" );
534
535     if( dims <= 0 || dims > CV_MAX_DIM_HEAP )
536         CV_Error( CV_StsOutOfRange, "bad number of dimensions" );
537
538     if( !sizes )
539         CV_Error( CV_StsNullPtr, "NULL <sizes> pointer" );
540
541     for( i = 0; i < dims; i++ )
542     {
543         if( sizes[i] <= 0 )
544             CV_Error( CV_StsBadSize, "one of dimesion sizes is non-positive" );
545     }
546
547     CvSparseMat* arr = (CvSparseMat*)cvAlloc(sizeof(*arr)+MAX(0,dims-CV_MAX_DIM)*sizeof(arr->size[0]));
548
549     arr->type = CV_SPARSE_MAT_MAGIC_VAL | type;
550     arr->dims = dims;
551     arr->refcount = 0;
552     arr->hdr_refcount = 1;
553     memcpy( arr->size, sizes, dims*sizeof(sizes[0]));
554
555     arr->valoffset = (int)cvAlign(sizeof(CvSparseNode), pix_size1);
556     arr->idxoffset = (int)cvAlign(arr->valoffset + pix_size, sizeof(int));
557     size = (int)cvAlign(arr->idxoffset + dims*sizeof(int), sizeof(CvSetElem));
558
559     storage = cvCreateMemStorage( CV_SPARSE_MAT_BLOCK );
560     arr->heap = cvCreateSet( 0, sizeof(CvSet), size, storage );
561
562     arr->hashsize = CV_SPARSE_HASH_SIZE0;
563     size = arr->hashsize*sizeof(arr->hashtable[0]);
564     
565     arr->hashtable = (void**)cvAlloc( size );
566     memset( arr->hashtable, 0, size );
567
568     return arr;
569 }
570
571
572 // Creates CvMatND and underlying data
573 CV_IMPL void
574 cvReleaseSparseMat( CvSparseMat** array )
575 {
576     if( !array )
577         CV_Error( CV_HeaderIsNull, "" );
578
579     if( *array )
580     {
581         CvSparseMat* arr = *array;
582         
583         if( !CV_IS_SPARSE_MAT_HDR(arr) )
584             CV_Error( CV_StsBadFlag, "" );
585
586         *array = 0;
587
588         CvMemStorage* storage = arr->heap->storage;
589         cvReleaseMemStorage( &storage );
590         cvFree( &arr->hashtable );
591         cvFree( &arr );
592     }
593 }
594
595
596 // Creates CvMatND and underlying data
597 CV_IMPL CvSparseMat*
598 cvCloneSparseMat( const CvSparseMat* src )
599 {
600     if( !CV_IS_SPARSE_MAT_HDR(src) )
601         CV_Error( CV_StsBadArg, "Invalid sparse array header" );
602
603     CvSparseMat* dst = cvCreateSparseMat( src->dims, src->size, src->type );
604     cvCopy( src, dst ); 
605     return dst;
606 }
607
608
609 CvSparseNode*
610 cvInitSparseMatIterator( const CvSparseMat* mat, CvSparseMatIterator* iterator )
611 {
612     CvSparseNode* node = 0;
613     int idx;
614
615     if( !CV_IS_SPARSE_MAT( mat ))
616         CV_Error( CV_StsBadArg, "Invalid sparse matrix header" );
617
618     if( !iterator )
619         CV_Error( CV_StsNullPtr, "NULL iterator pointer" );
620
621     iterator->mat = (CvSparseMat*)mat;
622     iterator->node = 0;
623
624     for( idx = 0; idx < mat->hashsize; idx++ )
625         if( mat->hashtable[idx] )
626         {
627             node = iterator->node = (CvSparseNode*)mat->hashtable[idx];
628             break;
629         }
630
631     iterator->curidx = idx;
632     return node;
633 }
634
635 #define ICV_SPARSE_MAT_HASH_MULTIPLIER  cv::SparseMat::HASH_SCALE
636
637 static uchar*
638 icvGetNodePtr( CvSparseMat* mat, const int* idx, int* _type,
639                int create_node, unsigned* precalc_hashval )
640 {
641     uchar* ptr = 0;
642     int i, tabidx;
643     unsigned hashval = 0;
644     CvSparseNode *node;
645     assert( CV_IS_SPARSE_MAT( mat ));
646
647     if( !precalc_hashval )
648     {
649         for( i = 0; i < mat->dims; i++ )
650         {
651             int t = idx[i];
652             if( (unsigned)t >= (unsigned)mat->size[i] )
653                 CV_Error( CV_StsOutOfRange, "One of indices is out of range" );
654             hashval = hashval*ICV_SPARSE_MAT_HASH_MULTIPLIER + t;
655         }
656     }
657     else
658     {
659         hashval = *precalc_hashval;
660     }
661
662     tabidx = hashval & (mat->hashsize - 1);
663     hashval &= INT_MAX;
664
665     if( create_node >= -1 )
666     {
667         for( node = (CvSparseNode*)mat->hashtable[tabidx];
668              node != 0; node = node->next )
669         {
670             if( node->hashval == hashval )
671             {
672                 int* nodeidx = CV_NODE_IDX(mat,node);
673                 for( i = 0; i < mat->dims; i++ )
674                     if( idx[i] != nodeidx[i] )
675                         break;
676                 if( i == mat->dims )
677                 {
678                     ptr = (uchar*)CV_NODE_VAL(mat,node);
679                     break;
680                 }
681             }
682         }
683     }
684
685     if( !ptr && create_node )
686     {
687         if( mat->heap->active_count >= mat->hashsize*CV_SPARSE_HASH_RATIO )
688         {
689             void** newtable;
690             int newsize = MAX( mat->hashsize*2, CV_SPARSE_HASH_SIZE0);
691             int newrawsize = newsize*sizeof(newtable[0]);
692             
693             CvSparseMatIterator iterator;
694             assert( (newsize & (newsize - 1)) == 0 );
695
696             // resize hash table
697             newtable = (void**)cvAlloc( newrawsize );
698             memset( newtable, 0, newrawsize );
699
700             node = cvInitSparseMatIterator( mat, &iterator );
701             while( node )
702             {
703                 CvSparseNode* next = cvGetNextSparseNode( &iterator );
704                 int newidx = node->hashval & (newsize - 1);
705                 node->next = (CvSparseNode*)newtable[newidx];
706                 newtable[newidx] = node;
707                 node = next;
708             }
709
710             cvFree( &mat->hashtable );
711             mat->hashtable = newtable;
712             mat->hashsize = newsize;
713             tabidx = hashval & (newsize - 1);
714         }
715
716         node = (CvSparseNode*)cvSetNew( mat->heap );
717         node->hashval = hashval;
718         node->next = (CvSparseNode*)mat->hashtable[tabidx];
719         mat->hashtable[tabidx] = node;
720         CV_MEMCPY_INT( CV_NODE_IDX(mat,node), idx, mat->dims );
721         ptr = (uchar*)CV_NODE_VAL(mat,node);
722         if( create_node > 0 )
723             CV_ZERO_CHAR( ptr, CV_ELEM_SIZE(mat->type));
724     }
725
726     if( _type )
727         *_type = CV_MAT_TYPE(mat->type);
728
729     return ptr;
730 }
731
732
733 static void
734 icvDeleteNode( CvSparseMat* mat, const int* idx, unsigned* precalc_hashval )
735 {
736     int i, tabidx;
737     unsigned hashval = 0;
738     CvSparseNode *node, *prev = 0;
739     assert( CV_IS_SPARSE_MAT( mat ));
740
741     if( !precalc_hashval )
742     {
743         for( i = 0; i < mat->dims; i++ )
744         {
745             int t = idx[i];
746             if( (unsigned)t >= (unsigned)mat->size[i] )
747                 CV_Error( CV_StsOutOfRange, "One of indices is out of range" );
748             hashval = hashval*ICV_SPARSE_MAT_HASH_MULTIPLIER + t;
749         }
750     }
751     else
752     {
753         hashval = *precalc_hashval;
754     }
755
756     tabidx = hashval & (mat->hashsize - 1);
757     hashval &= INT_MAX;
758
759     for( node = (CvSparseNode*)mat->hashtable[tabidx];
760          node != 0; prev = node, node = node->next )
761     {
762         if( node->hashval == hashval )
763         {
764             int* nodeidx = CV_NODE_IDX(mat,node);
765             for( i = 0; i < mat->dims; i++ )
766                 if( idx[i] != nodeidx[i] )
767                     break;
768             if( i == mat->dims )
769                 break;
770         }
771     }
772
773     if( node )
774     {
775         if( prev )
776             prev->next = node->next;
777         else
778             mat->hashtable[tabidx] = node->next;
779         cvSetRemoveByPtr( mat->heap, node );
780     }
781 }
782
783
784 /****************************************************************************************\
785 *                          Common for multiple array types operations                    *
786 \****************************************************************************************/
787
788 // Allocates underlying array data
789 CV_IMPL void
790 cvCreateData( CvArr* arr )
791 {
792     if( CV_IS_MAT_HDR( arr ))
793     {
794         size_t step, total_size;
795         CvMat* mat = (CvMat*)arr;
796         step = mat->step;
797
798         if( mat->data.ptr != 0 )
799             CV_Error( CV_StsError, "Data is already allocated" );
800
801         if( step == 0 )
802             step = CV_ELEM_SIZE(mat->type)*mat->cols;
803
804         total_size = step*mat->rows + sizeof(int) + CV_MALLOC_ALIGN;
805         mat->refcount = (int*)cvAlloc( (size_t)total_size );
806         mat->data.ptr = (uchar*)cvAlignPtr( mat->refcount + 1, CV_MALLOC_ALIGN );
807         *mat->refcount = 1;
808     }
809     else if( CV_IS_IMAGE_HDR(arr))
810     {
811         IplImage* img = (IplImage*)arr;
812
813         if( img->imageData != 0 )
814             CV_Error( CV_StsError, "Data is already allocated" );
815
816         if( !CvIPL.allocateData )
817         {
818             img->imageData = img->imageDataOrigin = 
819                         (char*)cvAlloc( (size_t)img->imageSize );
820         }
821         else
822         {
823             int depth = img->depth;
824             int width = img->width;
825
826             if( img->depth == IPL_DEPTH_32F || img->nChannels == 64 )
827             {
828                 img->width *= img->depth == IPL_DEPTH_32F ? sizeof(float) : sizeof(double);
829                 img->depth = IPL_DEPTH_8U;
830             }
831
832             CvIPL.allocateData( img, 0, 0 );
833
834             img->width = width;
835             img->depth = depth;
836         }
837     }
838     else if( CV_IS_MATND_HDR( arr ))
839     {
840         CvMatND* mat = (CvMatND*)arr;
841         int i;
842         size_t total_size = CV_ELEM_SIZE(mat->type);
843
844         if( mat->data.ptr != 0 )
845             CV_Error( CV_StsError, "Data is already allocated" );
846
847         if( CV_IS_MAT_CONT( mat->type ))
848         {
849             total_size = (size_t)mat->dim[0].size*(mat->dim[0].step != 0 ?
850                          mat->dim[0].step : total_size);
851         }
852         else
853         {
854             for( i = mat->dims - 1; i >= 0; i-- )
855             {
856                 size_t size = (size_t)mat->dim[i].step*mat->dim[i].size;
857
858                 if( total_size < size )
859                     total_size = size;
860             }
861         }
862         
863         mat->refcount = (int*)cvAlloc( total_size +
864                                         sizeof(int) + CV_MALLOC_ALIGN );
865         mat->data.ptr = (uchar*)cvAlignPtr( mat->refcount + 1, CV_MALLOC_ALIGN );
866         *mat->refcount = 1;
867     }
868     else
869         CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" );
870 }
871
872
873 // Assigns external data to array
874 CV_IMPL void
875 cvSetData( CvArr* arr, void* data, int step )
876 {
877     int pix_size, min_step;
878
879     if( CV_IS_MAT_HDR(arr) || CV_IS_MATND_HDR(arr) )
880         cvReleaseData( arr );
881
882     if( CV_IS_MAT_HDR( arr ))
883     {
884         CvMat* mat = (CvMat*)arr;
885     
886         int type = CV_MAT_TYPE(mat->type);
887         pix_size = CV_ELEM_SIZE(type);
888         min_step = mat->cols*pix_size;
889
890         if( step != CV_AUTOSTEP && step != 0 )
891         {
892             if( step < min_step && data != 0 )
893                 CV_Error( CV_BadStep, "" );
894             mat->step = step;
895         }
896         else
897             mat->step = min_step;
898
899         mat->data.ptr = (uchar*)data;
900         mat->type = CV_MAT_MAGIC_VAL | type |
901                     (mat->rows == 1 || mat->step == min_step ? CV_MAT_CONT_FLAG : 0);
902         icvCheckHuge( mat );
903     }
904     else if( CV_IS_IMAGE_HDR( arr ))
905     {
906         IplImage* img = (IplImage*)arr;
907     
908         pix_size = ((img->depth & 255) >> 3)*img->nChannels;
909         min_step = img->width*pix_size;
910
911         if( step != CV_AUTOSTEP && img->height > 1 )
912         {
913             if( step < min_step && data != 0 )
914                 CV_Error( CV_BadStep, "" );
915             img->widthStep = step;
916         }
917         else
918         {
919             img->widthStep = min_step;
920         }
921
922         img->imageSize = img->widthStep * img->height;
923         img->imageData = img->imageDataOrigin = (char*)data;
924
925         if( (((int)(size_t)data | step) & 7) == 0 &&
926             cvAlign(img->width * pix_size, 8) == step )
927             img->align = 8;
928         else
929             img->align = 4;
930     }
931     else if( CV_IS_MATND_HDR( arr ))
932     {
933         CvMatND* mat = (CvMatND*)arr;
934         int i;
935         int64 cur_step;
936     
937         if( step != CV_AUTOSTEP )
938             CV_Error( CV_BadStep,
939             "For multidimensional array only CV_AUTOSTEP is allowed here" );
940
941         mat->data.ptr = (uchar*)data;
942         cur_step = CV_ELEM_SIZE(mat->type);
943
944         for( i = mat->dims - 1; i >= 0; i-- )
945         {
946             if( cur_step > INT_MAX )
947                 CV_Error( CV_StsOutOfRange, "The array is too big" );
948             mat->dim[i].step = (int)cur_step;
949             cur_step *= mat->dim[i].size;
950         }
951     }
952     else
953         CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" );
954 }
955
956
957 // Deallocates array's data
958 CV_IMPL void
959 cvReleaseData( CvArr* arr )
960 {
961     if( CV_IS_MAT_HDR( arr ) || CV_IS_MATND_HDR( arr ))
962     {
963         CvMat* mat = (CvMat*)arr;
964         cvDecRefData( mat );
965     }
966     else if( CV_IS_IMAGE_HDR( arr ))
967     {
968         IplImage* img = (IplImage*)arr;
969
970         if( !CvIPL.deallocate )
971         {
972             char* ptr = img->imageDataOrigin;
973             img->imageData = img->imageDataOrigin = 0;
974             cvFree( &ptr );
975         }
976         else
977         {
978             CvIPL.deallocate( img, IPL_IMAGE_DATA );
979         }
980     }
981     else
982         CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" );
983 }
984
985
986 // Retrieves essential information about image ROI or CvMat data
987 CV_IMPL void
988 cvGetRawData( const CvArr* arr, uchar** data, int* step, CvSize* roi_size )
989 {
990     if( CV_IS_MAT( arr ))
991     {
992         CvMat *mat = (CvMat*)arr;
993
994         if( step )
995             *step = mat->step;
996
997         if( data )
998             *data = mat->data.ptr;
999
1000         if( roi_size )
1001             *roi_size = cvGetMatSize( mat );
1002     }
1003     else if( CV_IS_IMAGE( arr ))
1004     {
1005         IplImage* img = (IplImage*)arr;
1006
1007         if( step )
1008             *step = img->widthStep;
1009
1010         if( data )
1011             *data = cvPtr2D( img, 0, 0 );
1012
1013         if( roi_size )
1014         {
1015             if( img->roi )
1016             {
1017                 *roi_size = cvSize( img->roi->width, img->roi->height );
1018             }
1019             else
1020             {
1021                 *roi_size = cvSize( img->width, img->height );
1022             }
1023         }
1024     }
1025     else if( CV_IS_MATND( arr ))
1026     {
1027         CvMatND* mat = (CvMatND*)arr;
1028
1029         if( !CV_IS_MAT_CONT( mat->type ))
1030             CV_Error( CV_StsBadArg, "Only continuous nD arrays are supported here" );
1031
1032         if( data )
1033             *data = mat->data.ptr;
1034
1035         if( roi_size || step )
1036         {
1037             int i, size1 = mat->dim[0].size, size2 = 1;
1038
1039             if( mat->dims > 2 )
1040                 for( i = 1; i < mat->dims; i++ )
1041                     size1 *= mat->dim[i].size;
1042             else
1043                 size2 = mat->dim[1].size;
1044
1045             if( roi_size )
1046             {
1047                 roi_size->width = size2;
1048                 roi_size->height = size1;
1049             }
1050
1051             if( step )
1052                 *step = mat->dim[0].step;
1053         }
1054     }
1055     else
1056         CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" );
1057 }
1058
1059
1060 CV_IMPL int
1061 cvGetElemType( const CvArr* arr )
1062 {
1063     int type = -1;
1064     if( CV_IS_MAT_HDR(arr) || CV_IS_MATND_HDR(arr) || CV_IS_SPARSE_MAT_HDR(arr))
1065         type = CV_MAT_TYPE( ((CvMat*)arr)->type );
1066     else if( CV_IS_IMAGE(arr))
1067     {
1068         IplImage* img = (IplImage*)arr;
1069         type = CV_MAKETYPE( IplToCvDepth(img->depth), img->nChannels );
1070     }
1071     else
1072         CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" );
1073
1074     return type;
1075 }
1076
1077
1078 // Returns a number of array dimensions
1079 CV_IMPL int
1080 cvGetDims( const CvArr* arr, int* sizes )
1081 {
1082     int dims = -1;
1083     if( CV_IS_MAT_HDR( arr ))
1084     {
1085         CvMat* mat = (CvMat*)arr;
1086         
1087         dims = 2;
1088         if( sizes )
1089         {
1090             sizes[0] = mat->rows;
1091             sizes[1] = mat->cols;
1092         }
1093     }
1094     else if( CV_IS_IMAGE( arr ))
1095     {
1096         IplImage* img = (IplImage*)arr;
1097         dims = 2;
1098
1099         if( sizes )
1100         {
1101             sizes[0] = img->height;
1102             sizes[1] = img->width;
1103         }
1104     }
1105     else if( CV_IS_MATND_HDR( arr ))
1106     {
1107         CvMatND* mat = (CvMatND*)arr;
1108         dims = mat->dims;
1109         
1110         if( sizes )
1111         {
1112             int i;
1113             for( i = 0; i < dims; i++ )
1114                 sizes[i] = mat->dim[i].size;
1115         }
1116     }
1117     else if( CV_IS_SPARSE_MAT_HDR( arr ))
1118     {
1119         CvSparseMat* mat = (CvSparseMat*)arr;
1120         dims = mat->dims;
1121         
1122         if( sizes )
1123             memcpy( sizes, mat->size, dims*sizeof(sizes[0]));
1124     }
1125     else
1126         CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" );
1127
1128     return dims;
1129 }
1130
1131
1132 // Returns the size of particular array dimension
1133 CV_IMPL int
1134 cvGetDimSize( const CvArr* arr, int index )
1135 {
1136     int size = -1;
1137
1138     if( CV_IS_MAT( arr ))
1139     {
1140         CvMat *mat = (CvMat*)arr;
1141
1142         switch( index )
1143         {
1144         case 0:
1145             size = mat->rows;
1146             break;
1147         case 1:
1148             size = mat->cols;
1149             break;
1150         default:
1151             CV_Error( CV_StsOutOfRange, "bad dimension index" );
1152         }
1153     }
1154     else if( CV_IS_IMAGE( arr ))
1155     {
1156         IplImage* img = (IplImage*)arr;
1157
1158         switch( index )
1159         {
1160         case 0:
1161             size = !img->roi ? img->height : img->roi->height;
1162             break;
1163         case 1:
1164             size = !img->roi ? img->width : img->roi->width;
1165             break;
1166         default:
1167             CV_Error( CV_StsOutOfRange, "bad dimension index" );
1168         }
1169     }
1170     else if( CV_IS_MATND_HDR( arr ))
1171     {
1172         CvMatND* mat = (CvMatND*)arr;
1173         
1174         if( (unsigned)index >= (unsigned)mat->dims )
1175             CV_Error( CV_StsOutOfRange, "bad dimension index" );
1176
1177         size = mat->dim[index].size;
1178     }
1179     else if( CV_IS_SPARSE_MAT_HDR( arr ))
1180     {
1181         CvSparseMat* mat = (CvSparseMat*)arr;
1182         
1183         if( (unsigned)index >= (unsigned)mat->dims )
1184             CV_Error( CV_StsOutOfRange, "bad dimension index" );
1185
1186         size = mat->size[index];
1187     }
1188     else
1189         CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" );
1190
1191     return size;
1192 }
1193
1194
1195 // Returns the size of CvMat or IplImage
1196 CV_IMPL CvSize
1197 cvGetSize( const CvArr* arr )
1198 {
1199     CvSize size = { 0, 0 };
1200
1201     if( CV_IS_MAT_HDR( arr ))
1202     {
1203         CvMat *mat = (CvMat*)arr;
1204
1205         size.width = mat->cols;
1206         size.height = mat->rows;
1207     }
1208     else if( CV_IS_IMAGE_HDR( arr ))
1209     {
1210         IplImage* img = (IplImage*)arr;
1211
1212         if( img->roi )
1213         {
1214             size.width = img->roi->width;
1215             size.height = img->roi->height;
1216         }
1217         else
1218         {
1219             size.width = img->width;
1220             size.height = img->height;
1221         }
1222     }
1223     else
1224         CV_Error( CV_StsBadArg, "Array should be CvMat or IplImage" );
1225
1226     return size;
1227 }
1228
1229
1230 // Selects sub-array (no data is copied)
1231 CV_IMPL  CvMat*
1232 cvGetSubRect( const CvArr* arr, CvMat* submat, CvRect rect )
1233 {
1234     CvMat* res = 0;
1235     CvMat stub, *mat = (CvMat*)arr;
1236
1237     if( !CV_IS_MAT( mat ))
1238         mat = cvGetMat( mat, &stub );
1239
1240     if( !submat )
1241         CV_Error( CV_StsNullPtr, "" );
1242
1243     if( (rect.x|rect.y|rect.width|rect.height) < 0 )
1244         CV_Error( CV_StsBadSize, "" );
1245
1246     if( rect.x + rect.width > mat->cols ||
1247         rect.y + rect.height > mat->rows )
1248         CV_Error( CV_StsBadSize, "" );
1249
1250     {
1251     /*
1252     int* refcount = mat->refcount;
1253
1254     if( refcount )
1255         ++*refcount;
1256
1257     cvDecRefData( submat );
1258     */
1259     submat->data.ptr = mat->data.ptr + (size_t)rect.y*mat->step +
1260                        rect.x*CV_ELEM_SIZE(mat->type);
1261     submat->step = mat->step;
1262     submat->type = (mat->type & (rect.width < mat->cols ? ~CV_MAT_CONT_FLAG : -1)) |
1263                    (rect.height <= 1 ? CV_MAT_CONT_FLAG : 0);
1264     submat->rows = rect.height;
1265     submat->cols = rect.width;
1266     submat->refcount = 0;
1267     res = submat;
1268     }
1269
1270     return res;
1271 }
1272
1273
1274 // Selects array's row span.
1275 CV_IMPL  CvMat*
1276 cvGetRows( const CvArr* arr, CvMat* submat,
1277            int start_row, int end_row, int delta_row )
1278 {
1279     CvMat* res = 0;
1280     CvMat stub, *mat = (CvMat*)arr;
1281
1282     if( !CV_IS_MAT( mat ))
1283         mat = cvGetMat( mat, &stub );
1284
1285     if( !submat )
1286         CV_Error( CV_StsNullPtr, "" );
1287
1288     if( (unsigned)start_row >= (unsigned)mat->rows ||
1289         (unsigned)end_row > (unsigned)mat->rows || delta_row <= 0 )
1290         CV_Error( CV_StsOutOfRange, "" );
1291
1292     {
1293     /*
1294     int* refcount = mat->refcount;
1295
1296     if( refcount )
1297         ++*refcount;
1298
1299     cvDecRefData( submat );
1300     */
1301     if( delta_row == 1 )
1302     {
1303         submat->rows = end_row - start_row;
1304         submat->step = mat->step;
1305     }
1306     else
1307     {
1308         submat->rows = (end_row - start_row + delta_row - 1)/delta_row;
1309         submat->step = mat->step * delta_row;
1310     }
1311
1312     submat->cols = mat->cols;
1313     submat->step &= submat->rows > 1 ? -1 : 0;
1314     submat->data.ptr = mat->data.ptr + (size_t)start_row*mat->step;
1315     submat->type = (mat->type | (submat->rows == 1 ? CV_MAT_CONT_FLAG : 0)) &
1316                    (delta_row != 1 && submat->rows > 1 ? ~CV_MAT_CONT_FLAG : -1);
1317     submat->refcount = 0;
1318     submat->hdr_refcount = 0;
1319     res = submat;
1320     }
1321
1322     return res;
1323 }
1324
1325
1326 // Selects array's column span.
1327 CV_IMPL  CvMat*
1328 cvGetCols( const CvArr* arr, CvMat* submat, int start_col, int end_col )
1329 {
1330     CvMat* res = 0;
1331     CvMat stub, *mat = (CvMat*)arr;
1332     int cols;
1333
1334     if( !CV_IS_MAT( mat ))
1335         mat = cvGetMat( mat, &stub );
1336
1337     if( !submat )
1338         CV_Error( CV_StsNullPtr, "" );
1339     
1340     cols = mat->cols;
1341     if( (unsigned)start_col >= (unsigned)cols ||
1342         (unsigned)end_col > (unsigned)cols )
1343         CV_Error( CV_StsOutOfRange, "" );
1344
1345     {
1346     /*
1347     int* refcount = mat->refcount;
1348
1349     if( refcount )
1350         ++*refcount;
1351
1352     cvDecRefData( submat );
1353     */
1354     submat->rows = mat->rows;
1355     submat->cols = end_col - start_col;
1356     submat->step = mat->step;
1357     submat->data.ptr = mat->data.ptr + (size_t)start_col*CV_ELEM_SIZE(mat->type);
1358     submat->type = mat->type & (submat->rows > 1 && submat->cols < cols ? ~CV_MAT_CONT_FLAG : -1);
1359     submat->refcount = 0;
1360     submat->hdr_refcount = 0;
1361     res = submat;
1362     }
1363
1364     return res;
1365 }
1366
1367
1368 // Selects array diagonal
1369 CV_IMPL  CvMat*
1370 cvGetDiag( const CvArr* arr, CvMat* submat, int diag )
1371 {
1372     CvMat* res = 0;
1373     CvMat stub, *mat = (CvMat*)arr;
1374     int len, pix_size; 
1375
1376     if( !CV_IS_MAT( mat ))
1377         mat = cvGetMat( mat, &stub );
1378
1379     if( !submat )
1380         CV_Error( CV_StsNullPtr, "" );
1381
1382     pix_size = CV_ELEM_SIZE(mat->type);
1383
1384     /*{
1385     int* refcount = mat->refcount;
1386
1387     if( refcount )
1388         ++*refcount;
1389
1390     cvDecRefData( submat );
1391     }*/
1392
1393     if( diag >= 0 )
1394     {
1395         len = mat->cols - diag;
1396         
1397         if( len <= 0 )
1398             CV_Error( CV_StsOutOfRange, "" );
1399
1400         len = CV_IMIN( len, mat->rows );
1401         submat->data.ptr = mat->data.ptr + diag*pix_size;
1402     }
1403     else
1404     {
1405         len = mat->rows + diag;
1406         
1407         if( len <= 0 )
1408             CV_Error( CV_StsOutOfRange, "" );
1409
1410         len = CV_IMIN( len, mat->cols );
1411         submat->data.ptr = mat->data.ptr - diag*mat->step;
1412     }
1413
1414     submat->rows = len;
1415     submat->cols = 1;
1416     submat->step = mat->step + (submat->rows > 1 ? pix_size : 0);
1417     submat->type = mat->type;
1418     if( submat->rows > 1 )
1419         submat->type &= ~CV_MAT_CONT_FLAG;
1420     else
1421         submat->type |= CV_MAT_CONT_FLAG;
1422     submat->refcount = 0;
1423     submat->hdr_refcount = 0;
1424     res = submat;
1425
1426     return res;
1427 }
1428
1429
1430 /****************************************************************************************\
1431 *                      Operations on CvScalar and accessing array elements               *
1432 \****************************************************************************************/
1433
1434 // Converts CvScalar to specified type
1435 CV_IMPL void
1436 cvScalarToRawData( const CvScalar* scalar, void* data, int type, int extend_to_12 )
1437 {
1438     type = CV_MAT_TYPE(type);
1439     int cn = CV_MAT_CN( type );
1440     int depth = type & CV_MAT_DEPTH_MASK;
1441
1442     assert( scalar && data );
1443     if( (unsigned)(cn - 1) >= 4 )
1444         CV_Error( CV_StsOutOfRange, "The number of channels must be 1, 2, 3 or 4" );
1445
1446     switch( depth )
1447     {
1448     case CV_8UC1:
1449         while( cn-- )
1450         {
1451             int t = cvRound( scalar->val[cn] );
1452             ((uchar*)data)[cn] = CV_CAST_8U(t);
1453         }
1454         break;
1455     case CV_8SC1:
1456         while( cn-- )
1457         {
1458             int t = cvRound( scalar->val[cn] );
1459             ((char*)data)[cn] = CV_CAST_8S(t);
1460         }
1461         break;
1462     case CV_16UC1:
1463         while( cn-- )
1464         {
1465             int t = cvRound( scalar->val[cn] );
1466             ((ushort*)data)[cn] = CV_CAST_16U(t);
1467         }
1468         break;
1469     case CV_16SC1:
1470         while( cn-- )
1471         {
1472             int t = cvRound( scalar->val[cn] );
1473             ((short*)data)[cn] = CV_CAST_16S(t);
1474         }
1475         break;
1476     case CV_32SC1:
1477         while( cn-- )
1478             ((int*)data)[cn] = cvRound( scalar->val[cn] );
1479         break;
1480     case CV_32FC1:
1481         while( cn-- )
1482             ((float*)data)[cn] = (float)(scalar->val[cn]);
1483         break;
1484     case CV_64FC1:
1485         while( cn-- )
1486             ((double*)data)[cn] = (double)(scalar->val[cn]);
1487         break;
1488     default:
1489         assert(0);
1490         CV_Error( CV_BadDepth, "" );
1491     }
1492
1493     if( extend_to_12 )
1494     {
1495         int pix_size = CV_ELEM_SIZE(type);
1496         int offset = CV_ELEM_SIZE1(depth)*12;
1497
1498         do
1499         {
1500             offset -= pix_size;
1501             CV_MEMCPY_AUTO( (char*)data + offset, data, pix_size );
1502         }
1503         while( offset > pix_size );
1504     }
1505 }
1506
1507
1508 // Converts data of specified type to CvScalar
1509 CV_IMPL void
1510 cvRawDataToScalar( const void* data, int flags, CvScalar* scalar )
1511 {
1512     int cn = CV_MAT_CN( flags );
1513
1514     assert( scalar && data );
1515     
1516     if( (unsigned)(cn - 1) >= 4 )
1517         CV_Error( CV_StsOutOfRange, "The number of channels must be 1, 2, 3 or 4" );
1518
1519     memset( scalar->val, 0, sizeof(scalar->val));
1520
1521     switch( CV_MAT_DEPTH( flags ))
1522     {
1523     case CV_8U:
1524         while( cn-- )
1525             scalar->val[cn] = CV_8TO32F(((uchar*)data)[cn]);
1526         break;
1527     case CV_8S:
1528         while( cn-- )
1529             scalar->val[cn] = CV_8TO32F(((char*)data)[cn]);
1530         break;
1531     case CV_16U:
1532         while( cn-- )
1533             scalar->val[cn] = ((ushort*)data)[cn];
1534         break;
1535     case CV_16S:
1536         while( cn-- )
1537             scalar->val[cn] = ((short*)data)[cn];
1538         break;
1539     case CV_32S:
1540         while( cn-- )
1541             scalar->val[cn] = ((int*)data)[cn];
1542         break;
1543     case CV_32F:
1544         while( cn-- )
1545             scalar->val[cn] = ((float*)data)[cn];
1546         break;
1547     case CV_64F:
1548         while( cn-- )
1549             scalar->val[cn] = ((double*)data)[cn];
1550         break;
1551     default:
1552         assert(0);
1553         CV_Error( CV_BadDepth, "" );
1554     }
1555 }
1556
1557
1558 static double icvGetReal( const void* data, int type )
1559 {
1560     switch( type )
1561     {
1562     case CV_8U:
1563         return *(uchar*)data;
1564     case CV_8S:
1565         return *(char*)data;
1566     case CV_16U:
1567         return *(ushort*)data;
1568     case CV_16S:
1569         return *(short*)data;
1570     case CV_32S:
1571         return *(int*)data;
1572     case CV_32F:
1573         return *(float*)data;
1574     case CV_64F:
1575         return *(double*)data;
1576     }
1577
1578     return 0;
1579 }
1580
1581
1582 static void icvSetReal( double value, const void* data, int type )
1583 {
1584     if( type < CV_32F )
1585     {
1586         int ivalue = cvRound(value);
1587         switch( type )
1588         {
1589         case CV_8U:
1590             *(uchar*)data = CV_CAST_8U(ivalue);
1591             break;
1592         case CV_8S:
1593             *(char*)data = CV_CAST_8S(ivalue);
1594             break;
1595         case CV_16U:
1596             *(ushort*)data = CV_CAST_16U(ivalue);
1597             break;
1598         case CV_16S:
1599             *(short*)data = CV_CAST_16S(ivalue);
1600             break;
1601         case CV_32S:
1602             *(int*)data = CV_CAST_32S(ivalue);
1603             break;
1604         }
1605     }
1606     else
1607     {
1608         switch( type )
1609         {
1610         case CV_32F:
1611             *(float*)data = (float)value;
1612             break;
1613         case CV_64F:
1614             *(double*)data = value;
1615             break;
1616         }
1617     }
1618 }
1619
1620
1621 // Returns pointer to specified element of array (linear index is used)
1622 CV_IMPL  uchar*
1623 cvPtr1D( const CvArr* arr, int idx, int* _type )
1624 {
1625     uchar* ptr = 0;
1626     if( CV_IS_MAT( arr ))
1627     {
1628         CvMat* mat = (CvMat*)arr;
1629
1630         int type = CV_MAT_TYPE(mat->type);
1631         int pix_size = CV_ELEM_SIZE(type);
1632
1633         if( _type )
1634             *_type = type;
1635         
1636         // the first part is mul-free sufficient check
1637         // that the index is within the matrix
1638         if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) &&
1639             (unsigned)idx >= (unsigned)(mat->rows*mat->cols))
1640             CV_Error( CV_StsOutOfRange, "index is out of range" );
1641
1642         if( CV_IS_MAT_CONT(mat->type))
1643         {
1644             ptr = mat->data.ptr + (size_t)idx*pix_size;
1645         }
1646         else
1647         {
1648             int row, col;
1649             if( mat->cols == 1 )
1650                 row = idx, col = 0;
1651             else
1652                 row = idx/mat->cols, col = idx - row*mat->cols;
1653             ptr = mat->data.ptr + (size_t)row*mat->step + col*pix_size;
1654         }
1655     }
1656     else if( CV_IS_IMAGE_HDR( arr ))
1657     {
1658         IplImage* img = (IplImage*)arr;
1659         int width = !img->roi ? img->width : img->roi->width;
1660         int y = idx/width, x = idx - y*width;
1661
1662         ptr = cvPtr2D( arr, y, x, _type );
1663     }
1664     else if( CV_IS_MATND( arr ))
1665     {
1666         CvMatND* mat = (CvMatND*)arr;
1667         int j, type = CV_MAT_TYPE(mat->type);
1668         size_t size = mat->dim[0].size;
1669
1670         if( _type )
1671             *_type = type;
1672
1673         for( j = 1; j < mat->dims; j++ )
1674             size *= mat->dim[j].size;
1675
1676         if((unsigned)idx >= (unsigned)size )
1677             CV_Error( CV_StsOutOfRange, "index is out of range" );
1678
1679         if( CV_IS_MAT_CONT(mat->type))
1680         {
1681             int pix_size = CV_ELEM_SIZE(type);
1682             ptr = mat->data.ptr + (size_t)idx*pix_size;
1683         }
1684         else
1685         {
1686             ptr = mat->data.ptr;
1687             for( j = mat->dims - 1; j >= 0; j-- )
1688             {
1689                 int sz = mat->dim[j].size;
1690                 if( sz )
1691                 {
1692                     int t = idx/sz;
1693                     ptr += (idx - t*sz)*mat->dim[j].step;
1694                     idx = t;
1695                 }
1696             }
1697         }
1698     }
1699     else if( CV_IS_SPARSE_MAT( arr ))
1700     {
1701         CvSparseMat* m = (CvSparseMat*)arr;
1702         if( m->dims == 1 )
1703             ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, _type, 1, 0 );
1704         else
1705         {
1706             int i, n = m->dims;
1707             int* _idx = (int*)cvStackAlloc(n*sizeof(_idx[0]));
1708             
1709             for( i = n - 1; i >= 0; i-- )
1710             {
1711                 int t = idx / m->size[i];
1712                 _idx[i] = idx - t*m->size[i];
1713                 idx = t;
1714             }
1715             ptr = icvGetNodePtr( (CvSparseMat*)arr, _idx, _type, 1, 0 );
1716         }
1717     }
1718     else
1719     {
1720         CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" );
1721     }
1722
1723     return ptr;
1724 }
1725
1726
1727 // Returns pointer to specified element of 2d array
1728 CV_IMPL  uchar*
1729 cvPtr2D( const CvArr* arr, int y, int x, int* _type )
1730 {
1731     uchar* ptr = 0;
1732     if( CV_IS_MAT( arr ))
1733     {
1734         CvMat* mat = (CvMat*)arr;
1735         int type;
1736
1737         if( (unsigned)y >= (unsigned)(mat->rows) ||
1738             (unsigned)x >= (unsigned)(mat->cols) )
1739             CV_Error( CV_StsOutOfRange, "index is out of range" );
1740
1741         type = CV_MAT_TYPE(mat->type);
1742         if( _type )
1743             *_type = type;
1744
1745         ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type);
1746     }
1747     else if( CV_IS_IMAGE( arr ))
1748     {
1749         IplImage* img = (IplImage*)arr;
1750         int pix_size = (img->depth & 255) >> 3;
1751         int width, height;
1752         ptr = (uchar*)img->imageData;
1753
1754         if( img->dataOrder == 0 )
1755             pix_size *= img->nChannels;
1756
1757         if( img->roi )
1758         {
1759             width = img->roi->width;
1760             height = img->roi->height;
1761
1762             ptr += img->roi->yOffset*img->widthStep +
1763                    img->roi->xOffset*pix_size;
1764
1765             if( img->dataOrder )
1766             {
1767                 int coi = img->roi->coi;
1768                 if( !coi )
1769                     CV_Error( CV_BadCOI,
1770                         "COI must be non-null in case of planar images" );
1771                 ptr += (coi - 1)*img->imageSize;
1772             }
1773         }
1774         else
1775         {
1776             width = img->width;
1777             height = img->height;
1778         }
1779
1780         if( (unsigned)y >= (unsigned)height ||
1781             (unsigned)x >= (unsigned)width )
1782             CV_Error( CV_StsOutOfRange, "index is out of range" );
1783
1784         ptr += y*img->widthStep + x*pix_size;
1785
1786         if( _type )
1787         {
1788             int type = IplToCvDepth(img->depth);
1789             if( type < 0 || (unsigned)(img->nChannels - 1) > 3 )
1790                 CV_Error( CV_StsUnsupportedFormat, "" );
1791
1792             *_type = CV_MAKETYPE( type, img->nChannels );
1793         }
1794     }
1795     else if( CV_IS_MATND( arr ))
1796     {
1797         CvMatND* mat = (CvMatND*)arr;
1798
1799         if( mat->dims != 2 || 
1800             (unsigned)y >= (unsigned)(mat->dim[0].size) ||
1801             (unsigned)x >= (unsigned)(mat->dim[1].size) )
1802             CV_Error( CV_StsOutOfRange, "index is out of range" );
1803
1804         ptr = mat->data.ptr + (size_t)y*mat->dim[0].step + x*mat->dim[1].step;
1805         if( _type )
1806             *_type = CV_MAT_TYPE(mat->type);
1807     }
1808     else if( CV_IS_SPARSE_MAT( arr ))
1809     {
1810         int idx[] = { y, x };
1811         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, _type, 1, 0 );
1812     }
1813     else
1814     {
1815         CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" );
1816     }
1817
1818     return ptr;
1819 }
1820
1821
1822 // Returns pointer to specified element of 3d array
1823 CV_IMPL  uchar*
1824 cvPtr3D( const CvArr* arr, int z, int y, int x, int* _type )
1825 {
1826     uchar* ptr = 0;
1827     if( CV_IS_MATND( arr ))
1828     {
1829         CvMatND* mat = (CvMatND*)arr;
1830
1831         if( mat->dims != 3 || 
1832             (unsigned)z >= (unsigned)(mat->dim[0].size) ||
1833             (unsigned)y >= (unsigned)(mat->dim[1].size) ||
1834             (unsigned)x >= (unsigned)(mat->dim[2].size) )
1835             CV_Error( CV_StsOutOfRange, "index is out of range" );
1836
1837         ptr = mat->data.ptr + (size_t)z*mat->dim[0].step +
1838               (size_t)y*mat->dim[1].step + x*mat->dim[2].step;
1839
1840         if( _type )
1841             *_type = CV_MAT_TYPE(mat->type);
1842     }
1843     else if( CV_IS_SPARSE_MAT( arr ))
1844     {
1845         int idx[] = { z, y, x };
1846         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, _type, 1, 0 );
1847     }
1848     else
1849     {
1850         CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" );
1851     }
1852
1853     return ptr;
1854 }
1855
1856
1857 // Returns pointer to specified element of n-d array
1858 CV_IMPL  uchar*
1859 cvPtrND( const CvArr* arr, const int* idx, int* _type,
1860          int create_node, unsigned* precalc_hashval )
1861 {
1862     uchar* ptr = 0;
1863     if( !idx )
1864         CV_Error( CV_StsNullPtr, "NULL pointer to indices" );
1865
1866     if( CV_IS_SPARSE_MAT( arr ))
1867         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, 
1868                              _type, create_node, precalc_hashval );
1869     else if( CV_IS_MATND( arr ))
1870     {
1871         CvMatND* mat = (CvMatND*)arr;
1872         int i;
1873         ptr = mat->data.ptr;
1874
1875         for( i = 0; i < mat->dims; i++ )
1876         {
1877             if( (unsigned)idx[i] >= (unsigned)(mat->dim[i].size) )
1878                 CV_Error( CV_StsOutOfRange, "index is out of range" );
1879             ptr += (size_t)idx[i]*mat->dim[i].step;
1880         }
1881
1882         if( _type )
1883             *_type = CV_MAT_TYPE(mat->type);
1884     }
1885     else if( CV_IS_MAT_HDR(arr) || CV_IS_IMAGE_HDR(arr) )
1886         ptr = cvPtr2D( arr, idx[0], idx[1], _type );
1887     else
1888         CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" );
1889
1890     return ptr;
1891 }
1892
1893
1894 // Returns specifed element of n-D array given linear index
1895 CV_IMPL  CvScalar
1896 cvGet1D( const CvArr* arr, int idx )
1897 {
1898     CvScalar scalar = {{0,0,0,0}};
1899     int type = 0;
1900     uchar* ptr;
1901     
1902     if( CV_IS_MAT( arr ) && CV_IS_MAT_CONT( ((CvMat*)arr)->type ))
1903     {
1904         CvMat* mat = (CvMat*)arr;
1905
1906         type = CV_MAT_TYPE(mat->type);
1907         int pix_size = CV_ELEM_SIZE(type);
1908
1909         // the first part is mul-free sufficient check
1910         // that the index is within the matrix
1911         if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) &&
1912             (unsigned)idx >= (unsigned)(mat->rows*mat->cols))
1913             CV_Error( CV_StsOutOfRange, "index is out of range" );
1914
1915         ptr = mat->data.ptr + (size_t)idx*pix_size;
1916     }
1917     else if( !CV_IS_SPARSE_MAT( arr ) || ((CvSparseMat*)arr)->dims > 1 )
1918         ptr = cvPtr1D( arr, idx, &type );
1919     else
1920         ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, &type, 0, 0 );
1921
1922     if( ptr )
1923         cvRawDataToScalar( ptr, type, &scalar );
1924
1925     return scalar;
1926 }
1927
1928
1929 // Returns specifed element of 2D array
1930 CV_IMPL  CvScalar
1931 cvGet2D( const CvArr* arr, int y, int x )
1932 {
1933     CvScalar scalar = {{0,0,0,0}};
1934     int type = 0;
1935     uchar* ptr;
1936
1937     if( CV_IS_MAT( arr ))
1938     {
1939         CvMat* mat = (CvMat*)arr;
1940
1941         if( (unsigned)y >= (unsigned)(mat->rows) ||
1942             (unsigned)x >= (unsigned)(mat->cols) )
1943             CV_Error( CV_StsOutOfRange, "index is out of range" );
1944
1945         type = CV_MAT_TYPE(mat->type);
1946         ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type);
1947     }
1948     else if( !CV_IS_SPARSE_MAT( arr ))
1949         ptr = cvPtr2D( arr, y, x, &type );
1950     else
1951     {
1952         int idx[] = { y, x };
1953         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 );
1954     }
1955
1956     if( ptr )
1957         cvRawDataToScalar( ptr, type, &scalar );
1958
1959     return scalar;
1960 }
1961
1962
1963 // Returns specifed element of 3D array
1964 CV_IMPL  CvScalar
1965 cvGet3D( const CvArr* arr, int z, int y, int x )
1966 {
1967     CvScalar scalar = {{0,0,0,0}};
1968     int type = 0;
1969     uchar* ptr;
1970
1971     if( !CV_IS_SPARSE_MAT( arr ))
1972         ptr = cvPtr3D( arr, z, y, x, &type );
1973     else
1974     {
1975         int idx[] = { z, y, x };
1976         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 );
1977     }
1978     
1979     if( ptr )
1980         cvRawDataToScalar( ptr, type, &scalar );
1981     return scalar;
1982 }
1983
1984
1985 // Returns specifed element of nD array
1986 CV_IMPL  CvScalar
1987 cvGetND( const CvArr* arr, const int* idx )
1988 {
1989     CvScalar scalar = {{0,0,0,0}};
1990     int type = 0;
1991     uchar* ptr;
1992
1993     if( !CV_IS_SPARSE_MAT( arr ))
1994         ptr = cvPtrND( arr, idx, &type );
1995     else
1996         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 );
1997
1998     if( ptr )
1999         cvRawDataToScalar( ptr, type, &scalar );
2000
2001     return scalar;
2002 }
2003
2004
2005 // Returns specifed element of n-D array given linear index
2006 CV_IMPL  double
2007 cvGetReal1D( const CvArr* arr, int idx )
2008 {
2009     double value = 0;
2010     int type = 0;
2011     uchar* ptr;
2012
2013     if( CV_IS_MAT( arr ) && CV_IS_MAT_CONT( ((CvMat*)arr)->type ))
2014     {
2015         CvMat* mat = (CvMat*)arr;
2016
2017         type = CV_MAT_TYPE(mat->type);
2018         int pix_size = CV_ELEM_SIZE(type);
2019
2020         // the first part is mul-free sufficient check
2021         // that the index is within the matrix
2022         if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) &&
2023             (unsigned)idx >= (unsigned)(mat->rows*mat->cols))
2024             CV_Error( CV_StsOutOfRange, "index is out of range" );
2025
2026         ptr = mat->data.ptr + (size_t)idx*pix_size;
2027     }
2028     else if( !CV_IS_SPARSE_MAT( arr ) || ((CvSparseMat*)arr)->dims > 1 )
2029         ptr = cvPtr1D( arr, idx, &type );
2030     else
2031         ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, &type, 0, 0 );
2032
2033     if( ptr )
2034     {
2035         if( CV_MAT_CN( type ) > 1 )
2036             CV_Error( CV_BadNumChannels, "cvGetReal* support only single-channel arrays" );
2037
2038         value = icvGetReal( ptr, type );
2039     }
2040     return value;
2041 }
2042
2043
2044 // Returns specifed element of 2D array
2045 CV_IMPL  double
2046 cvGetReal2D( const CvArr* arr, int y, int x )
2047 {
2048     double value = 0;
2049     int type = 0;
2050     uchar* ptr;
2051     
2052     if( CV_IS_MAT( arr ))
2053     {
2054         CvMat* mat = (CvMat*)arr;
2055
2056         if( (unsigned)y >= (unsigned)(mat->rows) ||
2057             (unsigned)x >= (unsigned)(mat->cols) )
2058             CV_Error( CV_StsOutOfRange, "index is out of range" );
2059
2060         type = CV_MAT_TYPE(mat->type);
2061         ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type);
2062     }
2063     else if( !CV_IS_SPARSE_MAT( arr ))
2064         ptr = cvPtr2D( arr, y, x, &type );
2065     else
2066     {
2067         int idx[] = { y, x };
2068         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 );
2069     }
2070
2071     if( ptr )
2072     {
2073         if( CV_MAT_CN( type ) > 1 )
2074             CV_Error( CV_BadNumChannels, "cvGetReal* support only single-channel arrays" );
2075
2076         value = icvGetReal( ptr, type );
2077     }
2078
2079     return value;
2080 }
2081
2082
2083 // Returns specifed element of 3D array
2084 CV_IMPL  double
2085 cvGetReal3D( const CvArr* arr, int z, int y, int x )
2086 {
2087     double value = 0;
2088     int type = 0;
2089     uchar* ptr;
2090
2091     if( !CV_IS_SPARSE_MAT( arr ))
2092         ptr = cvPtr3D( arr, z, y, x, &type );
2093     else
2094     {
2095         int idx[] = { z, y, x };
2096         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 );
2097     }
2098     
2099     if( ptr )
2100     {
2101         if( CV_MAT_CN( type ) > 1 )
2102             CV_Error( CV_BadNumChannels, "cvGetReal* support only single-channel arrays" );
2103
2104         value = icvGetReal( ptr, type );
2105     }
2106
2107     return value;
2108 }
2109
2110
2111 // Returns specifed element of nD array
2112 CV_IMPL  double
2113 cvGetRealND( const CvArr* arr, const int* idx )
2114 {
2115     double value = 0;
2116     int type = 0;
2117     uchar* ptr;
2118     
2119     if( !CV_IS_SPARSE_MAT( arr ))
2120         ptr = cvPtrND( arr, idx, &type );
2121     else
2122         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 );
2123
2124     if( ptr )
2125     {
2126         if( CV_MAT_CN( type ) > 1 )
2127             CV_Error( CV_BadNumChannels, "cvGetReal* support only single-channel arrays" );
2128
2129         value = icvGetReal( ptr, type );
2130     }
2131
2132     return value;
2133 }
2134
2135
2136 // Assigns new value to specifed element of nD array given linear index
2137 CV_IMPL  void
2138 cvSet1D( CvArr* arr, int idx, CvScalar scalar )
2139 {
2140     int type = 0;
2141     uchar* ptr;
2142     
2143     if( CV_IS_MAT( arr ) && CV_IS_MAT_CONT( ((CvMat*)arr)->type ))
2144     {
2145         CvMat* mat = (CvMat*)arr;
2146
2147         type = CV_MAT_TYPE(mat->type);
2148         int pix_size = CV_ELEM_SIZE(type);
2149
2150         // the first part is mul-free sufficient check
2151         // that the index is within the matrix
2152         if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) &&
2153             (unsigned)idx >= (unsigned)(mat->rows*mat->cols))
2154             CV_Error( CV_StsOutOfRange, "index is out of range" );
2155
2156         ptr = mat->data.ptr + (size_t)idx*pix_size;
2157     }
2158     else if( !CV_IS_SPARSE_MAT( arr ) || ((CvSparseMat*)arr)->dims > 1 )
2159         ptr = cvPtr1D( arr, idx, &type );
2160     else
2161         ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, &type, -1, 0 );
2162
2163     cvScalarToRawData( &scalar, ptr, type );
2164 }
2165
2166
2167 // Assigns new value to specifed element of 2D array
2168 CV_IMPL  void
2169 cvSet2D( CvArr* arr, int y, int x, CvScalar scalar )
2170 {
2171     int type = 0;
2172     uchar* ptr;
2173     
2174     if( CV_IS_MAT( arr ))
2175     {
2176         CvMat* mat = (CvMat*)arr;
2177
2178         if( (unsigned)y >= (unsigned)(mat->rows) ||
2179             (unsigned)x >= (unsigned)(mat->cols) )
2180             CV_Error( CV_StsOutOfRange, "index is out of range" );
2181
2182         type = CV_MAT_TYPE(mat->type);
2183         ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type);
2184     }
2185     else if( !CV_IS_SPARSE_MAT( arr ))
2186         ptr = cvPtr2D( arr, y, x, &type );
2187     else
2188     {
2189         int idx[] = { y, x };
2190         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 );
2191     }
2192     cvScalarToRawData( &scalar, ptr, type );
2193 }
2194
2195
2196 // Assigns new value to specifed element of 3D array
2197 CV_IMPL  void
2198 cvSet3D( CvArr* arr, int z, int y, int x, CvScalar scalar )
2199 {
2200     int type = 0;
2201     uchar* ptr;
2202     
2203     if( !CV_IS_SPARSE_MAT( arr ))
2204         ptr = cvPtr3D( arr, z, y, x, &type );
2205     else
2206     {
2207         int idx[] = { z, y, x };
2208         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 );
2209     }
2210     cvScalarToRawData( &scalar, ptr, type );
2211 }
2212
2213
2214 // Assigns new value to specifed element of nD array
2215 CV_IMPL  void
2216 cvSetND( CvArr* arr, const int* idx, CvScalar scalar )
2217 {
2218     int type = 0;
2219     uchar* ptr;
2220     
2221     if( !CV_IS_SPARSE_MAT( arr ))
2222         ptr = cvPtrND( arr, idx, &type );
2223     else
2224         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 );
2225     cvScalarToRawData( &scalar, ptr, type );
2226 }
2227
2228
2229 CV_IMPL  void
2230 cvSetReal1D( CvArr* arr, int idx, double value )
2231 {
2232     int type = 0;
2233     uchar* ptr;
2234     
2235     if( CV_IS_MAT( arr ) && CV_IS_MAT_CONT( ((CvMat*)arr)->type ))
2236     {
2237         CvMat* mat = (CvMat*)arr;
2238
2239         type = CV_MAT_TYPE(mat->type);
2240         int pix_size = CV_ELEM_SIZE(type);
2241
2242         // the first part is mul-free sufficient check
2243         // that the index is within the matrix
2244         if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) &&
2245             (unsigned)idx >= (unsigned)(mat->rows*mat->cols))
2246             CV_Error( CV_StsOutOfRange, "index is out of range" );
2247
2248         ptr = mat->data.ptr + (size_t)idx*pix_size;
2249     }
2250     else if( !CV_IS_SPARSE_MAT( arr ) || ((CvSparseMat*)arr)->dims > 1 )
2251         ptr = cvPtr1D( arr, idx, &type );
2252     else
2253         ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, &type, -1, 0 );
2254
2255     if( CV_MAT_CN( type ) > 1 )
2256         CV_Error( CV_BadNumChannels, "cvSetReal* support only single-channel arrays" );
2257
2258     if( ptr )
2259         icvSetReal( value, ptr, type );
2260 }
2261
2262
2263 CV_IMPL  void
2264 cvSetReal2D( CvArr* arr, int y, int x, double value )
2265 {
2266     int type = 0;
2267     uchar* ptr;
2268     
2269     if( CV_IS_MAT( arr ))
2270     {
2271         CvMat* mat = (CvMat*)arr;
2272
2273         if( (unsigned)y >= (unsigned)(mat->rows) ||
2274             (unsigned)x >= (unsigned)(mat->cols) )
2275             CV_Error( CV_StsOutOfRange, "index is out of range" );
2276
2277         type = CV_MAT_TYPE(mat->type);
2278         ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type);
2279     }
2280     else if( !CV_IS_SPARSE_MAT( arr ))
2281     {
2282         ptr = cvPtr2D( arr, y, x, &type );
2283     }
2284     else
2285     {
2286         int idx[] = { y, x };
2287         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 );
2288     }
2289     if( CV_MAT_CN( type ) > 1 )
2290         CV_Error( CV_BadNumChannels, "cvSetReal* support only single-channel arrays" );
2291
2292     if( ptr )
2293         icvSetReal( value, ptr, type );
2294 }
2295
2296
2297 CV_IMPL  void
2298 cvSetReal3D( CvArr* arr, int z, int y, int x, double value )
2299 {
2300     int type = 0;
2301     uchar* ptr;
2302     
2303     if( !CV_IS_SPARSE_MAT( arr ))
2304         ptr = cvPtr3D( arr, z, y, x, &type );
2305     else
2306     {
2307         int idx[] = { z, y, x };
2308         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 );
2309     }
2310     if( CV_MAT_CN( type ) > 1 )
2311         CV_Error( CV_BadNumChannels, "cvSetReal* support only single-channel arrays" );
2312
2313     if( ptr )
2314         icvSetReal( value, ptr, type );
2315 }
2316
2317
2318 CV_IMPL  void
2319 cvSetRealND( CvArr* arr, const int* idx, double value )
2320 {
2321     int type = 0;
2322     uchar* ptr;
2323     
2324     if( !CV_IS_SPARSE_MAT( arr ))
2325         ptr = cvPtrND( arr, idx, &type );
2326     else
2327         ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 );
2328
2329     if( CV_MAT_CN( type ) > 1 )
2330         CV_Error( CV_BadNumChannels, "cvSetReal* support only single-channel arrays" );
2331
2332     if( ptr )
2333         icvSetReal( value, ptr, type );
2334 }
2335
2336
2337 CV_IMPL void
2338 cvClearND( CvArr* arr, const int* idx )
2339 {
2340     if( !CV_IS_SPARSE_MAT( arr ))
2341     {
2342         int type;
2343         uchar* ptr;
2344         ptr = cvPtrND( arr, idx, &type );
2345         if( ptr )
2346             CV_ZERO_CHAR( ptr, CV_ELEM_SIZE(type) );
2347     }
2348     else
2349         icvDeleteNode( (CvSparseMat*)arr, idx, 0 );
2350 }
2351
2352
2353 /****************************************************************************************\
2354 *                             Conversion to CvMat or IplImage                            *
2355 \****************************************************************************************/
2356
2357 // convert array (CvMat or IplImage) to CvMat
2358 CV_IMPL CvMat*
2359 cvGetMat( const CvArr* array, CvMat* mat,
2360           int* pCOI, int allowND )
2361 {
2362     CvMat* result = 0;
2363     CvMat* src = (CvMat*)array;
2364     int coi = 0;
2365
2366     if( !mat || !src )
2367         CV_Error( CV_StsNullPtr, "NULL array pointer is passed" );
2368
2369     if( CV_IS_MAT_HDR(src))
2370     {
2371         if( !src->data.ptr )
2372             CV_Error( CV_StsNullPtr, "The matrix has NULL data pointer" );
2373         
2374         result = (CvMat*)src;
2375     }
2376     else if( CV_IS_IMAGE_HDR(src) )
2377     {
2378         const IplImage* img = (const IplImage*)src;
2379         int depth, order;
2380
2381         if( img->imageData == 0 )
2382             CV_Error( CV_StsNullPtr, "The image has NULL data pointer" );
2383
2384         depth = IplToCvDepth( img->depth );
2385         if( depth < 0 )
2386             CV_Error( CV_BadDepth, "" );
2387
2388         order = img->dataOrder & (img->nChannels > 1 ? -1 : 0);
2389
2390         if( img->roi )
2391         {
2392             if( order == IPL_DATA_ORDER_PLANE )
2393             {
2394                 int type = depth;
2395
2396                 if( img->roi->coi == 0 )
2397                     CV_Error( CV_StsBadFlag,
2398                     "Images with planar data layout should be used with COI selected" );
2399
2400                 cvInitMatHeader( mat, img->roi->height,
2401                                 img->roi->width, type,
2402                                 img->imageData + (img->roi->coi-1)*img->imageSize +
2403                                 img->roi->yOffset*img->widthStep +
2404                                 img->roi->xOffset*CV_ELEM_SIZE(type),
2405                                 img->widthStep );
2406             }
2407             else /* pixel order */
2408             {
2409                 int type = CV_MAKETYPE( depth, img->nChannels );
2410                 coi = img->roi->coi;
2411
2412                 if( img->nChannels > CV_CN_MAX )
2413                     CV_Error( CV_BadNumChannels,
2414                         "The image is interleaved and has over CV_CN_MAX channels" );
2415
2416                 cvInitMatHeader( mat, img->roi->height, img->roi->width,
2417                                  type, img->imageData +
2418                                  img->roi->yOffset*img->widthStep +
2419                                  img->roi->xOffset*CV_ELEM_SIZE(type),
2420                                  img->widthStep );
2421             }
2422         }
2423         else
2424         {
2425             int type = CV_MAKETYPE( depth, img->nChannels );
2426
2427             if( order != IPL_DATA_ORDER_PIXEL )
2428                 CV_Error( CV_StsBadFlag, "Pixel order should be used with coi == 0" );
2429
2430             cvInitMatHeader( mat, img->height, img->width, type,
2431                              img->imageData, img->widthStep );
2432         }
2433
2434         result = mat;
2435     }
2436     else if( allowND && CV_IS_MATND_HDR(src) )
2437     {
2438         CvMatND* matnd = (CvMatND*)src;
2439         int i;
2440         int size1 = matnd->dim[0].size, size2 = 1;
2441         
2442         if( !src->data.ptr )
2443             CV_Error( CV_StsNullPtr, "Input array has NULL data pointer" );
2444
2445         if( !CV_IS_MAT_CONT( matnd->type ))
2446             CV_Error( CV_StsBadArg, "Only continuous nD arrays are supported here" );
2447
2448         if( matnd->dims > 2 )
2449             for( i = 1; i < matnd->dims; i++ )
2450                 size2 *= matnd->dim[i].size;
2451         else
2452             size2 = matnd->dims == 1 ? 1 : matnd->dim[1].size;
2453
2454         mat->refcount = 0;
2455         mat->hdr_refcount = 0;
2456         mat->data.ptr = matnd->data.ptr;
2457         mat->rows = size1;
2458         mat->cols = size2;
2459         mat->type = CV_MAT_TYPE(matnd->type) | CV_MAT_MAGIC_VAL | CV_MAT_CONT_FLAG;
2460         mat->step = size2*CV_ELEM_SIZE(matnd->type);
2461         mat->step &= size1 > 1 ? -1 : 0;
2462
2463         icvCheckHuge( mat );
2464         result = mat;
2465     }
2466     else
2467         CV_Error( CV_StsBadFlag, "Unrecognized or unsupported array type" );
2468
2469     if( pCOI )
2470         *pCOI = coi;
2471
2472     return result;
2473 }
2474
2475
2476 CV_IMPL CvArr*
2477 cvReshapeMatND( const CvArr* arr,
2478                 int sizeof_header, CvArr* _header,
2479                 int new_cn, int new_dims, int* new_sizes )
2480 {
2481     CvArr* result = 0;
2482     int dims, coi = 0;
2483
2484     if( !arr || !_header )
2485         CV_Error( CV_StsNullPtr, "NULL pointer to array or destination header" );
2486
2487     if( new_cn == 0 && new_dims == 0 )
2488         CV_Error( CV_StsBadArg, "None of array parameters is changed: dummy call?" );
2489
2490     dims = cvGetDims( arr );
2491
2492     if( new_dims == 0 )
2493     {
2494         new_sizes = 0;
2495         new_dims = dims;
2496     }
2497     else if( new_dims == 1 )
2498     {
2499         new_sizes = 0;
2500     }
2501     else
2502     {
2503         if( new_dims <= 0 || new_dims > CV_MAX_DIM )
2504             CV_Error( CV_StsOutOfRange, "Non-positive or too large number of dimensions" );
2505         if( !new_sizes )
2506             CV_Error( CV_StsNullPtr, "New dimension sizes are not specified" );
2507     }
2508
2509     if( new_dims <= 2 )
2510     {
2511         CvMat* mat = (CvMat*)arr;
2512         CvMat* header = (CvMat*)_header;
2513         int* refcount = 0;
2514         int  hdr_refcount = 0;
2515         int  total_width, new_rows, cn;
2516
2517         if( sizeof_header != sizeof(CvMat))
2518             CV_Error( CV_StsBadArg, "The header should be CvMat" );
2519
2520         if( mat == header )
2521         {
2522             refcount = mat->refcount;
2523             hdr_refcount = mat->hdr_refcount;
2524         }
2525         else if( !CV_IS_MAT( mat ))
2526             mat = cvGetMat( mat, header, &coi, 1 );
2527
2528         cn = CV_MAT_CN( mat->type );
2529         total_width = mat->cols * cn;
2530
2531         if( new_cn == 0 )
2532             new_cn = cn;
2533
2534         if( new_sizes )
2535             new_rows = new_sizes[0];
2536         else if( new_dims == 1 )
2537             new_rows = total_width*mat->rows/new_cn;
2538         else
2539         {
2540             new_rows = mat->rows;
2541             if( new_cn > total_width )
2542                 new_rows = mat->rows * total_width / new_cn;
2543         }
2544
2545         if( new_rows != mat->rows )
2546         {
2547             int total_size = total_width * mat->rows;
2548
2549             if( !CV_IS_MAT_CONT( mat->type ))
2550                 CV_Error( CV_BadStep,
2551                 "The matrix is not continuous so the number of rows can not be changed" );
2552
2553             total_width = total_size / new_rows;
2554
2555             if( total_width * new_rows != total_size )
2556                 CV_Error( CV_StsBadArg, "The total number of matrix elements "
2557                                         "is not divisible by the new number of rows" );
2558         }
2559
2560         header->rows = new_rows;
2561         header->cols = total_width / new_cn;
2562
2563         if( header->cols * new_cn != total_width ||
2564             (new_sizes && header->cols != new_sizes[1]) )
2565             CV_Error( CV_StsBadArg, "The total matrix width is not "
2566                             "divisible by the new number of columns" );
2567
2568         header->type = (mat->type & ~CV_MAT_TYPE_MASK) | CV_MAKETYPE(mat->type, new_cn);
2569         header->step = header->cols * CV_ELEM_SIZE(mat->type);
2570         header->step &= new_rows > 1 ? -1 : 0;
2571         header->refcount = refcount;
2572         header->hdr_refcount = hdr_refcount;
2573     }
2574     else
2575     {
2576         CvMatND* header = (CvMatND*)_header;
2577
2578         if( sizeof_header != sizeof(CvMatND))
2579             CV_Error( CV_StsBadSize, "The header should be CvMatND" );
2580         
2581         if( !new_sizes )
2582         {
2583             if( !CV_IS_MATND( arr ))
2584                 CV_Error( CV_StsBadArg, "The source array must be CvMatND" );
2585
2586             {
2587             CvMatND* mat = (CvMatND*)arr;
2588             assert( new_cn > 0 );
2589             int last_dim_size = mat->dim[mat->dims-1].size*CV_MAT_CN(mat->type);
2590             int new_size = last_dim_size/new_cn;
2591
2592             if( new_size*new_cn != last_dim_size )
2593                 CV_Error( CV_StsBadArg,
2594                 "The last dimension full size is not divisible by new number of channels");
2595
2596             if( mat != header )
2597             {
2598                 memcpy( header, mat, sizeof(*header));
2599                 header->refcount = 0;
2600                 header->hdr_refcount = 0;
2601             }
2602
2603             header->dim[header->dims-1].size = new_size;
2604             header->type = (header->type & ~CV_MAT_TYPE_MASK) | CV_MAKETYPE(header->type, new_cn);
2605             }
2606         }
2607         else
2608         {
2609             CvMatND stub;
2610             CvMatND* mat = (CvMatND*)arr;
2611             int i, size1, size2;
2612             int step;
2613             
2614             if( new_cn != 0 )
2615                 CV_Error( CV_StsBadArg,
2616                 "Simultaneous change of shape and number of channels is not supported. "
2617                 "Do it by 2 separate calls" );
2618             
2619             if( !CV_IS_MATND( mat ))
2620             {
2621                 cvGetMatND( mat, &stub, &coi );
2622                 mat = &stub;
2623             }
2624
2625             if( CV_IS_MAT_CONT( mat->type ))
2626                 CV_Error( CV_StsBadArg, "Non-continuous nD arrays are not supported" );
2627
2628             size1 = mat->dim[0].size;
2629             for( i = 1; i < dims; i++ )
2630                 size1 *= mat->dim[i].size;
2631
2632             size2 = 1;
2633             for( i = 0; i < new_dims; i++ )
2634             {
2635                 if( new_sizes[i] <= 0 )
2636                     CV_Error( CV_StsBadSize,
2637                     "One of new dimension sizes is non-positive" );
2638                 size2 *= new_sizes[i];
2639             }
2640
2641             if( size1 != size2 )
2642                 CV_Error( CV_StsBadSize,
2643                 "Number of elements in the original and reshaped array is different" );
2644
2645             if( header != mat )
2646             {
2647                 header->refcount = 0;
2648                 header->hdr_refcount = 0;
2649             }
2650
2651             header->dims = new_dims;
2652             header->type = mat->type;
2653             header->data.ptr = mat->data.ptr;
2654             step = CV_ELEM_SIZE(header->type);
2655
2656             for( i = new_dims - 1; i >= 0; i-- )
2657             {
2658                 header->dim[i].size = new_sizes[i];
2659                 header->dim[i].step = step;
2660                 step *= new_sizes[i];
2661             }
2662         }
2663     }
2664
2665     if( !coi )
2666         CV_Error( CV_BadCOI, "COI is not supported by this operation" );
2667
2668     result = _header;
2669     return result;
2670 }
2671
2672
2673 CV_IMPL CvMat*
2674 cvReshape( const CvArr* array, CvMat* header,
2675            int new_cn, int new_rows )
2676 {
2677     CvMat* result = 0;
2678     CvMat *mat = (CvMat*)array;
2679     int total_width, new_width;
2680
2681     if( !header )
2682         CV_Error( CV_StsNullPtr, "" );
2683
2684     if( !CV_IS_MAT( mat ))
2685     {
2686         int coi = 0;
2687         mat = cvGetMat( mat, header, &coi, 1 );
2688         if( coi )
2689             CV_Error( CV_BadCOI, "COI is not supported" );
2690     }
2691
2692     if( new_cn == 0 )
2693         new_cn = CV_MAT_CN(mat->type);
2694     else if( (unsigned)(new_cn - 1) > 3 )
2695         CV_Error( CV_BadNumChannels, "" );
2696
2697     if( mat != header )
2698     {
2699         int hdr_refcount = header->hdr_refcount;
2700         *header = *mat;
2701         header->refcount = 0;
2702         header->hdr_refcount = hdr_refcount;
2703     }
2704
2705     total_width = mat->cols * CV_MAT_CN( mat->type );
2706
2707     if( (new_cn > total_width || total_width % new_cn != 0) && new_rows == 0 )
2708         new_rows = mat->rows * total_width / new_cn;
2709
2710     if( new_rows == 0 || new_rows == mat->rows )
2711     {
2712         header->rows = mat->rows;
2713         header->step = mat->step;
2714     }
2715     else
2716     {
2717         int total_size = total_width * mat->rows;
2718         if( !CV_IS_MAT_CONT( mat->type ))
2719             CV_Error( CV_BadStep,
2720             "The matrix is not continuous, thus its number of rows can not be changed" );
2721
2722         if( (unsigned)new_rows > (unsigned)total_size )
2723             CV_Error( CV_StsOutOfRange, "Bad new number of rows" );
2724
2725         total_width = total_size / new_rows;
2726
2727         if( total_width * new_rows != total_size )
2728             CV_Error( CV_StsBadArg, "The total number of matrix elements "
2729                                     "is not divisible by the new number of rows" );
2730
2731         header->rows = new_rows;
2732         header->step = total_width * CV_ELEM_SIZE1(mat->type);
2733     }
2734
2735     new_width = total_width / new_cn;
2736
2737     if( new_width * new_cn != total_width )
2738         CV_Error( CV_BadNumChannels,
2739         "The total width is not divisible by the new number of channels" );
2740
2741     header->cols = new_width;
2742     header->type = (mat->type  & ~CV_MAT_TYPE_MASK) | CV_MAKETYPE(mat->type, new_cn);
2743
2744     result = header;
2745     return  result;
2746 }
2747
2748
2749 // convert array (CvMat or IplImage) to IplImage
2750 CV_IMPL IplImage*
2751 cvGetImage( const CvArr* array, IplImage* img )
2752 {
2753     IplImage* result = 0;
2754     const IplImage* src = (const IplImage*)array;
2755     int depth;
2756
2757     if( !img )
2758         CV_Error( CV_StsNullPtr, "" );
2759
2760     if( !CV_IS_IMAGE_HDR(src) )
2761     {
2762         const CvMat* mat = (const CvMat*)src;
2763         
2764         if( !CV_IS_MAT_HDR(mat))
2765             CV_Error( CV_StsBadFlag, "" );
2766
2767         if( mat->data.ptr == 0 )
2768             CV_Error( CV_StsNullPtr, "" );
2769
2770         depth = cvIplDepth(mat->type);
2771
2772         cvInitImageHeader( img, cvSize(mat->cols, mat->rows),
2773                            depth, CV_MAT_CN(mat->type) );
2774         cvSetData( img, mat->data.ptr, mat->step );
2775
2776         result = img;
2777     }
2778     else
2779     {
2780         result = (IplImage*)src;
2781     }
2782
2783     return result;
2784 }
2785
2786
2787 /****************************************************************************************\
2788 *                               IplImage-specific functions                              *
2789 \****************************************************************************************/
2790
2791 static IplROI* icvCreateROI( int coi, int xOffset, int yOffset, int width, int height )
2792 {
2793     IplROI *roi = 0;
2794     if( !CvIPL.createROI )
2795     {
2796         roi = (IplROI*)cvAlloc( sizeof(*roi));
2797
2798         roi->coi = coi;
2799         roi->xOffset = xOffset;
2800         roi->yOffset = yOffset;
2801         roi->width = width;
2802         roi->height = height;
2803     }
2804     else
2805     {
2806         roi = CvIPL.createROI( coi, xOffset, yOffset, width, height );
2807     }
2808
2809     return roi;
2810 }
2811
2812 static  void
2813 icvGetColorModel( int nchannels, const char** colorModel, const char** channelSeq )
2814 {
2815     static const char* tab[][2] =
2816     {
2817         {"GRAY", "GRAY"},
2818         {"",""},
2819         {"RGB","BGR"},
2820         {"RGB","BGRA"}
2821     };
2822
2823     nchannels--;
2824     *colorModel = *channelSeq = "";
2825
2826     if( (unsigned)nchannels <= 3 )
2827     {
2828         *colorModel = tab[nchannels][0];
2829         *channelSeq = tab[nchannels][1];
2830     }
2831 }
2832
2833
2834 // create IplImage header
2835 CV_IMPL IplImage *
2836 cvCreateImageHeader( CvSize size, int depth, int channels )
2837 {
2838     IplImage *img = 0;
2839
2840     if( !CvIPL.createHeader )
2841     {
2842         img = (IplImage *)cvAlloc( sizeof( *img ));
2843         cvInitImageHeader( img, size, depth, channels, IPL_ORIGIN_TL,
2844                                     CV_DEFAULT_IMAGE_ROW_ALIGN );
2845     }
2846     else
2847     {
2848         const char *colorModel, *channelSeq;
2849
2850         icvGetColorModel( channels, &colorModel, &channelSeq );
2851
2852         img = CvIPL.createHeader( channels, 0, depth, (char*)colorModel, (char*)channelSeq,
2853                                   IPL_DATA_ORDER_PIXEL, IPL_ORIGIN_TL,
2854                                   CV_DEFAULT_IMAGE_ROW_ALIGN,
2855                                   size.width, size.height, 0, 0, 0, 0 );
2856     }
2857
2858     return img;
2859 }
2860
2861
2862 // create IplImage header and allocate underlying data
2863 CV_IMPL IplImage *
2864 cvCreateImage( CvSize size, int depth, int channels )
2865 {
2866     IplImage *img = cvCreateImageHeader( size, depth, channels );
2867     assert( img );
2868     cvCreateData( img );
2869
2870     return img;
2871 }
2872
2873
2874 // initalize IplImage header, allocated by the user
2875 CV_IMPL IplImage*
2876 cvInitImageHeader( IplImage * image, CvSize size, int depth,
2877                    int channels, int origin, int align )
2878 {
2879     const char *colorModel, *channelSeq;
2880
2881     if( !image )
2882         CV_Error( CV_HeaderIsNull, "null pointer to header" );
2883
2884     memset( image, 0, sizeof( *image ));
2885     image->nSize = sizeof( *image );
2886
2887     icvGetColorModel( channels, &colorModel, &channelSeq );
2888     strncpy( image->colorModel, colorModel, 4 );
2889     strncpy( image->channelSeq, channelSeq, 4 );
2890
2891     if( size.width < 0 || size.height < 0 )
2892         CV_Error( CV_BadROISize, "Bad input roi" );
2893
2894     if( (depth != (int)IPL_DEPTH_1U && depth != (int)IPL_DEPTH_8U &&
2895          depth != (int)IPL_DEPTH_8S && depth != (int)IPL_DEPTH_16U &&
2896          depth != (int)IPL_DEPTH_16S && depth != (int)IPL_DEPTH_32S &&
2897          depth != (int)IPL_DEPTH_32F && depth != (int)IPL_DEPTH_64F) ||
2898          channels < 0 )
2899         CV_Error( CV_BadDepth, "Unsupported format" );
2900     if( origin != CV_ORIGIN_BL && origin != CV_ORIGIN_TL )
2901         CV_Error( CV_BadOrigin, "Bad input origin" );
2902
2903     if( align != 4 && align != 8 )
2904         CV_Error( CV_BadAlign, "Bad input align" );
2905
2906     image->width = size.width;
2907     image->height = size.height;
2908
2909     if( image->roi )
2910     {
2911         image->roi->coi = 0;
2912         image->roi->xOffset = image->roi->yOffset = 0;
2913         image->roi->width = size.width;
2914         image->roi->height = size.height;
2915     }
2916
2917     image->nChannels = MAX( channels, 1 );
2918     image->depth = depth;
2919     image->align = align;
2920     image->widthStep = (((image->width * image->nChannels *
2921          (image->depth & ~IPL_DEPTH_SIGN) + 7)/8)+ align - 1) & (~(align - 1));
2922     image->origin = origin;
2923     image->imageSize = image->widthStep * image->height;
2924
2925     return image;
2926 }
2927
2928
2929 CV_IMPL void
2930 cvReleaseImageHeader( IplImage** image )
2931 {
2932     if( !image )
2933         CV_Error( CV_StsNullPtr, "" );
2934
2935     if( *image )
2936     {
2937         IplImage* img = *image;
2938         *image = 0;
2939         
2940         if( !CvIPL.deallocate )
2941         {
2942             cvFree( &img->roi );
2943             cvFree( &img );
2944         }
2945         else
2946         {
2947             CvIPL.deallocate( img, IPL_IMAGE_HEADER | IPL_IMAGE_ROI );
2948         }
2949     }
2950 }
2951
2952
2953 CV_IMPL void
2954 cvReleaseImage( IplImage ** image )
2955 {
2956     if( !image )
2957         CV_Error( CV_StsNullPtr, "" );
2958
2959     if( *image )
2960     {
2961         IplImage* img = *image;
2962         *image = 0;
2963         
2964         cvReleaseData( img );
2965         cvReleaseImageHeader( &img );
2966     }
2967 }
2968
2969
2970 CV_IMPL void
2971 cvSetImageROI( IplImage* image, CvRect rect )
2972 {
2973     if( !image )
2974         CV_Error( CV_HeaderIsNull, "" );
2975
2976     if( rect.x > image->width || rect.y > image->height )
2977         CV_Error( CV_BadROISize, "" );
2978
2979     if( rect.x + rect.width < 0 || rect.y + rect.height < 0 )
2980         CV_Error( CV_BadROISize, "" );
2981
2982     if( rect.x < 0 )
2983     {
2984         rect.width += rect.x;
2985         rect.x = 0;
2986     }
2987
2988     if( rect.y < 0 )
2989     {
2990         rect.height += rect.y;
2991         rect.y = 0;
2992     }
2993
2994     if( rect.x + rect.width > image->width )
2995         rect.width = image->width - rect.x;
2996
2997     if( rect.y + rect.height > image->height )
2998         rect.height = image->height - rect.y;
2999
3000     if( image->roi )
3001     {
3002         image->roi->xOffset = rect.x;
3003         image->roi->yOffset = rect.y;
3004         image->roi->width = rect.width;
3005         image->roi->height = rect.height;
3006     }
3007     else
3008         image->roi = icvCreateROI( 0, rect.x, rect.y, rect.width, rect.height );
3009 }
3010
3011
3012 CV_IMPL void
3013 cvResetImageROI( IplImage* image )
3014 {
3015     if( !image )
3016         CV_Error( CV_HeaderIsNull, "" );
3017
3018     if( image->roi )
3019     {
3020         if( !CvIPL.deallocate )
3021         {
3022             cvFree( &image->roi );
3023         }
3024         else
3025         {
3026             CvIPL.deallocate( image, IPL_IMAGE_ROI );
3027             image->roi = 0;
3028         }
3029     }
3030 }
3031
3032
3033 CV_IMPL CvRect
3034 cvGetImageROI( const IplImage* img )
3035 {
3036     CvRect rect = { 0, 0, 0, 0 };
3037     if( !img )
3038         CV_Error( CV_StsNullPtr, "Null pointer to image" );
3039
3040     if( img->roi )
3041         rect = cvRect( img->roi->xOffset, img->roi->yOffset,
3042                        img->roi->width, img->roi->height );
3043     else
3044         rect = cvRect( 0, 0, img->width, img->height );
3045     
3046     return rect;
3047 }
3048
3049
3050 CV_IMPL void
3051 cvSetImageCOI( IplImage* image, int coi )
3052 {
3053     if( !image )
3054         CV_Error( CV_HeaderIsNull, "" );
3055
3056     if( (unsigned)coi > (unsigned)(image->nChannels) )
3057         CV_Error( CV_BadCOI, "" );
3058
3059     if( image->roi || coi != 0 )
3060     {
3061         if( image->roi )
3062         {
3063             image->roi->coi = coi;
3064         }
3065         else
3066         {
3067             image->roi = icvCreateROI( coi, 0, 0, image->width, image->height );
3068         }
3069     }
3070 }
3071
3072
3073 CV_IMPL int
3074 cvGetImageCOI( const IplImage* image )
3075 {
3076     if( !image )
3077         CV_Error( CV_HeaderIsNull, "" );
3078
3079     return image->roi ? image->roi->coi : 0;
3080 }
3081
3082
3083 CV_IMPL IplImage*
3084 cvCloneImage( const IplImage* src )
3085 {
3086     IplImage* dst = 0;
3087
3088     if( !CV_IS_IMAGE_HDR( src ))
3089         CV_Error( CV_StsBadArg, "Bad image header" );
3090
3091     if( !CvIPL.cloneImage )
3092     {
3093         dst = (IplImage*)cvAlloc( sizeof(*dst));
3094
3095         memcpy( dst, src, sizeof(*src));
3096         dst->imageData = dst->imageDataOrigin = 0;
3097         dst->roi = 0;
3098
3099         if( src->roi )
3100         {
3101             dst->roi = icvCreateROI( src->roi->coi, src->roi->xOffset,
3102                           src->roi->yOffset, src->roi->width, src->roi->height );
3103         }
3104
3105         if( src->imageData )
3106         {
3107             int size = src->imageSize;
3108             cvCreateData( dst );
3109             memcpy( dst->imageData, src->imageData, size );
3110         }
3111     }
3112     else
3113         dst = CvIPL.cloneImage( src );
3114
3115     return dst;
3116 }
3117
3118
3119 /****************************************************************************************\
3120 *                            Additional operations on CvTermCriteria                     *
3121 \****************************************************************************************/
3122
3123 CV_IMPL CvTermCriteria
3124 cvCheckTermCriteria( CvTermCriteria criteria, double default_eps,
3125                      int default_max_iters )
3126 {
3127     CvTermCriteria crit;
3128
3129     crit.type = CV_TERMCRIT_ITER|CV_TERMCRIT_EPS;
3130     crit.max_iter = default_max_iters;
3131     crit.epsilon = (float)default_eps;
3132
3133     if( (criteria.type & ~(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER)) != 0 )
3134         CV_Error( CV_StsBadArg,
3135                   "Unknown type of term criteria" );
3136
3137     if( (criteria.type & CV_TERMCRIT_ITER) != 0 )
3138     {
3139         if( criteria.max_iter <= 0 )
3140             CV_Error( CV_StsBadArg,
3141                   "Iterations flag is set and maximum number of iterations is <= 0" );
3142         crit.max_iter = criteria.max_iter;
3143     }
3144     
3145     if( (criteria.type & CV_TERMCRIT_EPS) != 0 )
3146     {
3147         if( criteria.epsilon < 0 )
3148             CV_Error( CV_StsBadArg, "Accuracy flag is set and epsilon is < 0" );
3149
3150         crit.epsilon = criteria.epsilon;
3151     }
3152
3153     if( (criteria.type & (CV_TERMCRIT_EPS | CV_TERMCRIT_ITER)) == 0 )
3154         CV_Error( CV_StsBadArg,
3155                   "Neither accuracy nor maximum iterations "
3156                   "number flags are set in criteria type" );
3157
3158     crit.epsilon = (float)MAX( 0, crit.epsilon );
3159     crit.max_iter = MAX( 1, crit.max_iter );
3160
3161     return crit;
3162 }
3163
3164
3165 /* End of file. */