Update to 2.0.0 tree from current Fremantle build
[opencv] / interfaces / swig / python / pyhelpers.cpp
1 #include "pyhelpers.h"
2 #include <iostream>
3 #include <sstream>
4
5 int PySwigObject_Check(PyObject *op);
6
7 /* Py_ssize_t for old Pythons */
8 #if PY_VERSION_HEX < 0x02050000
9 typedef int Py_ssize_t;
10 #endif
11
12 PyObject * PyTuple_FromIntArray(int * arr, int len){
13   PyObject * obj = PyTuple_New(len);
14   for(int i=0; i<len; i++){
15     PyTuple_SetItem(obj, i, PyLong_FromLong( arr[i] ) );
16   }
17   return obj;
18 }
19
20 PyObject * SWIG_SetResult(PyObject * result, PyObject * obj){
21   if(result){
22     Py_DECREF(result);
23   }
24   result = PyTuple_New(1);
25   PyTuple_SetItem(result, 0, obj);
26   return result;
27 }
28
29 PyObject * SWIG_AppendResult(PyObject * result, PyObject ** to_add, int num){
30   if ((!result) || (result == Py_None)) {
31     /* no other results, so just add our values */
32
33     /* if only one object, return that */
34     if(num==1){
35       return to_add[0];
36     }
37     
38     /* create a new tuple to put in our new pointer python objects */
39     result = PyTuple_New (num);
40
41     /* put in our new pointer python objects */
42     for(int i=0; i<num; i++){
43       PyTuple_SetItem (result, i, to_add[i]);
44     } 
45   }
46   else {
47     /* we have other results, so add it to the end */
48
49     if (!PyTuple_Check (result)) {
50       /* previous result is not a tuple, so create one and put
51          previous result and current pointer in it */
52
53       /* first, save previous result */
54       PyObject *obj_save = result;
55
56       /* then, create the tuple */
57       result = PyTuple_New (1);
58
59       /* finaly, put the saved value in the tuple */
60       PyTuple_SetItem (result, 0, obj_save);
61     }
62
63     /* create a new tuple to put in our new pointer python object */
64     PyObject *my_obj = PyTuple_New (num);
65
66     /* put in our new pointer python object */
67     for( int i=0; i<num ; i++ ){
68       PyTuple_SetItem (my_obj, i, to_add[i]);
69     }
70
71     /* save the previous result */
72     PyObject *obj_save = result;
73
74     /* concat previous and our new result */
75     result = PySequence_Concat (obj_save, my_obj);
76
77     /* decrement the usage of no more used objects */
78     Py_DECREF (obj_save);
79     Py_DECREF (my_obj);
80   }
81   return result;
82 }
83
84 template <typename T>
85 void cv_arr_write(FILE * f, const char * fmt, T * data, size_t rows, size_t nch, size_t step){
86     size_t i,j,k;
87     char * cdata = (char *) data;
88     const char * chdelim1="", * chdelim2="";
89
90     // only output channel parens if > 1
91     if(nch>1){
92         chdelim1="(";
93         chdelim2=")";
94     }
95
96     fputs("[",f);
97     for(i=0; i<rows; i++){
98     fputs("[",f);
99
100         // first element
101         // out<<chdelim1;
102     fputs(chdelim1, f);
103         fprintf(f, fmt, ((T*)(cdata+i*step))[0]);
104         for(k=1; k<nch; k++){
105       fputs(", ", f);
106       fprintf(f, fmt, ((T*)(cdata+i*step))[k]);
107         }
108     fputs(chdelim2,f);
109
110         // remaining elements
111         for(j=nch*sizeof(T); j<step; j+=(nch*sizeof(T))){
112       fprintf(f, ",%s", chdelim1);
113           fprintf(f, fmt, ((T*)(cdata+i*step+j))[0]);
114             for(k=1; k<nch; k++){
115         fputs(", ", f);
116         fprintf(f, fmt, ((T*)(cdata+i*step+j))[k]);
117             }
118       fputs(chdelim2, f);
119         }
120     fputs( "]\n", f );
121     }
122   fputs( "]", f );
123 }
124
125 void cvArrPrint(CvArr * arr){
126     CV_FUNCNAME( "cvArrPrint" );
127       
128   __BEGIN__;
129   CvMat * mat;
130   CvMat stub;
131
132   mat = cvGetMat(arr, &stub);
133   
134   int cn = CV_MAT_CN(mat->type);
135   int depth = CV_MAT_DEPTH(mat->type);
136   int step = MAX(mat->step, cn*mat->cols*CV_ELEM_SIZE(depth));
137
138
139   switch(depth){
140     case CV_8U:
141       cv_arr_write(stdout, "%u", (uchar *)mat->data.ptr, mat->rows, cn, step);
142       break;
143     case CV_8S:
144       cv_arr_write(stdout, "%d", (char *)mat->data.ptr, mat->rows, cn, step);
145       break;
146     case CV_16U:
147       cv_arr_write(stdout, "%u", (ushort *)mat->data.ptr, mat->rows, cn, step);
148       break;
149     case CV_16S:
150       cv_arr_write(stdout, "%d", (short *)mat->data.ptr, mat->rows, cn, step);
151       break;
152     case CV_32S:
153       cv_arr_write(stdout, "%d", (int *)mat->data.ptr, mat->rows, cn, step);
154       break;
155     case CV_32F:
156       cv_arr_write(stdout, "%f", (float *)mat->data.ptr, mat->rows, cn, step);
157       break;
158     case CV_64F:
159       cv_arr_write(stdout, "%g", (double *)mat->data.ptr, mat->rows, cn, step);
160       break;
161     default:
162       CV_ERROR( CV_StsError, "Unknown element type");
163       break;
164   }
165
166   __END__;
167 }
168
169 // deal with negative array indices
170 int PyLong_AsIndex( PyObject * idx_object, int len ){
171   int idx = PyLong_AsLong( idx_object );
172   if(idx<0) return len+idx;
173   return idx;
174 }
175
176 CvRect PySlice_to_CvRect(CvArr * src, PyObject * idx_object){
177   CvSize sz = cvGetSize(src);
178   //printf("Size %dx%d\n", sz.height, sz.width);
179   int lower[2], upper[2];
180   Py_ssize_t len, start, stop, step, slicelength;
181
182   if(PyInt_Check(idx_object) || PyLong_Check(idx_object)){
183     // if array is a row vector, assume index into columns
184     if(sz.height>1){
185       lower[0] = PyLong_AsIndex( idx_object, sz.height );
186       upper[0] = lower[0] + 1;
187       lower[1] = 0;
188       upper[1] = sz.width;
189     }
190     else{
191       lower[0] = 0;
192       upper[0] = sz.height;
193       lower[1] = PyLong_AsIndex( idx_object, sz.width );
194       upper[1] = lower[1]+1;
195     }
196   }
197
198   // 1. Slice
199   else if(PySlice_Check(idx_object)){
200     len = sz.height;
201     if(PySlice_GetIndicesEx( (PySliceObject*)idx_object, len, &start, &stop, &step, &slicelength )!=0){
202       printf("Error in PySlice_GetIndicesEx: returning NULL");
203       PyErr_SetString(PyExc_Exception, "Error");
204       return cvRect(0,0,0,0);
205     }
206     // if array is a row vector, assume index bounds are into columns
207     if(sz.height>1){
208       lower[0] = (int) start; // use c convention of start index = 0
209       upper[0] = (int) stop;    // use c convention
210       lower[1] = 0;
211       upper[1] = sz.width;
212     }
213     else{
214       lower[1] = (int) start; // use c convention of start index = 0
215       upper[1] = (int) stop;    // use c convention
216       lower[0] = 0;
217       upper[0] = sz.height;
218     }
219   }
220
221   // 2. Tuple
222   else if(PyTuple_Check(idx_object)){
223     //printf("PyTuple{\n");
224     if(PyObject_Length(idx_object)!=2){
225       //printf("Expected a sequence of length 2: returning NULL");
226       PyErr_SetString(PyExc_ValueError, "Expected a sequence with 2 elements");
227       return cvRect(0,0,0,0);
228     }
229     for(int i=0; i<2; i++){
230       PyObject *o = PyTuple_GetItem(idx_object, i);
231
232       // 2a. Slice -- same as above
233       if(PySlice_Check(o)){
234         //printf("PySlice\n");
235         len = (i==0 ? sz.height : sz.width);
236         if(PySlice_GetIndicesEx( (PySliceObject*)o, len, &start, &stop, &step, &slicelength )!=0){
237           PyErr_SetString(PyExc_Exception, "Error");
238           printf("Error in PySlice_GetIndicesEx: returning NULL");
239           return cvRect(0,0,0,0);
240         }
241         //printf("PySlice_GetIndecesEx(%d, %d, %d, %d, %d)\n", len, start, stop, step, slicelength);
242         lower[i] = start;
243         upper[i] = stop;
244
245       }
246
247       // 2b. Integer
248       else if(PyInt_Check(o) || PyLong_Check(o)){
249         //printf("PyInt\n");
250         lower[i] = PyLong_AsIndex(o, i==0 ? sz.height : sz.width);
251         upper[i] = lower[i]+1;
252       }
253
254       else {
255         PyErr_SetString(PyExc_TypeError, "Expected a sequence of slices or integers");
256         printf("Expected a slice or int as sequence item: returning NULL");
257         return cvRect(0,0,0,0);
258       }
259     }
260   }
261
262   else {
263     PyErr_SetString( PyExc_TypeError, "Expected a slice or sequence");
264     printf("Expected a slice or sequence: returning NULL");
265     return cvRect(0,0,0,0);
266   }
267
268   //lower[0] = MAX(0, lower[0]);
269   //lower[1] = MAX(0, lower[1]);
270   //upper[0] = MIN(sz.height, upper[0]);
271   //upper[1] = MIN(sz.width, upper[1]);
272   //printf("Slice=%d %d %d %d\n", lower[0], upper[0], lower[1], upper[1]);
273   return cvRect(lower[1],lower[0], upper[1]-lower[1], upper[0]-lower[0]);
274 }
275
276 int CheckSliceBounds(CvRect * rect, int w, int h){
277         //printf("__setitem__ slice(%d:%d, %d:%d) array(%d,%d)", rect.x, rect.y, rect.x+rect.width, rect.y+rect.height, w, h);
278         if(rect->width<=0 || rect->height<=0 ||
279                 rect->width>w || rect->height>h ||
280                 rect->x<0 || rect->y<0 ||
281                 rect->x>= w || rect->y >=h){
282                 char errstr[256];
283
284                 // previous function already set error string
285                 if(rect->width==0 && rect->height==0 && rect->x==0 && rect->y==0) return -1;
286
287                 sprintf(errstr, "Requested slice [ %d:%d %d:%d ] oversteps array sized [ %d %d ]", 
288                         rect->x, rect->y, rect->x+rect->width, rect->y+rect->height, w, h);
289                 PyErr_SetString(PyExc_IndexError, errstr);
290                 //PyErr_SetString(PyExc_ValueError, errstr);
291                 return 0;
292         }
293     return 1;
294 }
295
296 double PyObject_AsDouble(PyObject * obj){
297   if(PyNumber_Check(obj)){
298     if(PyFloat_Check(obj)){
299       return PyFloat_AsDouble(obj);
300     }
301     else if(PyInt_Check(obj) || PyLong_Check(obj)){
302       return (double) PyLong_AsLong(obj);
303     }
304   }
305   PyErr_SetString( PyExc_TypeError, "Could not convert python object to Double");
306   return -1;
307 }
308
309 long PyObject_AsLong(PyObject * obj){
310     if(PyNumber_Check(obj)){
311         if(PyFloat_Check(obj)){
312             return (long) PyFloat_AsDouble(obj);
313         }
314         else if(PyInt_Check(obj) || PyLong_Check(obj)){
315             return PyLong_AsLong(obj);
316         }
317     }
318   PyErr_SetString( PyExc_TypeError, "Could not convert python object to Long");
319   return -1;
320 }
321
322 CvArr * PyArray_to_CvArr (PyObject * obj)
323 {
324   // let's try to create a temporary CvMat header that points to the
325   // data owned by obj and reflects its memory layout
326   
327   CvArr * cvarr  = NULL;
328   
329   void * raw_data = 0;
330   long   rows;
331   long   cols;
332   long   channels;
333   long   step;
334   long   mat_type     = 7;
335   long   element_size = 1;
336   
337   // infer layout from array interface
338   PyObject * interface = PyObject_GetAttrString (obj, "__array_interface__");
339   
340   
341   // the array interface should be a dict
342   if (PyMapping_Check (interface))
343   {
344     if (PyMapping_HasKeyString (interface, (char*)"version") &&
345         PyMapping_HasKeyString (interface, (char*)"shape")   &&
346         PyMapping_HasKeyString (interface, (char*)"typestr") &&
347         PyMapping_HasKeyString (interface, (char*)"data"))
348     {
349       PyObject * version = PyMapping_GetItemString (interface, (char*)"version");
350       PyObject * shape   = PyMapping_GetItemString (interface, (char*)"shape");
351       PyObject * typestr = PyMapping_GetItemString (interface, (char*)"typestr");
352       PyObject * data    = PyMapping_GetItemString (interface, (char*)"data");
353       
354       if (!PyInt_Check (version)  ||  PyInt_AsLong (version) != 3)
355         PyErr_SetString(PyExc_TypeError, "OpenCV understands version 3 of the __array_interface__ only");
356       else
357       {
358         if (!PyTuple_Check (shape)  ||  PyTuple_Size (shape) < 2  ||  PyTuple_Size (shape) > 3)
359           PyErr_SetString(PyExc_TypeError, "arrays must have a shape with 2 or 3 dimensions");
360         else
361         {
362           rows     = PyInt_AsLong (PyTuple_GetItem (shape, 0));
363           cols     = PyInt_AsLong (PyTuple_GetItem (shape, 1));
364           channels = PyTuple_Size (shape) < 3 ? 1 : PyInt_AsLong (PyTuple_GetItem (shape, 2));
365           
366           if (rows < 1  ||  cols < 1  ||  channels < 1  ||  channels > 4)
367             PyErr_SetString(PyExc_TypeError, "rows and columns must be positive, channels from 1 to 4");
368           else
369           {
370 //              fprintf (stderr, "rows: %ld, cols: %ld, channels %ld\n", rows, cols, channels); fflush (stderr);
371             
372             if (! PyTuple_Check (data)  ||  PyTuple_Size (data) != 2  ||  
373                 !(PyInt_Check (PyTuple_GetItem (data,0)) || PyLong_Check (PyTuple_GetItem (data,0))) ||
374                 !(PyBool_Check (PyTuple_GetItem (data,1)) && !PyInt_AsLong (PyTuple_GetItem (data,1))))
375               PyErr_SetString (PyExc_TypeError, "arrays must have a pointer to writeable data");
376             else
377             {
378               raw_data = PyLong_AsVoidPtr (PyTuple_GetItem (data,0));
379 //                fprintf(stderr, "raw_data: %p\n", raw_data); fflush (stderr);
380               
381               char *      format_str = NULL;
382               Py_ssize_t  len        = 0;
383               
384               if (!PyString_Check (typestr)  ||  PyString_AsStringAndSize (typestr, & format_str, &len) == -1  ||  len !=3)
385                 PyErr_SetString(PyExc_TypeError, "there is something wrong with the format string");
386               else
387               {
388 //                fprintf(stderr, "format: %c %c\n", format_str[1], format_str[2]); fflush (stderr);
389               
390                 if      (format_str[1] == 'u'  &&  format_str[2] == '1')
391                 {
392                   element_size = 1;
393                   mat_type     = CV_MAKETYPE(CV_8U, channels);
394                 }
395                 else if (format_str[1] == 'i'  &&  format_str[2] == '1')
396                 {
397                   element_size = 1;
398                   mat_type     = CV_MAKETYPE(CV_8S, channels);
399                 }
400                 else if (format_str[1] == 'u'  &&  format_str[2] == '2')
401                 {
402                   element_size = 2;
403                   mat_type     = CV_MAKETYPE(CV_16U, channels);
404                 }
405                 else if (format_str[1] == 'i'  &&  format_str[2] == '2')
406                 {
407                   element_size = 2;
408                   mat_type     = CV_MAKETYPE(CV_16S, channels);
409                 }
410                 else if (format_str[1] == 'i'  &&  format_str[2] == '4')
411                 {
412                   element_size = 4;
413                   mat_type     = CV_MAKETYPE(CV_32S, channels);
414                 }
415                 else if (format_str[1] == 'f'  &&  format_str[2] == '4')
416                 {
417                   element_size = 4;
418                   mat_type     = CV_MAKETYPE(CV_32F, channels);
419                 }
420                 else if (format_str[1] == 'f'  &&  format_str[2] == '8')
421                 {
422                   element_size = 8;
423                   mat_type     = CV_MAKETYPE(CV_64F, channels);
424                 }
425                 else
426                 {
427                   PyErr_SetString(PyExc_TypeError, "unknown or unhandled element format");
428                   mat_type     = CV_USRTYPE1;
429                 }
430                 
431                 // handle strides if given
432                 // TODO: implement stride handling
433                 step = cols * channels * element_size;
434                 if (PyMapping_HasKeyString (interface, (char*)"strides"))
435                 {
436                   PyObject * strides = PyMapping_GetItemString (interface, (char*)"strides");
437                   
438                   if (strides != Py_None)
439                   {
440                     fprintf(stderr, "we have strides ... not handled!\n"); fflush (stderr);
441                     PyErr_SetString(PyExc_TypeError, "arrays with strides not handled yet");
442                     mat_type = CV_USRTYPE1; // use this to denote, we've got an error
443                   }
444                   
445                   Py_DECREF (strides);
446                 }
447                 
448                 // create matrix header if everything is okay
449                 if (mat_type != CV_USRTYPE1)
450                 {
451                   CvMat * temp_matrix = cvCreateMatHeader (rows, cols, mat_type);
452                   cvSetData (temp_matrix, raw_data, step);
453                   cvarr = temp_matrix;
454                   
455 //                    fprintf(stderr, "step_size: %ld, type: %ld\n", step, mat_type); fflush (stderr);
456                 }
457               }
458             }
459           }
460         }
461       }
462       
463       Py_DECREF (data);
464       Py_DECREF (typestr);
465       Py_DECREF (shape);
466       Py_DECREF (version);
467     }
468   
469   }
470   
471   Py_DECREF (interface);
472   
473   return cvarr;
474 }
475
476
477 // Convert Python lists to CvMat *
478 CvArr * PySequence_to_CvArr (PyObject * obj)
479 {
480   int        dims     [CV_MAX_DIM]   = {   1,    1,    1};
481   PyObject * container[CV_MAX_DIM+1] = {NULL, NULL, NULL, NULL};
482   int        ndim                    = 0;
483   PyObject * item                    = Py_None;
484   
485   // TODO: implement type detection - currently we create CV_64F only
486   // scan full array to
487   // - figure out dimensions
488   // - check consistency of dimensions
489   // - find appropriate data-type and signedness
490   //  enum NEEDED_DATATYPE { NEEDS_CHAR, NEEDS_INTEGER, NEEDS_FLOAT, NEEDS_DOUBLE };
491   //  NEEDED_DATATYPE needed_datatype = NEEDS_CHAR;
492   //  bool            needs_sign      = false;
493   
494   // scan first entries to find out dimensions
495   for (item = obj, ndim = 0; PySequence_Check (item) && ndim <= CV_MAX_DIM; ndim++)
496   {
497     dims [ndim]      = PySequence_Size    (item);
498     container [ndim] = PySequence_GetItem (item, 0); 
499     item             = container[ndim];
500   }
501   
502   // in contrast to PyTuple_GetItem, PySequence_GetItame returns a NEW reference
503   if (container[0])
504   {
505     Py_DECREF (container[0]);
506   }
507   if (container[1])
508   {
509     Py_DECREF (container[1]);
510   }
511   if (container[2])
512   {
513     Py_DECREF (container[2]);
514   }
515   if (container[3])
516   {
517     Py_DECREF (container[3]);
518   }
519   
520   // it only makes sense to support 2 and 3 dimensional data at this time
521   if (ndim < 2 || ndim > 3)
522   {
523     PyErr_SetString (PyExc_TypeError, "Nested sequences should have 2 or 3 dimensions");
524     return NULL;
525   }
526   
527   // also, the number of channels should match what's typical for OpenCV
528   if (ndim == 3  &&  (dims[2] < 1  ||  dims[2] > 4))
529   {
530     PyErr_SetString (PyExc_TypeError, "Currently, the third dimension of CvMat only supports 1 to 4 channels");
531     return NULL;
532   }
533   
534   // CvMat
535   CvMat * matrix = cvCreateMat (dims[0], dims[1], CV_MAKETYPE (CV_64F, dims[2]));
536   
537   for (int y = 0; y < dims[0]; y++)
538   {
539     PyObject * rowobj = PySequence_GetItem (obj, y);
540     
541     // double check size
542     if (PySequence_Check (rowobj)  &&  PySequence_Size (rowobj) == dims[1])
543     {
544       for (int x = 0; x < dims[1]; x++)
545       {
546         PyObject * colobj = PySequence_GetItem (rowobj, x);
547         
548         if (dims [2] > 1)
549         {
550           if (PySequence_Check (colobj)  &&  PySequence_Size (colobj) == dims[2])
551           {
552             PyObject * tuple = PySequence_Tuple (colobj);
553             
554             double  a, b, c, d;
555             if (PyArg_ParseTuple (colobj, "d|d|d|d", &a, &b, &c, &d))
556             {
557               cvSet2D (matrix, y, x, cvScalar (a, b, c, d));
558             }
559             else 
560             {
561               PyErr_SetString (PyExc_TypeError, "OpenCV only accepts numbers that can be converted to float");
562               cvReleaseMat (& matrix);
563               Py_DECREF (tuple);
564               Py_DECREF (colobj);
565               Py_DECREF (rowobj);
566               return NULL;
567             }
568
569             Py_DECREF (tuple);
570           }
571           else
572           {
573             PyErr_SetString (PyExc_TypeError, "All sub-sequences must have the same number of entries");
574             cvReleaseMat (& matrix);
575             Py_DECREF (colobj);
576             Py_DECREF (rowobj);
577             return NULL;
578           }
579         }
580         else
581         {
582           if (PyFloat_Check (colobj) || PyInt_Check (colobj))
583           {
584             cvmSet (matrix, y, x, PyFloat_AsDouble (colobj));
585           }
586           else
587           {
588             PyErr_SetString (PyExc_TypeError, "OpenCV only accepts numbers that can be converted to float");
589             cvReleaseMat (& matrix);
590             Py_DECREF (colobj);
591             Py_DECREF (rowobj);
592             return NULL;
593           }
594         }
595         
596         Py_DECREF (colobj);
597       }
598     }
599     else
600     {
601       PyErr_SetString (PyExc_TypeError, "All sub-sequences must have the same number of entries");
602       cvReleaseMat (& matrix);
603       Py_DECREF (rowobj);
604       return NULL;
605     }
606     
607     Py_DECREF (rowobj);
608   }
609   
610   return matrix;
611 }