Update the trunk to the OpenCV's CVS (2008-07-14)
[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     char * chdelim1="", * chdelim2="";
89
90     // only output channel parens if > 1
91     if(nch>1){
92         chdelim1="(";
93         chdelim2=")";
94     }
95
96     fprintf(f,"[");
97     for(i=0; i<rows; i++){
98                 fprintf(f, "[" );
99
100         // first element
101         // out<<chdelim1;
102                 fprintf(f, chdelim1);
103         fprintf(f, fmt, ((T*)(cdata+i*step))[0]);
104         for(k=1; k<nch; k++){
105                         fprintf(f, ", ");
106                         fprintf(f, fmt, ((T*)(cdata+i*step))[k]);
107         }
108                 fprintf(f, chdelim2);
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                                 fprintf(f, ", ");
116                                 fprintf(f, fmt, ((T*)(cdata+i*step+j))[k]);
117             }
118                         fprintf(f, chdelim2);
119         }
120                 fprintf(f, "]\n" );
121     }
122         fprintf(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 double PyObject_AsDouble(PyObject * obj){
277         if(PyNumber_Check(obj)){
278                 if(PyFloat_Check(obj)){
279                         return PyFloat_AsDouble(obj);
280                 }
281                 else if(PyInt_Check(obj) || PyLong_Check(obj)){
282                         return (double) PyLong_AsLong(obj);
283                 }
284         }
285         PyErr_SetString( PyExc_TypeError, "Could not convert python object to Double");
286         return -1;
287 }
288
289 long PyObject_AsLong(PyObject * obj){
290     if(PyNumber_Check(obj)){
291         if(PyFloat_Check(obj)){
292             return (long) PyFloat_AsDouble(obj);
293         }
294         else if(PyInt_Check(obj) || PyLong_Check(obj)){
295             return PyLong_AsLong(obj);
296         }
297     }
298         PyErr_SetString( PyExc_TypeError, "Could not convert python object to Long");
299         return -1;
300 }
301