module_opencv2.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2012, Willow Garage, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of the Willow Garage nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34 
35 #include "module.hpp"
36 
37 using namespace cv;
38 
39 // These are sucky, sketchy versions of the real things in OpenCV Python,
40 // inferior in every way.
41 
42 static int failmsg(const char *fmt, ...)
43 {
44  char str[1000];
45 
46  va_list ap;
47  va_start(ap, fmt);
48  vsnprintf(str, sizeof(str), fmt, ap);
49  va_end(ap);
50 
51  PyErr_SetString(PyExc_TypeError, str);
52  return 0;
53 }
54 
55 static PyObject* opencv_error = 0;
56 
58 {
59 public:
60  PyAllowThreads() : _state(PyEval_SaveThread()) {}
62  {
63  PyEval_RestoreThread(_state);
64  }
65 private:
66  PyThreadState* _state;
67 };
68 
69 #define ERRWRAP2(expr) \
70 try \
71 { \
72  PyAllowThreads allowThreads; \
73  expr; \
74 } \
75 catch (const cv::Exception &e) \
76 { \
77  PyErr_SetString(opencv_error, e.what()); \
78  return 0; \
79 }
80 
81 // Taken from http://stackoverflow.com/questions/19136944/call-c-opencv-functions-from-python-send-a-cv-mat-to-c-dll-which-is-usi
82 
83 
84 static size_t REFCOUNT_OFFSET = ( size_t )&((( PyObject* )0)->ob_refcnt ) +
85 ( 0x12345678 != *( const size_t* )"\x78\x56\x34\x12\0\0\0\0\0" )*sizeof( int );
86 
87 
88 static inline PyObject* pyObjectFromRefcount( const int* refcount )
89 {
90 return ( PyObject* )(( size_t )refcount - REFCOUNT_OFFSET );
91 }
92 
93 static inline int* refcountFromPyObject( const PyObject* obj )
94 {
95 return ( int* )(( size_t )obj + REFCOUNT_OFFSET );
96 }
97 
98 class NumpyAllocator : public cv::MatAllocator
99 {
100 public:
103 
104 void allocate( int dims, const int* sizes, int type, int*& refcount,
105 uchar*& datastart, uchar*& data, size_t* step );
106 
107 void deallocate( int* refcount, uchar* datastart, uchar* data );
108 };
109 
110 void NumpyAllocator::allocate( int dims, const int* sizes, int type, int*& refcount, uchar*& datastart, uchar*& data, size_t* step )
111 {
112  int depth = CV_MAT_DEPTH( type );
113  int cn = CV_MAT_CN( type );
114  const int f = ( int )( sizeof( size_t )/8 );
115  int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE :
116  depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT :
117  depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT :
118  depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT;
119  int i;
120  npy_intp _sizes[CV_MAX_DIM+1];
121  for( i = 0; i < dims; i++ )
122  _sizes[i] = sizes[i];
123  if( cn > 1 )
124  {
125  /*if( _sizes[dims-1] == 1 )
126  _sizes[dims-1] = cn;
127  else*/
128  _sizes[dims++] = cn;
129  }
130  PyObject* o = PyArray_SimpleNew( dims, _sizes, typenum );
131  if( !o )
132  CV_Error_(CV_StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims));
133  refcount = refcountFromPyObject(o);
134  npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o);
135  for( i = 0; i < dims - (cn > 1); i++ )
136  step[i] = (size_t)_strides[i];
137  datastart = data = (uchar*)PyArray_DATA((PyArrayObject*)o);
138 
139 }
140 
141 void NumpyAllocator::deallocate( int* refcount, uchar* datastart, uchar* data )
142 {
143  if( !refcount )
144  return;
145  PyObject* o = pyObjectFromRefcount(refcount);
146  Py_INCREF(o);
147  Py_DECREF(o);
148 }
149 
150 // Declare the object
152 
153 int convert_to_CvMat2(const PyObject* o, cv::Mat& m)
154 {
155  // to avoid PyArray_Check() to crash even with valid array
156  do_numpy_import();
157 
158  if(!o || o == Py_None)
159  {
160  if( !m.data )
161  m.allocator = &g_numpyAllocator;
162  return true;
163  }
164 
165  if( !PyArray_Check(o) )
166  {
167  failmsg("Not a numpy array");
168  return false;
169  }
170 
171  // NPY_LONG (64 bit) is converted to CV_32S (32 bit)
172  int typenum = PyArray_TYPE((PyArrayObject*) o);
173  int type = typenum == NPY_UBYTE ? CV_8U : typenum == NPY_BYTE ? CV_8S :
174  typenum == NPY_USHORT ? CV_16U : typenum == NPY_SHORT ? CV_16S :
175  typenum == NPY_INT || typenum == NPY_LONG ? CV_32S :
176  typenum == NPY_FLOAT ? CV_32F :
177  typenum == NPY_DOUBLE ? CV_64F : -1;
178 
179  if( type < 0 )
180  {
181  failmsg("data type = %d is not supported", typenum);
182  return false;
183  }
184 
185  int ndims = PyArray_NDIM((PyArrayObject*) o);
186  if(ndims >= CV_MAX_DIM)
187  {
188  failmsg("dimensionality (=%d) is too high", ndims);
189  return false;
190  }
191 
192  int size[CV_MAX_DIM+1];
193  size_t step[CV_MAX_DIM+1], elemsize = CV_ELEM_SIZE1(type);
194  const npy_intp* _sizes = PyArray_DIMS((PyArrayObject*) o);
195  const npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o);
196  bool transposed = false;
197 
198  for(int i = 0; i < ndims; i++)
199  {
200  size[i] = (int)_sizes[i];
201  step[i] = (size_t)_strides[i];
202  }
203 
204  if( ndims == 0 || step[ndims-1] > elemsize ) {
205  size[ndims] = 1;
206  step[ndims] = elemsize;
207  ndims++;
208  }
209 
210  if( ndims >= 2 && step[0] < step[1] )
211  {
212  std::swap(size[0], size[1]);
213  std::swap(step[0], step[1]);
214  transposed = true;
215  }
216 
217  if( ndims == 3 && size[2] <= CV_CN_MAX && step[1] == elemsize*size[2] )
218  {
219  ndims--;
220  type |= CV_MAKETYPE(0, size[2]);
221  }
222 
223  if( ndims > 2 )
224  {
225  failmsg("more than 2 dimensions");
226  return false;
227  }
228 
229  m = cv::Mat(ndims, size, type, PyArray_DATA((PyArrayObject*) o), step);
230 
231  if( m.data )
232  {
233  m.refcount = refcountFromPyObject(o);
234  m.addref(); // protect the original numpy array from deallocation
235  // (since Mat destructor will decrement the reference counter)
236  };
237  m.allocator = &g_numpyAllocator;
238 
239  if( transposed )
240  {
241  cv::Mat tmp;
242  tmp.allocator = &g_numpyAllocator;
243  transpose(m, tmp);
244  m = tmp;
245  }
246  return true;
247 }
248 
249 PyObject* pyopencv_from(const Mat& m)
250 {
251  if( !m.data )
252  Py_RETURN_NONE;
253  Mat temp, *p = (Mat*)&m;
254  if(!p->refcount || p->allocator != &g_numpyAllocator)
255  {
256  temp.allocator = &g_numpyAllocator;
257  ERRWRAP2(m.copyTo(temp));
258  p = &temp;
259  }
260  p->addref();
261  return pyObjectFromRefcount(p->refcount);
262 }
static size_t REFCOUNT_OFFSET
f
static PyObject * opencv_error
static int * refcountFromPyObject(const PyObject *obj)
#define ERRWRAP2(expr)
int convert_to_CvMat2(const PyObject *o, cv::Mat &m)
PyObject * pyopencv_from(const Mat &m)
static int failmsg(const char *fmt,...)
static PyObject * pyObjectFromRefcount(const int *refcount)
void deallocate(int *refcount, uchar *datastart, uchar *data)
PyThreadState * _state
void allocate(int dims, const int *sizes, int type, int *&refcount, uchar *&datastart, uchar *&data, size_t *step)
NumpyAllocator g_numpyAllocator


cv_bridge
Author(s): Patrick Mihelich, James Bowman
autogenerated on Tue Oct 4 2022 02:19:03