extended Python bindings; not merged into cv.cpp yet; and many of the helper functions, like pyopencv_to_*, pyopencv_from_* etc. are still missing
This commit is contained in:
356
modules/python/opencv2x.h
Normal file
356
modules/python/opencv2x.h
Normal file
@@ -0,0 +1,356 @@
|
||||
#ifndef OPENCV2X_PYTHON_WRAPPERS
|
||||
#define OPENCV2X_PYTHON_WRAPPERS
|
||||
|
||||
#include "opencv2/core/core.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
#define ERRWRAP2(expr) \
|
||||
try \
|
||||
{ \
|
||||
expr; \
|
||||
} \
|
||||
catch (const cv::Exception &e) \
|
||||
{ \
|
||||
PyErr_SetString(opencv_error, e.what()); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
static size_t REFCOUNT_OFFSET = (size_t)&(((PyObject*)0)->ob_refcnt) +
|
||||
(0x12345678 != *(const size_t*)"\x78\x56\x34\x12\0\0\0\0\0")*sizeof(int);
|
||||
|
||||
static inline PyObject* pyObjectFromRefcount(const int* refcount)
|
||||
{
|
||||
return (PyObject*)((size_t)refcount - REFCOUNT_OFFSET);
|
||||
}
|
||||
|
||||
static inline int* refcountFromPyObject(const PyObject* obj)
|
||||
{
|
||||
return (int*)((size_t)obj + REFCOUNT_OFFSET);
|
||||
}
|
||||
|
||||
class NumpyAllocator : public MatAllocator
|
||||
{
|
||||
public:
|
||||
NumpyAllocator() {}
|
||||
~NumpyAllocator() {}
|
||||
|
||||
void allocate(int dims, const int* sizes, int type, int*& refcount,
|
||||
uchar*& datastart, uchar*& data, size_t* step)
|
||||
{
|
||||
static int ncalls = 0;
|
||||
printf("NumpyAllocator::allocate: %d\n", ncalls++);
|
||||
|
||||
int depth = CV_MAT_DEPTH(type);
|
||||
int cn = CV_MAT_CN(type);
|
||||
const int f = (int)(sizeof(size_t)/8);
|
||||
int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE :
|
||||
depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT :
|
||||
depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT :
|
||||
depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT;
|
||||
int i;
|
||||
npy_intp _sizes[CV_MAX_DIM+1];
|
||||
for( i = 0; i < dims; i++ )
|
||||
_sizes[i] = sizes[i];
|
||||
if( cn > 1 )
|
||||
{
|
||||
if( _sizes[dims-1] == 1 )
|
||||
_sizes[dims-1] = cn;
|
||||
else
|
||||
_sizes[dims++] = cn;
|
||||
}
|
||||
PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum);
|
||||
if(!o)
|
||||
CV_Error_(CV_StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims));
|
||||
refcount = refcountFromPyObject(o);
|
||||
npy_intp* _strides = PyArray_STRIDES(o);
|
||||
for( i = 0; i < dims-1; i++ )
|
||||
step[i] = (size_t)_strides[i];
|
||||
datastart = data = (uchar*)PyArray_DATA(o);
|
||||
}
|
||||
|
||||
void deallocate(int* refcount, uchar* datastart, uchar* data)
|
||||
{
|
||||
static int ncalls = 0;
|
||||
printf("NumpyAllocator::deallocate: %d\n", ncalls++);
|
||||
|
||||
if( !refcount )
|
||||
return;
|
||||
PyObject* o = pyObjectFromRefcount(refcount);
|
||||
Py_DECREF(o);
|
||||
}
|
||||
};
|
||||
|
||||
NumpyAllocator g_numpyAllocator;
|
||||
|
||||
enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 };
|
||||
|
||||
static int pyobjToMat(const PyObject* o, Mat& m, const char* name = "<unknown>", bool allowND=true)
|
||||
{
|
||||
static int call_idx = 0;
|
||||
printf("pyobjToMatND: %d\n", call_idx++);
|
||||
|
||||
if( !PyArray_Check(o) ) {
|
||||
if( o == Py_None )
|
||||
return ARG_NONE;
|
||||
failmsg("%s is not a numpy array", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int typenum = PyArray_TYPE(o);
|
||||
int type = typenum == NPY_UBYTE ? CV_8U : typenum == NPY_BYTE ? CV_8S :
|
||||
typenum == NPY_USHORT ? CV_16U : typenum == NPY_SHORT ? CV_16S :
|
||||
typenum == NPY_INT || typenum == NPY_LONG ? CV_32S :
|
||||
typenum == NPY_FLOAT ? CV_32F :
|
||||
typenum == NPY_DOUBLE ? CV_64F : -1;
|
||||
|
||||
if( type < 0 )
|
||||
{
|
||||
failmsg("%s data type = %d is not supported", name, typenum);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ndims = PyArray_NDIM(o);
|
||||
if(ndims >= CV_MAX_DIM)
|
||||
{
|
||||
failmsg("%s dimensionality (=%d) is too high", name, ndims);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int size[CV_MAX_DIM+1];
|
||||
size_t step[CV_MAX_DIM+1], elemsize = CV_ELEM_SIZE(type);
|
||||
const npy_intp* _sizes = PyArray_DIMS(o);
|
||||
const npy_intp* _strides = PyArray_STRIDES(o);
|
||||
|
||||
for(int i = 0; i < ndims; i++)
|
||||
{
|
||||
size[i] = (int)_sizes[i];
|
||||
step[i] = (size_t)_strides[i];
|
||||
}
|
||||
|
||||
if( ndims == 0 || step[ndims-1] > elemsize ) {
|
||||
size[ndims] = 1;
|
||||
step[ndims] = elemsize;
|
||||
ndims++;
|
||||
}
|
||||
|
||||
m = Mat(ndims, size, type, PyArray_DATA(o), step);
|
||||
|
||||
if (!allowND)
|
||||
{
|
||||
if( ndims <= 2 )
|
||||
;
|
||||
else if( ndims == 3 )
|
||||
{
|
||||
if( size[2] > CV_CN_MAX || step[1] != elemsize*size[2] )
|
||||
{
|
||||
failmsg("%s is not contiguous, thus it can not be interpreted as image", name);
|
||||
return -1;
|
||||
}
|
||||
m.dims--;
|
||||
m.flags = (m.flags & ~CV_MAT_TYPE_MASK) | CV_MAKETYPE(type, size[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
failmsg("%s is not contiguous or has more than 3 dimensions, thus it can not be interpreted as image", name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if( m.data )
|
||||
{
|
||||
m.refcount = refcountFromPyObject(o);
|
||||
++*m.refcount; // protect the original numpy array from deallocation
|
||||
// (since Mat destructor will decrement the reference counter)
|
||||
};
|
||||
m.allocator = &g_numpyAllocator;
|
||||
return ARG_MAT;
|
||||
}
|
||||
|
||||
static void makeEmptyMat(Mat& m)
|
||||
{
|
||||
m = Mat();
|
||||
m.allocator = &g_numpyAllocator;
|
||||
}
|
||||
|
||||
static int pyobjToMat(const PyObject* o, Mat& m, const char* name = "<unknown>")
|
||||
{
|
||||
Mat temp;
|
||||
int code = pyobjToMat(o, temp, name, false);
|
||||
if(code > 0)
|
||||
m = Mat(temp);
|
||||
return code;
|
||||
}
|
||||
|
||||
static int pyobjToScalar(PyObject *o, Scalar& s, const char *name = "<unknown>")
|
||||
{
|
||||
if (PySequence_Check(o)) {
|
||||
PyObject *fi = PySequence_Fast(o, name);
|
||||
if (fi == NULL)
|
||||
return -1;
|
||||
if (4 < PySequence_Fast_GET_SIZE(fi))
|
||||
{
|
||||
failmsg("Scalar value for argument '%s' is longer than 4", name);
|
||||
return -1;
|
||||
}
|
||||
for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(fi); i++) {
|
||||
PyObject *item = PySequence_Fast_GET_ITEM(fi, i);
|
||||
if (PyFloat_Check(item) || PyInt_Check(item)) {
|
||||
s[i] = PyFloat_AsDouble(item);
|
||||
} else {
|
||||
failmsg("Scalar value for argument '%s' is not numeric", name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
Py_DECREF(fi);
|
||||
} else {
|
||||
if (PyFloat_Check(o) || PyInt_Check(o)) {
|
||||
s[0] = PyFloat_AsDouble(o);
|
||||
} else {
|
||||
failmsg("Scalar value for argument '%s' is not numeric", name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return ARG_SCALAR;
|
||||
}
|
||||
|
||||
|
||||
static int pyobjToMatOrScalar(PyObject* obj, Mat& m, Scalar& s, const char* name, bool allowND)
|
||||
{
|
||||
if( PyArray_Check(obj) || (obj == Py_None))
|
||||
return pyobjToMat(obj, m, name, allowND);
|
||||
|
||||
return pyobjToScalar(obj, s, name);
|
||||
}
|
||||
|
||||
static void pyc_add_mm(const Mat& a, const Mat& b, Mat& c, const Mat& mask) { add(a, b, c, mask); }
|
||||
static void pyc_add_ms(const Mat& a, const Scalar& s, Mat& c, const Mat& mask, bool) { add(a, s, c, mask); }
|
||||
static void pyc_subtract_mm(const Mat& a, const Mat& b, Mat& c, const Mat& mask) { subtract(a, b, c, mask); }
|
||||
static void pyc_subtract_ms(const Mat& a, const Scalar& s, Mat& c, const Mat& mask, bool rev)
|
||||
{
|
||||
if( !rev )
|
||||
subtract(a, s, c, mask);
|
||||
else
|
||||
subtract(s, a, c, mask);
|
||||
}
|
||||
|
||||
static void pyc_and_mm(const Mat& a, const Mat& b, Mat& c, const Mat& mask) { bitwise_and(a, b, c, mask); }
|
||||
static void pyc_and_ms(const Mat& a, const Scalar& s, Mat& c, const Mat& mask, bool) { bitwise_and(a, s, c, mask); }
|
||||
static void pyc_or_mm(const Mat& a, const Mat& b, Mat& c, const Mat& mask) { bitwise_or(a, b, c, mask); }
|
||||
static void pyc_or_ms(const Mat& a, const Scalar& s, Mat& c, const Mat& mask, bool) { bitwise_or(a, s, c, mask); }
|
||||
static void pyc_xor_mm(const Mat& a, const Mat& b, Mat& c, const Mat& mask) { bitwise_xor(a, b, c, mask); }
|
||||
static void pyc_xor_ms(const Mat& a, const Scalar& s, Mat& c, const Mat& mask, bool) { bitwise_xor(a, s, c, mask); }
|
||||
static void pyc_absdiff_mm(const Mat& a, const Mat& b, Mat& c, const Mat&) { absdiff(a, b, c); }
|
||||
static void pyc_absdiff_ms(const Mat& a, const Scalar& s, Mat& c, const Mat&, bool) { absdiff(a, s, c); }
|
||||
static void pyc_min_mm(const Mat& a, const Mat& b, Mat& c, const Mat&) { min(a, b, c); }
|
||||
static void pyc_min_ms(const Mat& a, const Scalar& s, Mat& c, const Mat&, bool)
|
||||
{
|
||||
CV_Assert( s.isReal() );
|
||||
min(a, s[0], c);
|
||||
}
|
||||
static void pyc_max_mm(const Mat& a, const Mat& b, Mat& c, const Mat&) { max(a, b, c); }
|
||||
static void pyc_max_ms(const Mat& a, const Scalar& s, Mat& c, const Mat&, bool)
|
||||
{
|
||||
CV_Assert( s.isReal() );
|
||||
max(a, s[0], c);
|
||||
}
|
||||
|
||||
typedef void (*BinaryOp)(const Mat& a, const Mat& b, Mat& c, const Mat& mask);
|
||||
typedef void (*BinaryOpS)(const Mat& a, const Scalar& s, Mat& c, const Mat& mask, bool rev);
|
||||
|
||||
static PyObject *pyopencv_binary_op(PyObject* args, PyObject* kw, BinaryOp binOp, BinaryOpS binOpS, bool supportMask)
|
||||
{
|
||||
PyObject *pysrc1 = 0, *pysrc2 = 0, *pydst = 0, *pymask = 0;
|
||||
Mat src1, src2, dst, mask;
|
||||
Scalar alpha, beta;
|
||||
|
||||
if( supportMask )
|
||||
{
|
||||
const char *keywords[] = { "src1", "src2", "dst", "mask", 0 };
|
||||
if( !PyArg_ParseTupleAndKeywords(args, kw, "OO|OO", (char**)keywords,
|
||||
&pysrc1, &pysrc2, &pydst, &pymask))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *keywords[] = { "src1", "src2", "dst", 0 };
|
||||
if( !PyArg_ParseTupleAndKeywords(args, kw, "OO|O", (char**)keywords,
|
||||
&pysrc1, &pysrc2, &pydst))
|
||||
return 0;
|
||||
}
|
||||
|
||||
int code_src1 = pysrc1 ? pyobjToMatOrScalar(pysrc1, src1, alpha, "src1", true) : -1;
|
||||
int code_src2 = pysrc2 ? pyobjToMatOrScalar(pysrc2, src2, beta, "src2", true) : -1;
|
||||
int code_dst = pydst ? pyobjToMat(pydst, dst, "dst", true) : 0;
|
||||
int code_mask = pymask ? pyobjToMat(pymask, mask, "mask", true) : 0;
|
||||
|
||||
if( code_src1 < 0 || code_src2 < 0 || code_dst < 0 || code_mask < 0 )
|
||||
return 0;
|
||||
|
||||
if( code_src1 == ARG_SCALAR && code_src2 == ARG_SCALAR )
|
||||
{
|
||||
failmsg("Both %s and %s are scalars", "src1", "src2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( code_dst == 0 )
|
||||
makeEmptyMat(dst);
|
||||
|
||||
ERRWRAP2(code_src1 != ARG_SCALAR && code_src2 != ARG_SCALAR ? binOp(src1, src2, dst, mask) :
|
||||
code_src1 != ARG_SCALAR ? binOpS(src2, alpha, dst, mask, true) : binOpS(src1, beta, dst, mask, false));
|
||||
|
||||
PyObject* result = pyObjectFromRefcount(dst.refcount);
|
||||
int D = PyArray_NDIM(result);
|
||||
const npy_intp* sz = PyArray_DIMS(result);
|
||||
|
||||
printf("Result: check = %d, ndims = %d, size = (%d x %d), typenum=%d\n", PyArray_Check(result),
|
||||
D, (int)sz[0], D >= 2 ? (int)sz[1] : 1, PyArray_TYPE(result));
|
||||
|
||||
//Py_INCREF(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_add(PyObject* self, PyObject* args, PyObject* kw)
|
||||
{
|
||||
return pyopencv_binary_op(args, kw, pyc_add_mm, pyc_add_ms, true);
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_subtract(PyObject* self, PyObject* args, PyObject* kw)
|
||||
{
|
||||
return pyopencv_binary_op(args, kw, pyc_subtract_mm, pyc_subtract_ms, true);
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_and(PyObject* self, PyObject* args, PyObject* kw)
|
||||
{
|
||||
return pyopencv_binary_op(args, kw, pyc_and_mm, pyc_and_ms, true);
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_or(PyObject* self, PyObject* args, PyObject* kw)
|
||||
{
|
||||
return pyopencv_binary_op(args, kw, pyc_or_mm, pyc_or_ms, true);
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_xor(PyObject* self, PyObject* args, PyObject* kw)
|
||||
{
|
||||
return pyopencv_binary_op(args, kw, pyc_xor_mm, pyc_xor_ms, true);
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_absdiff(PyObject* self, PyObject* args, PyObject* kw)
|
||||
{
|
||||
return pyopencv_binary_op(args, kw, pyc_absdiff_mm, pyc_absdiff_ms, true);
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_min(PyObject* self, PyObject* args, PyObject* kw)
|
||||
{
|
||||
return pyopencv_binary_op(args, kw, pyc_min_mm, pyc_min_ms, true);
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_max(PyObject* self, PyObject* args, PyObject* kw)
|
||||
{
|
||||
return pyopencv_binary_op(args, kw, pyc_max_mm, pyc_max_ms, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user