Commit 0adf68ae authored by Alexander Mordvintesv's avatar Alexander Mordvintesv

work on #2100: pyopencv_to functions now can receive argument information…

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.
parent a717b7cb
...@@ -45,6 +45,20 @@ static int failmsg(const char *fmt, ...) ...@@ -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; ...@@ -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>" ...@@ -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>" ...@@ -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>" ...@@ -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>" ...@@ -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>" ...@@ -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>" ...@@ -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) ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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>& ...@@ -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, ...@@ -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> > ...@@ -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> ...@@ -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> ...@@ -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> ...@@ -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): ...@@ -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): ...@@ -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])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment