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, ...)
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:
......@@ -199,7 +213,8 @@ NumpyAllocator g_numpyAllocator;
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)
{
......@@ -210,7 +225,7 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>"
if( !PyArray_Check(o) )
{
failmsg("%s is not a numpy array", name);
failmsg("%s is not a numpy array", info.name);
return false;
}
......@@ -223,14 +238,14 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>"
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;
}
......@@ -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);
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++)
{
......@@ -246,20 +275,14 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>"
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]);
......@@ -267,7 +290,7 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>"
if( ndims > 2 && !allowND )
{
failmsg("%s has more than 2 dimensions", name);
failmsg("%s has more than 2 dimensions", info.name);
return false;
}
......@@ -276,18 +299,14 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>"
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;
}
......@@ -593,7 +612,7 @@ static inline PyObject* pyopencv_from(const Point2d& p)
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)
......@@ -601,12 +620,12 @@ template<typename _Tp> struct pyopencvVecConverter
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);
......@@ -635,7 +654,7 @@ template<typename _Tp> struct pyopencvVecConverter
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)))
......@@ -647,7 +666,7 @@ template<typename _Tp> struct pyopencvVecConverter
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);
......@@ -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)
......@@ -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 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);
......@@ -724,7 +743,7 @@ template<typename _Tp> static inline bool pyopencv_to_generic_vec(PyObject* obj,
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);
......@@ -766,9 +785,9 @@ template<typename _Tp> struct pyopencvVecConverter<vector<_Tp> >
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)
......@@ -779,9 +798,9 @@ template<> struct pyopencvVecConverter<Mat>
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)
......@@ -792,9 +811,9 @@ template<> struct pyopencvVecConverter<KeyPoint>
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)
......@@ -805,9 +824,9 @@ template<> struct pyopencvVecConverter<DMatch>
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)
......
......@@ -329,6 +329,9 @@ class ArgInfo(object):
def isbig(self):
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):
def __init__(self, classname, name, decl, isconstructor):
......@@ -561,7 +564,7 @@ class FuncInfo(object):
if amapping[1] == "O":
code_decl += " PyObject* pyobj_%s = NULL;\n" % (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])
......
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