mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
work on #2100: pyopencv_to functions now can receive argument information through ArgInfo structure. Non-contiguous input numpy arrays are copied. In case of non-contiguous output array the TypeError is thrown.
This commit is contained in:
parent
a717b7cbed
commit
0adf68ae62
@ -45,6 +45,20 @@ static int failmsg(const char *fmt, ...)
|
|||||||
return 0;
|
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
|
class PyAllowThreads
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -199,7 +213,8 @@ NumpyAllocator g_numpyAllocator;
|
|||||||
|
|
||||||
enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 };
|
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(!o || o == Py_None)
|
||||||
{
|
{
|
||||||
@ -210,7 +225,7 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>"
|
|||||||
|
|
||||||
if( !PyArray_Check(o) )
|
if( !PyArray_Check(o) )
|
||||||
{
|
{
|
||||||
failmsg("%s is not a numpy array", name);
|
failmsg("%s is not a numpy array", info.name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,14 +238,14 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>"
|
|||||||
|
|
||||||
if( type < 0 )
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ndims = PyArray_NDIM(o);
|
int ndims = PyArray_NDIM(o);
|
||||||
if(ndims >= CV_MAX_DIM)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +253,21 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>"
|
|||||||
size_t step[CV_MAX_DIM+1], elemsize = CV_ELEM_SIZE1(type);
|
size_t step[CV_MAX_DIM+1], elemsize = CV_ELEM_SIZE1(type);
|
||||||
const npy_intp* _sizes = PyArray_DIMS(o);
|
const npy_intp* _sizes = PyArray_DIMS(o);
|
||||||
const npy_intp* _strides = PyArray_STRIDES(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++)
|
for(int i = 0; i < ndims; i++)
|
||||||
{
|
{
|
||||||
@ -246,20 +275,14 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>"
|
|||||||
step[i] = (size_t)_strides[i];
|
step[i] = (size_t)_strides[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ndims == 0 || step[ndims-1] > elemsize ) {
|
// handle degenerate case
|
||||||
|
if( ndims == 0) {
|
||||||
size[ndims] = 1;
|
size[ndims] = 1;
|
||||||
step[ndims] = elemsize;
|
step[ndims] = elemsize;
|
||||||
ndims++;
|
ndims++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ndims >= 2 && step[0] < step[1] )
|
if( ismultichannel )
|
||||||
{
|
|
||||||
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] )
|
|
||||||
{
|
{
|
||||||
ndims--;
|
ndims--;
|
||||||
type |= CV_MAKETYPE(0, size[2]);
|
type |= CV_MAKETYPE(0, size[2]);
|
||||||
@ -267,7 +290,7 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>"
|
|||||||
|
|
||||||
if( ndims > 2 && !allowND )
|
if( ndims > 2 && !allowND )
|
||||||
{
|
{
|
||||||
failmsg("%s has more than 2 dimensions", name);
|
failmsg("%s has more than 2 dimensions", info.name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,18 +299,14 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>"
|
|||||||
if( m.data )
|
if( m.data )
|
||||||
{
|
{
|
||||||
m.refcount = refcountFromPyObject(o);
|
m.refcount = refcountFromPyObject(o);
|
||||||
m.addref(); // protect the original numpy array from deallocation
|
if (!needcopy)
|
||||||
// (since Mat destructor will decrement the reference counter)
|
{
|
||||||
|
m.addref(); // protect the original numpy array from deallocation
|
||||||
|
// (since Mat destructor will decrement the reference counter)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
m.allocator = &g_numpyAllocator;
|
m.allocator = &g_numpyAllocator;
|
||||||
|
|
||||||
if( transposed )
|
|
||||||
{
|
|
||||||
Mat tmp;
|
|
||||||
tmp.allocator = &g_numpyAllocator;
|
|
||||||
transpose(m, tmp);
|
|
||||||
m = tmp;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,7 +612,7 @@ static inline PyObject* pyopencv_from(const Point2d& p)
|
|||||||
|
|
||||||
template<typename _Tp> struct pyopencvVecConverter
|
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;
|
typedef typename DataType<_Tp>::channel_type _Cp;
|
||||||
if(!obj || obj == Py_None)
|
if(!obj || obj == Py_None)
|
||||||
@ -601,12 +620,12 @@ template<typename _Tp> struct pyopencvVecConverter
|
|||||||
if (PyArray_Check(obj))
|
if (PyArray_Check(obj))
|
||||||
{
|
{
|
||||||
Mat m;
|
Mat m;
|
||||||
pyopencv_to(obj, m, name);
|
pyopencv_to(obj, m, info);
|
||||||
m.copyTo(value);
|
m.copyTo(value);
|
||||||
}
|
}
|
||||||
if (!PySequence_Check(obj))
|
if (!PySequence_Check(obj))
|
||||||
return false;
|
return false;
|
||||||
PyObject *seq = PySequence_Fast(obj, name);
|
PyObject *seq = PySequence_Fast(obj, info.name);
|
||||||
if (seq == NULL)
|
if (seq == NULL)
|
||||||
return false;
|
return false;
|
||||||
int i, j, n = (int)PySequence_Fast_GET_SIZE(seq);
|
int i, j, n = (int)PySequence_Fast_GET_SIZE(seq);
|
||||||
@ -635,7 +654,7 @@ template<typename _Tp> struct pyopencvVecConverter
|
|||||||
if( PyArray_Check(item))
|
if( PyArray_Check(item))
|
||||||
{
|
{
|
||||||
Mat src;
|
Mat src;
|
||||||
pyopencv_to(item, src, name);
|
pyopencv_to(item, src, info);
|
||||||
if( src.dims != 2 || src.channels() != 1 ||
|
if( src.dims != 2 || src.channels() != 1 ||
|
||||||
((src.cols != 1 || src.rows != channels) &&
|
((src.cols != 1 || src.rows != channels) &&
|
||||||
(src.cols != channels || src.rows != 1)))
|
(src.cols != channels || src.rows != 1)))
|
||||||
@ -647,7 +666,7 @@ template<typename _Tp> struct pyopencvVecConverter
|
|||||||
continue;
|
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 )
|
if( !seq_i || (int)PySequence_Fast_GET_SIZE(seq_i) != channels )
|
||||||
{
|
{
|
||||||
Py_XDECREF(seq_i);
|
Py_XDECREF(seq_i);
|
||||||
@ -694,9 +713,9 @@ template<typename _Tp> struct pyopencvVecConverter
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
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)
|
template<typename _Tp> static inline PyObject* pyopencv_from(const vector<_Tp>& value)
|
||||||
@ -707,13 +726,13 @@ template<typename _Tp> static inline PyObject* pyopencv_from(const vector<_Tp>&
|
|||||||
static PyObject* pyopencv_from(const KeyPoint&);
|
static PyObject* pyopencv_from(const KeyPoint&);
|
||||||
static PyObject* pyopencv_from(const DMatch&);
|
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)
|
if(!obj || obj == Py_None)
|
||||||
return true;
|
return true;
|
||||||
if (!PySequence_Check(obj))
|
if (!PySequence_Check(obj))
|
||||||
return false;
|
return false;
|
||||||
PyObject *seq = PySequence_Fast(obj, name);
|
PyObject *seq = PySequence_Fast(obj, info.name);
|
||||||
if (seq == NULL)
|
if (seq == NULL)
|
||||||
return false;
|
return false;
|
||||||
int i, n = (int)PySequence_Fast_GET_SIZE(seq);
|
int i, n = (int)PySequence_Fast_GET_SIZE(seq);
|
||||||
@ -724,7 +743,7 @@ template<typename _Tp> static inline bool pyopencv_to_generic_vec(PyObject* obj,
|
|||||||
for( i = 0; i < n; i++ )
|
for( i = 0; i < n; i++ )
|
||||||
{
|
{
|
||||||
PyObject* item = items[i];
|
PyObject* item = items[i];
|
||||||
if(!pyopencv_to(item, value[i], name))
|
if(!pyopencv_to(item, value[i], info))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Py_DECREF(seq);
|
Py_DECREF(seq);
|
||||||
@ -766,9 +785,9 @@ template<typename _Tp> struct pyopencvVecConverter<vector<_Tp> >
|
|||||||
|
|
||||||
template<> struct pyopencvVecConverter<Mat>
|
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)
|
static PyObject* from(const vector<Mat>& value)
|
||||||
@ -779,9 +798,9 @@ template<> struct pyopencvVecConverter<Mat>
|
|||||||
|
|
||||||
template<> struct pyopencvVecConverter<KeyPoint>
|
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)
|
static PyObject* from(const vector<KeyPoint>& value)
|
||||||
@ -792,9 +811,9 @@ template<> struct pyopencvVecConverter<KeyPoint>
|
|||||||
|
|
||||||
template<> struct pyopencvVecConverter<DMatch>
|
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)
|
static PyObject* from(const vector<DMatch>& value)
|
||||||
@ -805,9 +824,9 @@ template<> struct pyopencvVecConverter<DMatch>
|
|||||||
|
|
||||||
template<> struct pyopencvVecConverter<string>
|
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)
|
static PyObject* from(const vector<string>& value)
|
||||||
|
@ -329,6 +329,9 @@ class ArgInfo(object):
|
|||||||
def isbig(self):
|
def isbig(self):
|
||||||
return self.tp == "Mat" or self.tp == "vector_Mat"# or self.tp.startswith("vector")
|
return self.tp == "Mat" or self.tp == "vector_Mat"# or self.tp.startswith("vector")
|
||||||
|
|
||||||
|
def crepr(self):
|
||||||
|
return "ArgInfo(\"%s\", %d)" % (self.name, self.outputarg)
|
||||||
|
|
||||||
|
|
||||||
class FuncVariant(object):
|
class FuncVariant(object):
|
||||||
def __init__(self, classname, name, decl, isconstructor):
|
def __init__(self, classname, name, decl, isconstructor):
|
||||||
@ -561,7 +564,7 @@ class FuncInfo(object):
|
|||||||
if amapping[1] == "O":
|
if amapping[1] == "O":
|
||||||
code_decl += " PyObject* pyobj_%s = NULL;\n" % (a.name,)
|
code_decl += " PyObject* pyobj_%s = NULL;\n" % (a.name,)
|
||||||
parse_name = "pyobj_" + a.name
|
parse_name = "pyobj_" + a.name
|
||||||
code_cvt_list.append("pyopencv_to(pyobj_%s, %s)" % (a.name, a.name))
|
code_cvt_list.append("pyopencv_to(pyobj_%s, %s, %s)" % (a.name, a.name, a.crepr()))
|
||||||
|
|
||||||
all_cargs.append([amapping, parse_name])
|
all_cargs.append([amapping, parse_name])
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user