return 0;
}
+struct ArgInfo
+{
+ const char * name;
+ bool outputarg;
+ // more fields may be added if necessary
+
+ ArgInfo(const char * name_, bool outputarg_)
+ : name(name_)
+ , outputarg(outputarg_) {}
+
+ // to match with older pyopencv_to function signature
+ operator const char *() const { return name; }
+};
+
class PyAllowThreads
{
public:
enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 };
-static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>", bool allowND=true)
+// special case, when the convertor needs full ArgInfo structure
+static int pyopencv_to(const PyObject* o, Mat& m, const ArgInfo info, bool allowND=true)
{
if(!o || o == Py_None)
{
if( !PyArray_Check(o) )
{
- failmsg("%s is not a numpy array", name);
+ failmsg("%s is not a numpy array", info.name);
return false;
}
if( type < 0 )
{
- failmsg("%s data type = %d is not supported", name, typenum);
+ failmsg("%s data type = %d is not supported", info.name, typenum);
return false;
}
int ndims = PyArray_NDIM(o);
if(ndims >= CV_MAX_DIM)
{
- failmsg("%s dimensionality (=%d) is too high", name, ndims);
+ failmsg("%s dimensionality (=%d) is too high", info.name, ndims);
return false;
}
size_t step[CV_MAX_DIM+1], elemsize = CV_ELEM_SIZE1(type);
const npy_intp* _sizes = PyArray_DIMS(o);
const npy_intp* _strides = PyArray_STRIDES(o);
- bool transposed = false;
+ bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX;
+
+ bool needcopy = (_strides[ndims-1] != elemsize)
+ || (ismultichannel && _strides[ndims-2] != elemsize*_sizes[ndims-1]);
+
+ if (needcopy)
+ {
+ if (info.outputarg)
+ {
+ failmsg("output array %s is not row-contiguous (step[ndims-1] != elemsize)", info.name);
+ return false;
+ }
+ o = (PyObject*)PyArray_GETCONTIGUOUS((PyArrayObject*)o);
+ _strides = PyArray_STRIDES(o);
+ }
for(int i = 0; i < ndims; i++)
{
step[i] = (size_t)_strides[i];
}
- if( ndims == 0 || step[ndims-1] > elemsize ) {
+ // handle degenerate case
+ if( ndims == 0) {
size[ndims] = 1;
step[ndims] = elemsize;
ndims++;
}
- if( ndims >= 2 && step[0] < step[1] )
- {
- std::swap(size[0], size[1]);
- std::swap(step[0], step[1]);
- transposed = true;
- }
-
- if( ndims == 3 && size[2] <= CV_CN_MAX && step[1] == elemsize*size[2] )
+ if( ismultichannel )
{
ndims--;
type |= CV_MAKETYPE(0, size[2]);
if( ndims > 2 && !allowND )
{
- failmsg("%s has more than 2 dimensions", name);
+ failmsg("%s has more than 2 dimensions", info.name);
return false;
}
if( m.data )
{
m.refcount = refcountFromPyObject(o);
- m.addref(); // protect the original numpy array from deallocation
- // (since Mat destructor will decrement the reference counter)
+ if (!needcopy)
+ {
+ m.addref(); // protect the original numpy array from deallocation
+ // (since Mat destructor will decrement the reference counter)
+ }
};
m.allocator = &g_numpyAllocator;
- if( transposed )
- {
- Mat tmp;
- tmp.allocator = &g_numpyAllocator;
- transpose(m, tmp);
- m = tmp;
- }
return true;
}
template<typename _Tp> struct pyopencvVecConverter
{
- static bool to(PyObject* obj, vector<_Tp>& value, const char* name="<unknown>")
+ static bool to(PyObject* obj, vector<_Tp>& value, const ArgInfo info)
{
typedef typename DataType<_Tp>::channel_type _Cp;
if(!obj || obj == Py_None)
if (PyArray_Check(obj))
{
Mat m;
- pyopencv_to(obj, m, name);
+ pyopencv_to(obj, m, info);
m.copyTo(value);
}
if (!PySequence_Check(obj))
return false;
- PyObject *seq = PySequence_Fast(obj, name);
+ PyObject *seq = PySequence_Fast(obj, info.name);
if (seq == NULL)
return false;
int i, j, n = (int)PySequence_Fast_GET_SIZE(seq);
if( PyArray_Check(item))
{
Mat src;
- pyopencv_to(item, src, name);
+ pyopencv_to(item, src, info);
if( src.dims != 2 || src.channels() != 1 ||
((src.cols != 1 || src.rows != channels) &&
(src.cols != channels || src.rows != 1)))
continue;
}
- seq_i = PySequence_Fast(item, name);
+ seq_i = PySequence_Fast(item, info.name);
if( !seq_i || (int)PySequence_Fast_GET_SIZE(seq_i) != channels )
{
Py_XDECREF(seq_i);
};
-template<typename _Tp> static inline bool pyopencv_to(PyObject* obj, vector<_Tp>& value, const char* name="<unknown>")
+template<typename _Tp> static inline bool pyopencv_to(PyObject* obj, vector<_Tp>& value, const ArgInfo info)
{
- return pyopencvVecConverter<_Tp>::to(obj, value, name);
+ return pyopencvVecConverter<_Tp>::to(obj, value, info);
}
template<typename _Tp> static inline PyObject* pyopencv_from(const vector<_Tp>& value)
static PyObject* pyopencv_from(const KeyPoint&);
static PyObject* pyopencv_from(const DMatch&);
-template<typename _Tp> static inline bool pyopencv_to_generic_vec(PyObject* obj, vector<_Tp>& value, const char* name="<unknown>")
+template<typename _Tp> static inline bool pyopencv_to_generic_vec(PyObject* obj, vector<_Tp>& value, const ArgInfo info)
{
if(!obj || obj == Py_None)
return true;
if (!PySequence_Check(obj))
return false;
- PyObject *seq = PySequence_Fast(obj, name);
+ PyObject *seq = PySequence_Fast(obj, info.name);
if (seq == NULL)
return false;
int i, n = (int)PySequence_Fast_GET_SIZE(seq);
for( i = 0; i < n; i++ )
{
PyObject* item = items[i];
- if(!pyopencv_to(item, value[i], name))
+ if(!pyopencv_to(item, value[i], info))
break;
}
Py_DECREF(seq);
template<> struct pyopencvVecConverter<Mat>
{
- static bool to(PyObject* obj, vector<Mat>& value, const char* name="<unknown>")
+ static bool to(PyObject* obj, vector<Mat>& value, const ArgInfo info)
{
- return pyopencv_to_generic_vec(obj, value, name);
+ return pyopencv_to_generic_vec(obj, value, info);
}
static PyObject* from(const vector<Mat>& value)
template<> struct pyopencvVecConverter<KeyPoint>
{
- static bool to(PyObject* obj, vector<KeyPoint>& value, const char* name="<unknown>")
+ static bool to(PyObject* obj, vector<KeyPoint>& value, const ArgInfo info)
{
- return pyopencv_to_generic_vec(obj, value, name);
+ return pyopencv_to_generic_vec(obj, value, info);
}
static PyObject* from(const vector<KeyPoint>& value)
template<> struct pyopencvVecConverter<DMatch>
{
- static bool to(PyObject* obj, vector<DMatch>& value, const char* name="<unknown>")
+ static bool to(PyObject* obj, vector<DMatch>& value, const ArgInfo info)
{
- return pyopencv_to_generic_vec(obj, value, name);
+ return pyopencv_to_generic_vec(obj, value, info);
}
static PyObject* from(const vector<DMatch>& value)
template<> struct pyopencvVecConverter<string>
{
- static bool to(PyObject* obj, vector<string>& value, const char* name="<unknown>")
+ static bool to(PyObject* obj, vector<string>& value, const ArgInfo info)
{
- return pyopencv_to_generic_vec(obj, value, name);
+ return pyopencv_to_generic_vec(obj, value, info);
}
static PyObject* from(const vector<string>& value)