separated opencv 1.x and opencv 2.x wrappers. moved tests/python/* to modules/python/test

This commit is contained in:
Vadim Pisarevsky
2011-05-03 16:00:31 +00:00
parent 0c9e5f6c9c
commit 7f7965bc93
19 changed files with 4614 additions and 6993 deletions

845
modules/python/src2/cv2.cpp Normal file
View File

@@ -0,0 +1,845 @@
#include <Python.h>
#if !PYTHON_USE_NUMPY
#error "The module can only be built if NumPy is available"
#endif
#define MODULESTR "cv2"
#include "numpy/ndarrayobject.h"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/ml/ml.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/video/tracking.hpp"
#include "opencv2/video/background_segm.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv_extra_api.hpp"
static PyObject* opencv_error = 0;
static int failmsg(const char *fmt, ...)
{
char str[1000];
va_list ap;
va_start(ap, fmt);
vsnprintf(str, sizeof(str), fmt, ap);
va_end(ap);
PyErr_SetString(PyExc_TypeError, str);
return 0;
}
#define ERRWRAP2(expr) \
try \
{ \
expr; \
} \
catch (const cv::Exception &e) \
{ \
PyErr_SetString(opencv_error, e.what()); \
return 0; \
}
using namespace cv;
typedef vector<uchar> vector_uchar;
typedef vector<int> vector_int;
typedef vector<float> vector_float;
typedef vector<double> vector_double;
typedef vector<Point> vector_Point;
typedef vector<Point2f> vector_Point2f;
typedef vector<Vec2f> vector_Vec2f;
typedef vector<Vec3f> vector_Vec3f;
typedef vector<Vec4i> vector_Vec4i;
typedef vector<Rect> vector_Rect;
typedef vector<KeyPoint> vector_KeyPoint;
typedef vector<Mat> vector_Mat;
typedef vector<vector<Point> > vector_vector_Point;
typedef vector<vector<Point2f> > vector_vector_Point2f;
typedef vector<vector<Point3f> > vector_vector_Point3f;
static PyObject* failmsgp(const char *fmt, ...)
{
char str[1000];
va_list ap;
va_start(ap, fmt);
vsnprintf(str, sizeof(str), fmt, ap);
va_end(ap);
PyErr_SetString(PyExc_TypeError, str);
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)
{
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 - (cn > 1); i++ )
step[i] = (size_t)_strides[i];
datastart = data = (uchar*)PyArray_DATA(o);
}
void deallocate(int* refcount, uchar* datastart, uchar* data)
{
if( !refcount )
return;
PyObject* o = pyObjectFromRefcount(refcount);
Py_INCREF(o);
Py_DECREF(o);
}
};
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)
{
if(!o || o == Py_None)
{
if( !m.data )
m.allocator = &g_numpyAllocator;
return true;
}
if( !PyArray_Check(o) )
{
failmsg("%s is not a numpy array", name);
return false;
}
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 false;
}
int ndims = PyArray_NDIM(o);
if(ndims >= CV_MAX_DIM)
{
failmsg("%s dimensionality (=%d) is too high", name, ndims);
return false;
}
int size[CV_MAX_DIM+1];
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);
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++;
}
if( ndims == 3 && size[2] <= CV_CN_MAX && step[1] == elemsize*size[2] )
{
ndims--;
type |= CV_MAKETYPE(0, size[2]);
}
if( ndims > 2 && !allowND )
{
failmsg("%s has more than 2 dimensions", name);
return false;
}
m = Mat(ndims, size, type, PyArray_DATA(o), step);
if( m.data )
{
m.refcount = refcountFromPyObject(o);
m.addref(); // protect the original numpy array from deallocation
// (since Mat destructor will decrement the reference counter)
};
m.allocator = &g_numpyAllocator;
return true;
}
static PyObject* pyopencv_from(const Mat& m)
{
Mat temp, *p = (Mat*)&m;
if(!p->refcount || p->allocator != &g_numpyAllocator)
{
pyopencv_to(Py_None, temp);
m.copyTo(temp);
p = &temp;
}
p->addref();
return pyObjectFromRefcount(p->refcount);
}
static bool pyopencv_to(PyObject *o, Scalar& s, const char *name = "<unknown>")
{
if(!o || o == Py_None)
return true;
if (PySequence_Check(o)) {
PyObject *fi = PySequence_Fast(o, name);
if (fi == NULL)
return false;
if (4 < PySequence_Fast_GET_SIZE(fi))
{
failmsg("Scalar value for argument '%s' is longer than 4", name);
return false;
}
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 false;
}
}
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 false;
}
}
return true;
}
static inline PyObject* pyopencv_from(const Scalar& src)
{
return Py_BuildValue("(dddd)", src[0], src[1], src[2], src[3]);
}
static PyObject* pyopencv_from(bool value)
{
return PyBool_FromLong(value);
}
static bool pyopencv_to(PyObject* obj, bool& value, const char* name = "<unknown>")
{
if(!obj || obj == Py_None)
return true;
int _val = PyObject_IsTrue(obj);
if(_val < 0)
return false;
value = _val > 0;
return true;
}
static PyObject* pyopencv_from(size_t value)
{
return PyLong_FromUnsignedLong((unsigned long)value);
}
static PyObject* pyopencv_from(int value)
{
return PyInt_FromLong(value);
}
static bool pyopencv_to(PyObject* obj, int& value, const char* name = "<unknown>")
{
if(!obj || obj == Py_None)
return true;
value = (int)PyInt_AsLong(obj);
return value != -1 || !PyErr_Occurred();
}
static PyObject* pyopencv_from(double value)
{
return PyFloat_FromDouble(value);
}
static bool pyopencv_to(PyObject* obj, double& value, const char* name = "<unknown>")
{
if(!obj || obj == Py_None)
return true;
if(PyInt_CheckExact(obj))
value = (double)PyInt_AS_LONG(obj);
else
value = PyFloat_AsDouble(obj);
return !PyErr_Occurred();
}
static PyObject* pyopencv_from(float value)
{
return PyFloat_FromDouble(value);
}
static bool pyopencv_to(PyObject* obj, float& value, const char* name = "<unknown>")
{
if(!obj || obj == Py_None)
return true;
if(PyInt_CheckExact(obj))
value = (float)PyInt_AS_LONG(obj);
else
value = (float)PyFloat_AsDouble(obj);
return !PyErr_Occurred();
}
static PyObject* pyopencv_from(const string& value)
{
return PyString_FromString(value.empty() ? "" : value.c_str());
}
static bool pyopencv_to(PyObject* obj, string& value, const char* name = "<unknown>")
{
if(!obj || obj == Py_None)
return true;
char* str = PyString_AsString(obj);
if(!str)
return false;
value = string(str);
return true;
}
static inline bool pyopencv_to(PyObject* obj, Size& sz, const char* name = "<unknown>")
{
if(!obj || obj == Py_None)
return true;
return PyArg_Parse(obj, "ii", &sz.width, &sz.height) > 0;
}
static inline PyObject* pyopencv_from(const Size& sz)
{
return Py_BuildValue("(ii)", sz.width, sz.height);
}
static inline bool pyopencv_to(PyObject* obj, Rect& r, const char* name = "<unknown>")
{
if(!obj || obj == Py_None)
return true;
return PyArg_Parse(obj, "iiii", &r.x, &r.y, &r.width, &r.height) > 0;
}
static inline PyObject* pyopencv_from(const Rect& r)
{
return Py_BuildValue("(iiii)", r.x, r.y, r.width, r.height);
}
static inline bool pyopencv_to(PyObject* obj, Range& r, const char* name = "<unknown>")
{
if(!obj || obj == Py_None)
return true;
if(PyObject_Size(obj) == 0)
{
r = Range::all();
return true;
}
return PyArg_Parse(obj, "ii", &r.start, &r.end) > 0;
}
static inline PyObject* pyopencv_from(const Range& r)
{
return Py_BuildValue("(ii)", r.start, r.end);
}
static inline bool pyopencv_to(PyObject* obj, CvSlice& r, const char* name = "<unknown>")
{
if(!obj || obj == Py_None)
return true;
if(PyObject_Size(obj) == 0)
{
r = CV_WHOLE_SEQ;
return true;
}
return PyArg_Parse(obj, "ii", &r.start_index, &r.end_index) > 0;
}
static inline PyObject* pyopencv_from(const CvSlice& r)
{
return Py_BuildValue("(ii)", r.start_index, r.end_index);
}
static inline bool pyopencv_to(PyObject* obj, Point& p, const char* name = "<unknown>")
{
if(!obj || obj == Py_None)
return true;
if(PyComplex_CheckExact(obj))
{
Py_complex c = PyComplex_AsCComplex(obj);
p.x = saturate_cast<int>(c.real);
p.y = saturate_cast<int>(c.imag);
return true;
}
return PyArg_Parse(obj, "ii", &p.x, &p.y) > 0;
}
static inline bool pyopencv_to(PyObject* obj, Point2f& p, const char* name = "<unknown>")
{
if(!obj || obj == Py_None)
return true;
if(PyComplex_CheckExact(obj))
{
Py_complex c = PyComplex_AsCComplex(obj);
p.x = saturate_cast<float>(c.real);
p.y = saturate_cast<float>(c.imag);
return true;
}
return PyArg_Parse(obj, "ff", &p.x, &p.y) > 0;
}
static inline PyObject* pyopencv_from(const Point& p)
{
return Py_BuildValue("(ii)", p.x, p.y);
}
static inline PyObject* pyopencv_from(const Point2f& p)
{
return Py_BuildValue("(dd)", p.x, p.y);
}
static inline bool pyopencv_to(PyObject* obj, Vec3d& v, const char* name = "<unknown>")
{
if(!obj)
return true;
return PyArg_Parse(obj, "ddd", &v[0], &v[1], &v[2]) > 0;
}
static inline PyObject* pyopencv_from(const Vec3d& v)
{
return Py_BuildValue("(ddd)", v[0], v[1], v[2]);
}
static inline PyObject* pyopencv_from(const Point2d& p)
{
return Py_BuildValue("(dd)", p.x, p.y);
}
template<typename _Tp> struct pyopencvVecConverter
{
static bool to(PyObject* obj, vector<_Tp>& value, const char* name="<unknown>")
{
typedef typename DataType<_Tp>::channel_type _Cp;
if(!obj)
return true;
if (PyArray_Check(obj))
{
Mat m;
pyopencv_to(obj, m, name);
m.copyTo(value);
}
if (!PySequence_Check(obj))
return false;
PyObject *seq = PySequence_Fast(obj, name);
if (seq == NULL)
return false;
int i, j, n = (int)PySequence_Fast_GET_SIZE(seq);
value.resize(n);
int type = DataType<_Tp>::type;
int depth = CV_MAT_DEPTH(type), channels = CV_MAT_CN(type);
PyObject** items = PySequence_Fast_ITEMS(seq);
for( i = 0; i < n; i++ )
{
PyObject* item = items[i];
PyObject* seq_i = 0;
PyObject** items_i = &item;
_Cp* data = (_Cp*)&value[i];
if( channels == 2 && PyComplex_CheckExact(item) )
{
Py_complex c = PyComplex_AsCComplex(obj);
data[0] = saturate_cast<_Cp>(c.real);
data[1] = saturate_cast<_Cp>(c.imag);
continue;
}
if( channels > 1 )
{
if( PyArray_Check(obj))
{
Mat src;
pyopencv_to(obj, src, name);
if( src.dims != 2 || src.channels() != 1 ||
((src.cols != 1 || src.rows != channels) &&
(src.cols != channels || src.rows != 1)))
break;
Mat dst(src.rows, src.cols, depth, data);
src.convertTo(dst, type);
if( dst.data != (uchar*)data )
break;
continue;
}
seq_i = PySequence_Fast(item, name);
if( !seq_i || (int)PySequence_Fast_GET_SIZE(seq_i) != channels )
{
Py_XDECREF(seq_i);
break;
}
items_i = PySequence_Fast_ITEMS(seq_i);
}
for( j = 0; j < channels; j++ )
{
PyObject* item_ij = items_i[j];
if( PyInt_Check(item_ij))
{
int v = PyInt_AsLong(item_ij);
if( v == -1 && PyErr_Occurred() )
break;
data[j] = saturate_cast<_Cp>(v);
}
else if( PyFloat_Check(item_ij))
{
double v = PyFloat_AsDouble(item_ij);
if( PyErr_Occurred() )
break;
data[j] = saturate_cast<_Cp>(v);
}
else
break;
}
Py_XDECREF(seq_i);
if( j < channels )
break;
}
Py_DECREF(seq);
return i == n;
}
static PyObject* from(const vector<_Tp>& value)
{
if(value.empty())
return PyTuple_New(0);
Mat src((int)value.size(), DataType<_Tp>::channels, DataType<_Tp>::depth, (uchar*)&value[0]);
return pyopencv_from(src);
}
};
template<typename _Tp> static inline bool pyopencv_to(PyObject* obj, vector<_Tp>& value, const char* name="<unknown>")
{
return pyopencvVecConverter<_Tp>::to(obj, value, name);
}
template<typename _Tp> static inline PyObject* pyopencv_from(const vector<_Tp>& value)
{
return pyopencvVecConverter<_Tp>::from(value);
}
static PyObject* pyopencv_from(const KeyPoint&);
template<typename _Tp> static inline bool pyopencv_to_generic_vec(PyObject* obj, vector<_Tp>& value, const char* name="<unknown>")
{
if (!PySequence_Check(obj))
return false;
PyObject *seq = PySequence_Fast(obj, name);
if (seq == NULL)
return false;
int i, n = (int)PySequence_Fast_GET_SIZE(seq);
value.resize(n);
PyObject** items = PySequence_Fast_ITEMS(seq);
for( i = 0; i < n; i++ )
{
PyObject* item = items[i];
if(!pyopencv_to(item, value[i], name))
break;
}
Py_DECREF(seq);
return i == n;
}
template<typename _Tp> static inline PyObject* pyopencv_from_generic_vec(const vector<_Tp>& value)
{
int i, n = (int)value.size();
PyObject* seq = PyTuple_New(n);
for( i = 0; i < n; i++ )
{
PyObject* item = pyopencv_from(value[i]);
if(!item)
break;
PyTuple_SET_ITEM(seq, i, item);
}
if( i < n )
{
Py_DECREF(seq);
return 0;
}
return seq;
}
template<typename _Tp> struct pyopencvVecConverter<vector<_Tp> >
{
static bool to(PyObject* obj, vector<vector<_Tp> >& value, const char* name="<unknown>")
{
return pyopencv_to_generic_vec(obj, value, name);
}
static PyObject* from(const vector<vector<_Tp> >& value)
{
return pyopencv_from_generic_vec(value);
}
};
template<> struct pyopencvVecConverter<Mat>
{
static bool to(PyObject* obj, vector<Mat>& value, const char* name="<unknown>")
{
return pyopencv_to_generic_vec(obj, value, name);
}
static PyObject* from(const vector<Mat>& value)
{
return pyopencv_from_generic_vec(value);
}
};
template<> struct pyopencvVecConverter<KeyPoint>
{
static bool to(PyObject* obj, vector<KeyPoint>& value, const char* name="<unknown>")
{
return pyopencv_to_generic_vec(obj, value, name);
}
static PyObject* from(const vector<KeyPoint>& value)
{
return pyopencv_from_generic_vec(value);
}
};
static inline bool pyopencv_to(PyObject *obj, CvTermCriteria& dst, const char *name="<unknown>")
{
if(!obj)
return true;
return PyArg_ParseTuple(obj, "iid", &dst.type, &dst.max_iter, &dst.epsilon) > 0;
}
static inline PyObject* pyopencv_from(const CvTermCriteria& src)
{
return Py_BuildValue("(iid)", src.type, src.max_iter, src.epsilon);
}
static inline bool pyopencv_to(PyObject *obj, TermCriteria& dst, const char *name="<unknown>")
{
if(!obj)
return true;
return PyArg_ParseTuple(obj, "iid", &dst.type, &dst.maxCount, &dst.epsilon) > 0;
}
static inline PyObject* pyopencv_from(const TermCriteria& src)
{
return Py_BuildValue("(iid)", src.type, src.maxCount, src.epsilon);
}
static inline bool pyopencv_to(PyObject *obj, RotatedRect& dst, const char *name="<unknown>")
{
if(!obj)
return true;
return PyArg_ParseTuple(obj, "(ff)(ff)f", &dst.center.x, &dst.center.y, &dst.size.width, &dst.size.height, &dst.angle) > 0;
}
static inline PyObject* pyopencv_from(const RotatedRect& src)
{
return Py_BuildValue("((ff)(ff)f)", src.center.x, src.center.y, src.size.width, src.size.height, src.angle);
}
static inline PyObject* pyopencv_from(const Moments& m)
{
return Py_BuildValue("{s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d}",
"m00", m.m00, "m10", m.m10, "m01", m.m01,
"m20", m.m20, "m11", m.m11, "m02", m.m02,
"m30", m.m30, "m21", m.m21, "m12", m.m12, "m03", m.m03,
"mu20", m.mu20, "mu11", m.mu11, "mu02", m.mu02,
"mu30", m.mu30, "mu21", m.mu21, "mu12", m.mu12, "mu03", m.mu03,
"nu20", m.nu20, "nu11", m.nu11, "nu02", m.nu02,
"nu30", m.nu30, "nu21", m.nu21, "nu12", m.nu12, "mu03", m.nu03);
}
static inline PyObject* pyopencv_from(const CvDTreeNode* node)
{
double value = node->value;
int ivalue = cvRound(value);
return value == ivalue ? PyInt_FromLong(ivalue) : PyFloat_FromDouble(value);
}
#define MKTYPE2(NAME) pyopencv_##NAME##_specials(); if (!to_ok(&pyopencv_##NAME##_Type)) return
#include "pyopencv_generated_types.h"
#include "pyopencv_generated_funcs.h"
static PyMethodDef methods[] = {
#include "pyopencv_generated_func_tab.h"
{NULL, NULL},
};
/************************************************************************/
/* Module init */
static int to_ok(PyTypeObject *to)
{
to->tp_alloc = PyType_GenericAlloc;
to->tp_new = PyType_GenericNew;
to->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
return (PyType_Ready(to) == 0);
}
extern "C"
#if defined WIN32 || defined _WIN32
__declspec(dllexport)
#endif
void initcv2()
{
#if PYTHON_USE_NUMPY
import_array();
#endif
#if PYTHON_USE_NUMPY
#include "pyopencv_generated_type_reg.h"
#endif
PyObject* m = Py_InitModule(MODULESTR"", methods);
PyObject* d = PyModule_GetDict(m);
PyDict_SetItemString(d, "__version__", PyString_FromString("$Rev: 4557 $"));
opencv_error = PyErr_NewException((char*)MODULESTR".error", NULL, NULL);
PyDict_SetItemString(d, "error", opencv_error);
// AFAIK the only floating-point constant
PyDict_SetItemString(d, "CV_PI", PyFloat_FromDouble(CV_PI));
#define PUBLISH(I) PyDict_SetItemString(d, #I, PyInt_FromLong(I))
#define PUBLISHU(I) PyDict_SetItemString(d, #I, PyLong_FromUnsignedLong(I))
#define PUBLISH2(I, value) PyDict_SetItemString(d, #I, PyLong_FromLong(value))
PUBLISHU(IPL_DEPTH_8U);
PUBLISHU(IPL_DEPTH_8S);
PUBLISHU(IPL_DEPTH_16U);
PUBLISHU(IPL_DEPTH_16S);
PUBLISHU(IPL_DEPTH_32S);
PUBLISHU(IPL_DEPTH_32F);
PUBLISHU(IPL_DEPTH_64F);
PUBLISH(CV_LOAD_IMAGE_COLOR);
PUBLISH(CV_LOAD_IMAGE_GRAYSCALE);
PUBLISH(CV_LOAD_IMAGE_UNCHANGED);
PUBLISH(CV_HIST_ARRAY);
PUBLISH(CV_HIST_SPARSE);
PUBLISH(CV_8U);
PUBLISH(CV_8UC1);
PUBLISH(CV_8UC2);
PUBLISH(CV_8UC3);
PUBLISH(CV_8UC4);
PUBLISH(CV_8S);
PUBLISH(CV_8SC1);
PUBLISH(CV_8SC2);
PUBLISH(CV_8SC3);
PUBLISH(CV_8SC4);
PUBLISH(CV_16U);
PUBLISH(CV_16UC1);
PUBLISH(CV_16UC2);
PUBLISH(CV_16UC3);
PUBLISH(CV_16UC4);
PUBLISH(CV_16S);
PUBLISH(CV_16SC1);
PUBLISH(CV_16SC2);
PUBLISH(CV_16SC3);
PUBLISH(CV_16SC4);
PUBLISH(CV_32S);
PUBLISH(CV_32SC1);
PUBLISH(CV_32SC2);
PUBLISH(CV_32SC3);
PUBLISH(CV_32SC4);
PUBLISH(CV_32F);
PUBLISH(CV_32FC1);
PUBLISH(CV_32FC2);
PUBLISH(CV_32FC3);
PUBLISH(CV_32FC4);
PUBLISH(CV_64F);
PUBLISH(CV_64FC1);
PUBLISH(CV_64FC2);
PUBLISH(CV_64FC3);
PUBLISH(CV_64FC4);
PUBLISH(CV_NEXT_AROUND_ORG);
PUBLISH(CV_NEXT_AROUND_DST);
PUBLISH(CV_PREV_AROUND_ORG);
PUBLISH(CV_PREV_AROUND_DST);
PUBLISH(CV_NEXT_AROUND_LEFT);
PUBLISH(CV_NEXT_AROUND_RIGHT);
PUBLISH(CV_PREV_AROUND_LEFT);
PUBLISH(CV_PREV_AROUND_RIGHT);
PUBLISH(CV_WINDOW_AUTOSIZE);
PUBLISH(CV_PTLOC_INSIDE);
PUBLISH(CV_PTLOC_ON_EDGE);
PUBLISH(CV_PTLOC_VERTEX);
PUBLISH(CV_PTLOC_OUTSIDE_RECT);
PUBLISH(GC_BGD);
PUBLISH(GC_FGD);
PUBLISH(GC_PR_BGD);
PUBLISH(GC_PR_FGD);
PUBLISH(GC_INIT_WITH_RECT);
PUBLISH(GC_INIT_WITH_MASK);
PUBLISH(GC_EVAL);
#include "pyopencv_generated_const_reg.h"
}

759
modules/python/src2/gen2.py Normal file
View File

@@ -0,0 +1,759 @@
import hdr_parser, sys, re, os, cStringIO
from string import Template
gen_template_check_self = Template(""" if(!PyObject_TypeCheck(self, &pyopencv_${name}_Type))
return failmsgp("Incorrect type of self (must be '${name}' or its derivative)");
$cname* _self_ = ${amp}((pyopencv_${name}_t*)self)->v;
""")
gen_template_call_constructor = Template("""self = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
if(self) ERRWRAP2(self->v = $op$cname""")
gen_template_parse_args = Template("""const char* keywords[] = { $kw_list, NULL };
if( PyArg_ParseTupleAndKeywords(args, kw, "$fmtspec", (char**)keywords, $parse_arglist)$code_cvt )""")
gen_template_func_body = Template("""$code_decl
$code_parse
{
$code_fcall;
$code_ret;
}
""")
gen_template_simple_type_decl = Template("""
struct pyopencv_${name}_t
{
PyObject_HEAD
${cname} v;
};
static PyTypeObject pyopencv_${name}_Type =
{
PyObject_HEAD_INIT(&PyType_Type)
0,
MODULESTR".$wname",
sizeof(pyopencv_${name}_t),
};
static void pyopencv_${name}_dealloc(PyObject* self)
{
PyObject_Del(self);
}
static PyObject* pyopencv_from(const ${cname}& r)
{
pyopencv_${name}_t *m = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
m->v = r;
return (PyObject*)m;
}
static bool pyopencv_to(PyObject* src, ${cname}& dst, const char* name="<unknown>")
{
if( src == NULL || src == Py_None )
return true;
if(!PyObject_TypeCheck(src, &pyopencv_${name}_Type))
{
failmsg("Expected ${cname} for argument '%s'", name);
return false;
}
dst = ((pyopencv_${name}_t*)src)->v;
return true;
}
""")
gen_template_type_decl = Template("""
struct pyopencv_${name}_t
{
PyObject_HEAD
${cname}* v;
};
static PyTypeObject pyopencv_${name}_Type =
{
PyObject_HEAD_INIT(&PyType_Type)
0,
MODULESTR".$wname",
sizeof(pyopencv_${name}_t),
};
static void pyopencv_${name}_dealloc(PyObject* self)
{
delete ((pyopencv_${name}_t*)self)->v;
PyObject_Del(self);
}
""")
gen_template_map_type_cvt = Template("""
static bool pyopencv_to(PyObject* src, ${cname}& dst, const char* name="<unknown>");
""")
gen_template_set_prop_from_map = Template("""
if( PyMapping_HasKeyString(src, (char*)"$propname") )
{
tmp = PyMapping_GetItemString(src, (char*)"$propname");
ok = tmp && pyopencv_to(tmp, dst.$propname);
Py_DECREF(tmp);
if(!ok) return false;
}""")
gen_template_type_impl = Template("""
static PyObject* pyopencv_${name}_repr(PyObject* self)
{
char str[1000];
sprintf(str, "<$wname %p>", self);
return PyString_FromString(str);
}
${getset_code}
static PyGetSetDef pyopencv_${name}_getseters[] =
{${getset_inits}
{NULL} /* Sentinel */
};
${methods_code}
static PyMethodDef pyopencv_${name}_methods[] =
{
${methods_inits}
{NULL, NULL}
};
static void pyopencv_${name}_specials(void)
{
pyopencv_${name}_Type.tp_base = ${baseptr};
pyopencv_${name}_Type.tp_dealloc = pyopencv_${name}_dealloc;
pyopencv_${name}_Type.tp_repr = pyopencv_${name}_repr;
pyopencv_${name}_Type.tp_getset = pyopencv_${name}_getseters;
pyopencv_${name}_Type.tp_methods = pyopencv_${name}_methods;${extra_specials}
}
""")
gen_template_get_prop = Template("""
static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *closure)
{
return pyopencv_from(p->v${access}${member});
}
""")
gen_template_set_prop = Template("""
static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value, void *closure)
{
if (value == NULL)
{
PyErr_SetString(PyExc_TypeError, "Cannot delete the ${member} attribute");
return -1;
}
return pyopencv_to(value, p->v${access}${member}) ? 0 : -1;
}
""")
gen_template_prop_init = Template("""
{(char*)"${member}", (getter)pyopencv_${name}_get_${member}, NULL, (char*)"${member}", NULL},""")
gen_template_rw_prop_init = Template("""
{(char*)"${member}", (getter)pyopencv_${name}_get_${member}, (setter)pyopencv_${name}_set_${member}, (char*)"${member}", NULL},""")
simple_argtype_mapping = {
"bool": ("bool", "b", "0"),
"int": ("int", "i", "0"),
"float": ("float", "f", "0.f"),
"double": ("double", "d", "0"),
"c_string": ("char*", "s", '""')
}
class ClassProp(object):
def __init__(self, decl):
self.tp = decl[0].replace("*", "_ptr")
self.name = decl[1]
self.readonly = True
if "/RW" in decl[3]:
self.readonly = False
class ClassInfo(object):
def __init__(self, name, decl=None):
self.cname = name.replace(".", "::")
self.name = self.wname = re.sub(r"^cv\.", "", name)
self.ismap = False
self.issimple = False
self.methods = {}
self.props = []
self.consts = {}
customname = False
if decl:
self.bases = decl[1].split()[1:]
if len(self.bases) > 1:
print "Error: class %s has more than 1 base class (not supported by Python C extensions)" % (self.name,)
print "Bases: ", self.bases
return sys.exit(-1)
for m in decl[2]:
if m.startswith("="):
self.wname = m[1:]
customname = True
elif m == "/Map":
self.ismap = True
elif m == "/Simple":
self.issimple = True
self.props = [ClassProp(p) for p in decl[3]]
if not customname and self.wname.startswith("Cv"):
self.wname = self.wname[2:]
def gen_map_code(self, all_classes):
code = "static bool pyopencv_to(PyObject* src, %s& dst, const char* name)\n{\n PyObject* tmp;\n bool ok;\n" % (self.cname)
code += "".join([gen_template_set_prop_from_map.substitute(propname=p.name,proptype=p.tp) for p in self.props])
if self.bases:
code += "\n return pyopencv_to(src, (%s&)dst, name);\n}\n" % all_classes[self.bases[0]].cname
else:
code += "\n return true;\n}\n"
return code
def gen_code(self, all_classes):
if self.ismap:
return self.gen_map_code(all_classes)
getset_code = cStringIO.StringIO()
getset_inits = cStringIO.StringIO()
sorted_props = [(p.name, p) for p in self.props]
sorted_props.sort()
access_op = "->"
if self.issimple:
access_op = "."
for pname, p in sorted_props:
getset_code.write(gen_template_get_prop.substitute(name=self.name, member=pname, membertype=p.tp, access=access_op))
if p.readonly:
getset_inits.write(gen_template_prop_init.substitute(name=self.name, member=pname))
else:
getset_code.write(gen_template_set_prop.substitute(name=self.name, member=pname, membertype=p.tp, access=access_op))
getset_inits.write(gen_template_rw_prop_init.substitute(name=self.name, member=pname))
methods_code = cStringIO.StringIO()
methods_inits = cStringIO.StringIO()
sorted_methods = self.methods.items()
sorted_methods.sort()
for mname, m in sorted_methods:
methods_code.write(m.gen_code(all_classes))
methods_inits.write(m.get_tab_entry())
baseptr = "NULL"
if self.bases and all_classes.has_key(self.bases[0]):
baseptr = "&pyopencv_" + all_classes[self.bases[0]].name + "_Type"
code = gen_template_type_impl.substitute(name=self.name, wname=self.wname, cname=self.cname,
getset_code=getset_code.getvalue(), getset_inits=getset_inits.getvalue(),
methods_code=methods_code.getvalue(), methods_inits=methods_inits.getvalue(),
baseptr=baseptr, extra_specials="")
return code
class ConstInfo(object):
def __init__(self, name, val):
self.cname = name.replace(".", "::")
self.name = re.sub(r"^cv\.", "", name).replace(".", "_")
if self.name.startswith("Cv"):
self.name = self.name[2:]
self.name = re.sub(r"([a-z])([A-Z])", r"\1_\2", self.name)
self.name = self.name.upper()
self.value = val
class ArgInfo(object):
def __init__(self, arg_tuple):
self.tp = arg_tuple[0]
self.name = arg_tuple[1]
self.defval = arg_tuple[2]
self.isarray = False
self.arraylen = 0
self.arraycvt = None
self.inputarg = True
self.outputarg = False
for m in arg_tuple[3]:
if m == "/O":
self.inputarg = False
self.outputarg = True
elif m == "/IO":
self.inputarg = True
self.outputarg = True
elif m.startswith("/A"):
self.isarray = True
self.arraylen = m[2:].strip()
elif m.startswith("/CA"):
self.isarray = True
self.arraycvt = m[2:].strip()
self.py_inputarg = False
self.py_outputarg = False
def isbig(self):
return self.tp == "Mat" or self.tp == "vector_Mat"# or self.tp.startswith("vector")
class FuncVariant(object):
def __init__(self, classname, name, decl, isconstructor):
self.classname = classname
self.name = self.wname = name
self.isconstructor = isconstructor
if self.isconstructor and self.wname.startswith("Cv"):
self.wname = self.wname[2:]
self.rettype = decl[1]
if self.rettype == "void":
self.rettype = ""
self.args = []
self.array_counters = {}
for a in decl[3]:
ainfo = ArgInfo(a)
if ainfo.isarray and not ainfo.arraycvt:
c = ainfo.arraylen
c_arrlist = self.array_counters.get(c, [])
if c_arrlist:
c_arrlist.append(ainfo.name)
else:
self.array_counters[c] = [ainfo.name]
self.args.append(ainfo)
self.init_pyproto()
def init_pyproto(self):
# string representation of argument list, with '[', ']' symbols denoting optional arguments, e.g.
# "src1, src2[, dst[, mask]]" for cv.add
argstr = ""
# list of all input arguments of the Python function, with the argument numbers:
# [("src1", 0), ("src2", 1), ("dst", 2), ("mask", 3)]
# we keep an argument number to find the respective argument quickly, because
# some of the arguments of C function may not present in the Python function (such as array counters)
# or even go in a different order ("heavy" output parameters of the C function
# become the first optional input parameters of the Python function, and thus they are placed right after
# non-optional input parameters)
arglist = []
# the list of "heavy" output parameters. Heavy parameters are the parameters
# that can be expensive to allocate each time, such as vectors and matrices (see isbig).
outarr_list = []
# the list of output parameters. Also includes input/output parameters.
outlist = []
firstoptarg = 1000000
argno = -1
for a in self.args:
argno += 1
if a.name in self.array_counters:
continue
if a.outputarg:
outlist.append((a.name, argno))
if not a.inputarg:
if a.isbig():
outarr_list.append((a.name, argno))
continue
if not a.defval:
arglist.append((a.name, argno))
else:
firstoptarg = min(firstoptarg, len(arglist))
# if there are some array output parameters before the first default parameter, they
# are added as optional parameters before the first optional parameter
if outarr_list:
arglist += outarr_list
outarr_list = []
arglist.append((a.name, argno))
if outarr_list:
firstoptarg = min(firstoptarg, len(arglist))
arglist += outarr_list
firstoptarg = min(firstoptarg, len(arglist))
noptargs = len(arglist) - firstoptarg
argnamelist = [aname for aname, argno in arglist]
argstr = ", ".join(argnamelist[:firstoptarg])
argstr = "[, ".join([argstr] + argnamelist[firstoptarg:])
argstr += "]" * noptargs
if self.rettype:
outlist = [("retval", -1)] + outlist
elif self.isconstructor:
assert outlist == []
outlist = [("self", -1)]
if self.isconstructor:
classname = self.classname
if classname.startswith("Cv"):
classname=classname[2:]
outstr = "<%s object>" % (classname,)
elif outlist:
outstr = ", ".join([o[0] for o in outlist])
else:
outstr = "None"
self.py_docstring = "%s(%s) -> %s" % (self.wname, argstr, outstr)
self.py_noptargs = noptargs
self.py_arglist = arglist
for aname, argno in arglist:
self.args[argno].py_inputarg = True
for aname, argno in outlist:
if argno >= 0:
self.args[argno].py_outputarg = True
self.py_outlist = outlist
class FuncInfo(object):
def __init__(self, classname, name, cname, isconstructor):
self.classname = classname
self.name = name
self.cname = cname
self.isconstructor = isconstructor
self.variants = []
def add_variant(self, decl):
self.variants.append(FuncVariant(self.classname, self.name, decl, self.isconstructor))
def get_wrapper_name(self):
name = self.name
if self.classname:
classname = self.classname + "_"
if "[" in name:
name = "getelem"
else:
classname = ""
return "pyopencv_" + classname + name
def get_wrapper_prototype(self):
full_fname = self.get_wrapper_name()
if self.classname and not self.isconstructor:
self_arg = "self"
else:
self_arg = ""
return "static PyObject* %s(PyObject* %s, PyObject* args, PyObject* kw)" % (full_fname, self_arg)
def get_tab_entry(self):
docstring_list = []
have_empty_constructor = False
for v in self.variants:
s = v.py_docstring
if (not v.py_arglist) and self.isconstructor:
have_empty_constructor = True
if s not in docstring_list:
docstring_list.append(s)
# if there are just 2 constructors: default one and some other,
# we simplify the notation.
# Instead of ClassName(args ...) -> object or ClassName() -> object
# we write ClassName([args ...]) -> object
if have_empty_constructor and len(self.variants) == 2:
idx = self.variants[1].py_arglist != []
docstring_list = ["[" + self.variants[idx].py_docstring + "]"]
return Template(' {"$py_funcname", (PyCFunction)$wrap_funcname, METH_KEYWORDS, "$py_docstring"},\n'
).substitute(py_funcname = self.variants[0].wname, wrap_funcname=self.get_wrapper_name(),
py_docstring = " or ".join(docstring_list))
def gen_code(self, all_classes):
proto = self.get_wrapper_prototype()
code = "%s\n{\n" % (proto,)
selfinfo = ClassInfo("")
ismethod = self.classname != "" and not self.isconstructor
# full name is needed for error diagnostic in PyArg_ParseTupleAndKeywords
fullname = self.name
if self.classname:
selfinfo = all_classes[self.classname]
if not self.isconstructor:
amp = ""
if selfinfo.issimple:
amp = "&"
code += gen_template_check_self.substitute(name=selfinfo.name, cname=selfinfo.cname, amp=amp)
fullname = selfinfo.wname + "." + fullname
all_code_variants = []
declno = -1
for v in self.variants:
code_decl = ""
code_fcall = ""
code_ret = ""
code_cvt_list = []
if self.isconstructor:
code_decl += " pyopencv_%s_t* self = 0;\n" % selfinfo.name
op = "new "
if selfinfo.issimple:
op = ""
code_fcall = gen_template_call_constructor.substitute(name=selfinfo.name, cname=selfinfo.cname, op=op)
else:
code_fcall = "ERRWRAP2( "
if v.rettype:
code_decl += " " + v.rettype + " retval;\n"
code_fcall += "retval = "
if ismethod:
code_fcall += "_self_->" + self.cname
else:
code_fcall += self.cname
code_fcall += "("
all_cargs = []
parse_arglist = []
# declare all the C function arguments,
# add necessary conversions from Python objects to code_cvt_list,
# form the function/method call,
# for the list of type mappings
for a in v.args:
tp1 = tp = a.tp
amp = ""
defval0 = ""
if tp.endswith("*"):
tp = tp1 = tp[:-1]
amp = "&"
if tp.endswith("*"):
defval0 = "0"
tp1 = tp.replace("*", "_ptr")
if tp1.endswith("*"):
print "Error: type with star: a.tp=%s, tp=%s, tp1=%s" % (a.tp, tp, tp1)
sys.exit(-1)
amapping = simple_argtype_mapping.get(tp, (tp, "O", defval0))
parse_name = a.name
if a.py_inputarg:
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))
all_cargs.append([amapping, parse_name])
defval = a.defval
if not defval:
defval = amapping[2]
# "tp arg = tp();" is equivalent to "tp arg;" in the case of complex types
if defval == tp + "()" and amapping[1] == "O":
defval = ""
if a.outputarg and not a.inputarg:
defval = ""
if defval:
code_decl += " %s %s=%s;\n" % (amapping[0], a.name, defval)
else:
code_decl += " %s %s;\n" % (amapping[0], a.name)
if not code_fcall.endswith("("):
code_fcall += ", "
code_fcall += amp + a.name
code_fcall += "))"
if code_cvt_list:
code_cvt_list = [""] + code_cvt_list
# add info about return value, if any, to all_cargs. if there non-void return value,
# it is encoded in v.py_outlist as ("retval", -1) pair.
# As [-1] in Python accesses the last element of a list, we automatically handle the return value by
# adding the necessary info to the end of all_cargs list.
if v.rettype:
tp = v.rettype
tp1 = tp.replace("*", "_ptr")
amapping = simple_argtype_mapping.get(tp, (tp, "O", "0"))
all_cargs.append(amapping)
if v.args:
# form the format spec for PyArg_ParseTupleAndKeywords
fmtspec = "".join([all_cargs[argno][0][1] for aname, argno in v.py_arglist])
if v.py_noptargs > 0:
fmtspec = fmtspec[:-v.py_noptargs] + "|" + fmtspec[-v.py_noptargs:]
fmtspec += ":" + fullname
# form the argument parse code that:
# - declares the list of keyword parameters
# - calls PyArg_ParseTupleAndKeywords
# - converts complex arguments from PyObject's to native OpenCV types
code_parse = gen_template_parse_args.substitute(
kw_list = ", ".join(['"' + aname + '"' for aname, argno in v.py_arglist]),
fmtspec = fmtspec,
parse_arglist = ", ".join(["&" + all_cargs[argno][1] for aname, argno in v.py_arglist]),
code_cvt = " &&\n ".join(code_cvt_list))
else:
code_parse = "if(PyObject_Size(args) == 0 && PyObject_Size(kw) == 0)"
if len(v.py_outlist) == 0:
code_ret = "Py_RETURN_NONE"
elif len(v.py_outlist) == 1:
if self.isconstructor:
code_ret = "return (PyObject*)self"
else:
aname, argno = v.py_outlist[0]
code_ret = "return pyopencv_from(%s)" % (aname,)
else:
# ther is more than 1 return parameter; form the tuple out of them
fmtspec = "N"*len(v.py_outlist)
backcvt_arg_list = []
for aname, argno in v.py_outlist:
amapping = all_cargs[argno][0]
backcvt_arg_list.append("%s(%s)" % (amapping[2], aname))
code_ret = "return Py_BuildValue(\"(%s)\", %s)" % \
(fmtspec, ", ".join(["pyopencv_from(" + aname + ")" for aname, argno in v.py_outlist]))
all_code_variants.append(gen_template_func_body.substitute(code_decl=code_decl,
code_parse=code_parse, code_fcall=code_fcall, code_ret=code_ret))
if len(all_code_variants)==1:
# if the function/method has only 1 signature, then just put it
code += all_code_variants[0]
else:
# try to execute each signature
code += " PyErr_Clear();\n\n".join([" {\n" + v + " }\n" for v in all_code_variants])
code += "\n return NULL;\n}\n\n"
return code
class PythonWrapperGenerator(object):
def __init__(self):
self.clear()
def clear(self):
self.classes = {}
self.funcs = {}
self.consts = {}
self.code_types = cStringIO.StringIO()
self.code_funcs = cStringIO.StringIO()
self.code_func_tab = cStringIO.StringIO()
self.code_type_reg = cStringIO.StringIO()
self.code_const_reg = cStringIO.StringIO()
def add_class(self, stype, name, decl):
classinfo = ClassInfo(name, decl)
if self.classes.has_key(classinfo.name):
print "Generator error: class %s (cname=%s) already exists" \
% (classinfo.name, classinfo.cname)
sys.exit(-1)
self.classes[classinfo.name] = classinfo
def add_const(self, name, decl):
constinfo = ConstInfo(name, decl[1])
if self.consts.has_key(constinfo.name):
print "Generator error: constant %s (cname=%s) already exists" \
% (constinfo.name, constinfo.cname)
sys.exit(-1)
self.consts[constinfo.name] = constinfo
def add_func(self, decl):
classname = ""
name = decl[0]
dpos = name.rfind(".")
if dpos >= 0 and name[:dpos] != "cv":
classname = re.sub(r"^cv\.", "", name[:dpos])
name = name[dpos+1:]
cname = name
name = re.sub(r"^cv\.", "", name)
isconstructor = cname == classname
cname = cname.replace(".", "::")
isclassmethod = False
customname = False
for m in decl[2]:
if m == "/S":
isclassmethod = True
elif m.startswith("="):
name = m[1:]
customname = True
func_map = self.funcs
if not classname or isconstructor:
pass
elif isclassmethod:
if not customname:
name = classname + "_" + name
cname = classname + "::" + cname
classname = ""
else:
classinfo = self.classes.get(classname, ClassInfo(""))
if not classinfo.name:
print "Generator error: the class for method %s is missing" % (name,)
sys.exit(-1)
func_map = classinfo.methods
func = func_map.get(name, FuncInfo(classname, name, cname, isconstructor))
func.add_variant(decl)
if len(func.variants) == 1:
func_map[name] = func
def gen_const_reg(self, constinfo):
self.code_const_reg.write("PUBLISH2(%s,%s);\n" % (constinfo.name, constinfo.cname))
def save(self, path, name, buf):
f = open(path + "/" + name, "wt")
f.write(buf.getvalue())
f.close()
def gen(self, srcfiles, output_path):
self.clear()
parser = hdr_parser.CppHeaderParser()
# step 1: scan the headers and build more descriptive maps of classes, consts, functions
for hdr in srcfiles:
decls = parser.parse(hdr)
for decl in decls:
name = decl[0]
if name.startswith("struct") or name.startswith("class"):
# class/struct
p = name.find(" ")
stype = name[:p]
name = name[p+1:].strip()
self.add_class(stype, name, decl)
elif name.startswith("const"):
# constant
self.add_const(name.replace("const ", "").strip(), decl)
else:
# function
self.add_func(decl)
# step 2: generate code for the classes and their methods
classlist = self.classes.items()
classlist.sort()
for name, classinfo in classlist:
if classinfo.ismap:
self.code_types.write(gen_template_map_type_cvt.substitute(name=name, cname=classinfo.cname))
else:
if classinfo.issimple:
templ = gen_template_simple_type_decl
else:
templ = gen_template_type_decl
self.code_types.write(templ.substitute(name=name, wname=classinfo.wname, cname=classinfo.cname))
for name, classinfo in classlist:
code = classinfo.gen_code(self.classes)
self.code_types.write(code)
if not classinfo.ismap:
self.code_type_reg.write("MKTYPE2(%s);\n" % (classinfo.name,) )
# step 3: generate the code for all the global functions
funclist = self.funcs.items()
funclist.sort()
for name, func in funclist:
code = func.gen_code(self.classes)
self.code_funcs.write(code)
self.code_func_tab.write(func.get_tab_entry())
# step 4: generate the code for constants
constlist = self.consts.items()
constlist.sort()
for name, constinfo in constlist:
self.gen_const_reg(constinfo)
# That's it. Now save all the files
self.save(output_path, "pyopencv_generated_funcs.h", self.code_funcs)
self.save(output_path, "pyopencv_generated_func_tab.h", self.code_func_tab)
self.save(output_path, "pyopencv_generated_const_reg.h", self.code_const_reg)
self.save(output_path, "pyopencv_generated_types.h", self.code_types)
self.save(output_path, "pyopencv_generated_type_reg.h", self.code_type_reg)
if __name__ == "__main__":
srcfiles = hdr_parser.opencv_hdr_list
dstdir = "/Users/vp/tmp"
if len(sys.argv) > 2:
dstdir = sys.argv[1]
srcfiles = sys.argv[2:]
generator = PythonWrapperGenerator()
generator.gen(srcfiles, dstdir)

683
modules/python/src2/hdr_parser.py Executable file
View File

@@ -0,0 +1,683 @@
import os, sys, re
# the list only for debugging. The real list, used in the real OpenCV build, is specified in CMakeLists.txt
opencv_hdr_list = [
"../../core/include/opencv2/core/core.hpp",
"../../ml/include/opencv2/ml/ml.hpp",
"../../imgproc/include/opencv2/imgproc/imgproc.hpp",
"../../calib3d/include/opencv2/calib3d/calib3d.hpp",
"../../features2d/include/opencv2/features2d/features2d.hpp",
"../../video/include/opencv2/video/tracking.hpp",
"../../video/include/opencv2/video/background_segm.hpp",
"../../objdetect/include/opencv2/objdetect/objdetect.hpp",
"../../highgui/include/opencv2/highgui/highgui.hpp",
"opencv_extra_api.hpp",
]
"""
Each declaration is [funcname, return_value_type /* in C, not in Python */, <list_of_modifiers>, <list_of_arguments>],
where each element of <list_of_arguments> is 4-element list itself:
[argtype, argname, default_value /* or "" if none */, <list_of_modifiers>]
where the list of modifiers is yet another nested list of strings
(currently recognized are "/O" for output argument, "/S" for static (i.e. class) methods
and "/A value" for the plain C arrays with counters)
"""
class CppHeaderParser(object):
def __init__(self):
self.BLOCK_TYPE = 0
self.BLOCK_NAME = 1
self.PROCESS_FLAG = 2
self.PUBLIC_SECTION = 3
self.CLASS_DECL = 4
def batch_replace(self, s, pairs):
for before, after in pairs:
s = s.replace(before, after)
return s
def get_macro_arg(self, arg_str, npos):
npos2 = npos3 = arg_str.find("(", npos)
if npos2 < 0:
print "Error: no arguments for the macro at %d" % (self.lineno,)
sys.exit(-1)
balance = 1
while 1:
t, npos3 = self.find_next_token(arg_str, ['(', ')'], npos3+1)
if npos3 < 0:
print "Error: no matching ')' in the macro call at %d" % (self.lineno,)
sys.exit(-1)
if t == '(':
balance += 1
if t == ')':
balance -= 1
if balance == 0:
break
return arg_str[npos2+1:npos3].strip(), npos3
def parse_arg(self, arg_str, argno):
"""
Parses <arg_type> [arg_name]
Returns arg_type, arg_name, modlist, argno, where
modlist is the list of wrapper-related modifiers (such as "output argument", "has counter", ...)
and argno is the new index of an anonymous argument.
That is, if no arg_str is just an argument type without argument name, the argument name is set to
"arg" + str(argno), and then argno is incremented.
"""
modlist = []
# pass 0: extracts the modifiers
if "CV_OUT" in arg_str:
modlist.append("/O")
arg_str = arg_str.replace("CV_OUT", "")
if "CV_IN_OUT" in arg_str:
modlist.append("/IO")
arg_str = arg_str.replace("CV_IN_OUT", "")
isarray = False
npos = arg_str.find("CV_CARRAY")
if npos >= 0:
isarray = True
macro_arg, npos3 = self.get_macro_arg(arg_str, npos)
modlist.append("/A " + macro_arg)
arg_str = arg_str[:npos] + arg_str[npos3+1:]
npos = arg_str.find("CV_CUSTOM_CARRAY")
if npos >= 0:
isarray = True
macro_arg, npos3 = self.get_macro_arg(arg_str, npos)
modlist.append("/CA " + macro_arg)
arg_str = arg_str[:npos] + arg_str[npos3+1:]
arg_str = arg_str.strip()
word_start = 0
word_list = []
npos = -1
#print self.lineno, ":\t", arg_str
# pass 1: split argument type into tokens
while 1:
npos += 1
t, npos = self.find_next_token(arg_str, [" ", "&", "*", "<", ">", ","], npos)
w = arg_str[word_start:npos].strip()
if w == "operator":
word_list.append("operator " + arg_str[npos:].strip())
break
if w not in ["", "const"]:
word_list.append(w)
if t not in ["", " ", "&"]:
word_list.append(t)
if not t:
break
word_start = npos+1
npos = word_start - 1
arg_type = ""
arg_name = ""
angle_stack = []
#print self.lineno, ":\t", word_list
# pass 2: decrypt the list
wi = -1
prev_w = ""
for w in word_list:
wi += 1
if w == "*":
if prev_w == "char" and not isarray:
arg_type = arg_type[:-len("char")] + "c_string"
else:
arg_type += w
continue
elif w == "<":
arg_type += "_"
angle_stack.append(0)
elif w == "," or w == '>':
if not angle_stack:
print "Error at %d: argument contains ',' or '>' not within template arguments" % (self.lineno,)
sys.exit(-1)
if w == ",":
arg_type += "_and_"
elif w == ">":
if angle_stack[0] == 0:
print "Error at %d: template has no arguments" % (self.lineno,)
sys.exit(-1)
if angle_stack[0] > 1:
arg_type += "_end_"
angle_stack[-1:] = []
elif angle_stack:
arg_type += w
angle_stack[-1] += 1
elif arg_type and arg_type != "~":
arg_name = " ".join(word_list[wi:])
break
else:
arg_type += w
prev_w = w
counter_str = ""
add_star = False
if ("[" in arg_name) and not ("operator" in arg_str):
#print arg_str
p1 = arg_name.find("[")
p2 = arg_name.find("]",p1+1)
if p2 < 0:
print "Error at %d: no closing ]" % (self.lineno,)
sys.exit(-1)
counter_str = arg_name[p1+1:p2].strip()
if counter_str == "":
counter_str = "?"
if not isarray:
modlist.append("/A " + counter_str.strip())
arg_name = arg_name[:p1]
add_star = True
if not arg_name:
if arg_type.startswith("operator"):
arg_type, arg_name = "", arg_type
else:
arg_name = "arg" + str(argno)
argno += 1
while arg_type.endswith("_end_"):
arg_type = arg_type[:-len("_end_")]
if add_star:
arg_type += "*"
arg_type = self.batch_replace(arg_type, [("std::", ""), ("cv::", "")])
return arg_type, arg_name, modlist, argno
def parse_enum(self, decl_str):
l = decl_str
ll = l.split(",")
prev_val = ""
prev_val_delta = -1
decl = []
for pair in ll:
pv = pair.split("=")
if len(pv) == 1:
prev_val_delta += 1
val = ""
if prev_val:
val = prev_val + "+"
val += str(prev_val_delta)
else:
prev_val_delta = 0
prev_val = val = pv[1].strip()
decl.append(["const " + self.get_dotted_name(pv[0].strip()), val, [], []])
return decl
def parse_class_decl(self, decl_str):
"""
Parses class/struct declaration start in the form:
{class|struct} [CV_EXPORTS] <class_name> [: public <base_class1> [, ...]]
Returns class_name1, <list of base_classes>
"""
l = decl_str
modlist = []
if "CV_EXPORTS_W_MAP" in l:
l = l.replace("CV_EXPORTS_W_MAP", "")
modlist.append("/Map")
if "CV_EXPORTS_W_SIMPLE" in l:
l = l.replace("CV_EXPORTS_W_SIMPLE", "")
modlist.append("/Simple")
npos = l.find("CV_EXPORTS_AS")
if npos >= 0:
macro_arg, npos3 = self.get_macro_arg(l, npos)
modlist.append("=" + macro_arg)
l = l[:npos] + l[npos3+1:]
l = self.batch_replace(l, [("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("public ", " "), ("::", ".")]).strip()
ll = re.split(r'\s*[,:]?\s*', l)
ll = [le for le in ll if le]
classname = ll[1]
bases = ll[2:]
return classname, bases, modlist
def parse_func_decl(self, decl_str):
"""
Parses the function or method declaration in the form:
[([CV_EXPORTS] <rettype>) | CVAPI(rettype)]
[~]<function_name>
(<arg_type1> <arg_name1>[=<default_value1>] [, <arg_type2> <arg_name2>[=<default_value2>] ...])
[const] {; | <function_body>}
Returns the function declaration entry:
[<function_name>, <rettype>, <the_list_of_argument_descriptions>] (see above)
"""
if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or \
("CV_WRAP" in decl_str) or ("CV_WRAP_AS" in decl_str)):
return []
top = self.block_stack[-1]
func_modlist = []
npos = decl_str.find("CV_EXPORTS_AS")
if npos >= 0:
arg, npos3 = self.get_macro_arg(decl_str, npos)
func_modlist.append("="+arg)
decl_str = decl_str[:npos] + decl_str[npos3+1:]
npos = decl_str.find("CV_WRAP_AS")
if npos >= 0:
arg, npos3 = self.get_macro_arg(decl_str, npos)
func_modlist.append("="+arg)
decl_str = decl_str[:npos] + decl_str[npos3+1:]
# filter off some common prefixes, which are meaningless for Python wrappers.
# note that we do not strip "static" prefix, which does matter;
# it means class methods, not instance methods
decl_str = self.batch_replace(decl_str, [("virtual", ""), ("static inline", ""), ("inline", ""),\
("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("CV_WRAP ", " "), ("static CV_INLINE", ""), ("CV_INLINE", "")]).strip()
static_method = False
context = top[0]
if decl_str.startswith("static") and (context == "class" or context == "struct"):
decl_str = decl_str[len("static"):].lstrip()
static_method = True
args_begin = decl_str.find("(")
if decl_str.startswith("CVAPI"):
rtype_end = decl_str.find(")", args_begin+1)
if rtype_end < 0:
print "Error at %d. no terminating ) in CVAPI() macro: %s" % (self.lineno, decl_str)
sys.exit(-1)
decl_str = decl_str[args_begin+1:rtype_end] + " " + decl_str[rtype_end+1:]
args_begin = decl_str.find("(")
if args_begin < 0:
print "Error at %d: no args in '%s'" % (self.lineno, decl_str)
sys.exit(-1)
decl_start = decl_str[:args_begin].strip()
# handle operator () case
if decl_start.endswith("operator"):
args_begin = decl_str.find("(", args_begin+1)
if args_begin < 0:
print "Error at %d: no args in '%s'" % (self.lineno, decl_str)
sys.exit(-1)
decl_start = decl_str[:args_begin].strip()
rettype, funcname, modlist, argno = self.parse_arg(decl_start, -1)
if argno >= 0:
classname = top[1]
if rettype == classname or rettype == "~" + classname:
rettype, funcname = "", rettype
else:
print "Error at %d. the function/method name is missing: '%s'" % (self.lineno, decl_start)
sys.exit(-1)
if ("::" in funcname) or funcname.startswith("~"):
# if there is :: in function name (and this is in the header file),
# it means, this is inline implementation of a class method.
# Thus the function has been already declared within the class and we skip this repeated
# declaration.
# Also, skip the destructors, as they are always wrapped
return []
funcname = self.get_dotted_name(funcname)
arg_start = args_begin+1
npos = arg_start-1
balance = 1
angle_balance = 0
# scan the argument list; handle nested parentheses
args_decls = []
args = []
argno = 1
while balance > 0:
npos += 1
t, npos = self.find_next_token(decl_str, ["(", ")", ",", "<", ">"], npos)
if not t:
print "Error: no closing ')' at %d" % (self.lineno,)
print decl_str
print decl_str[arg_start:]
sys.exit(-1)
if t == "<":
angle_balance += 1
if t == ">":
angle_balance -= 1
if t == "(":
balance += 1
if t == ")":
balance -= 1
if (t == "," and balance == 1 and angle_balance == 0) or balance == 0:
# process next function argument
a = decl_str[arg_start:npos].strip()
#print "arg = ", a
arg_start = npos+1
if a:
eqpos = a.find("=")
defval = ""
modlist = []
if eqpos >= 0:
defval = a[eqpos+1:].strip()
else:
eqpos = a.find("CV_DEFAULT")
if eqpos >= 0:
defval, pos3 = self.get_macro_arg(a, eqpos)
else:
eqpos = a.find("CV_WRAP_DEFAULT")
if eqpos >= 0:
defval, pos3 = self.get_macro_arg(a, eqpos)
if defval == "NULL":
defval = "0"
if eqpos >= 0:
a = a[:eqpos].strip()
arg_type, arg_name, modlist, argno = self.parse_arg(a, argno)
if arg_type == "InputArray" or arg_type == "InputOutputArray":
arg_type = "Mat"
elif arg_type == "OutputArray":
arg_type = "Mat"
modlist.append("/O")
elif arg_type == "InputArrayOfArrays" or arg_type == "InputOutputArrayOfArrays":
arg_type = "vector_Mat"
elif arg_type == "OutputArrayOfArrays":
arg_type = "vector_Mat"
modlist.append("/O")
defval = self.batch_replace(defval, [("InputArrayOfArrays", "vector<Mat>"),
("InputOutputArrayOfArrays", "vector<Mat>"),
("OutputArrayOfArrays", "vector<Mat>"),
("InputArray", "Mat"),
("InputOutputArray", "Mat"),
("OutputArray", "Mat")]).strip()
args.append([arg_type, arg_name, defval, modlist])
npos = arg_start-1
npos = decl_str.replace(" ", "").find("=0", npos)
if npos >= 0:
# skip pure virtual functions
return []
if static_method:
rettype = " ".join([rettype, "/S"])
return [funcname, rettype, func_modlist, args]
def get_dotted_name(self, name):
"""
adds the dot-separated container class/namespace names to the bare function/class name, e.g. when we have
namespace cv {
class A {
public:
f(int);
};
}
the function will convert "A" to "cv.A" and "f" to "cv.A.f".
"""
if not self.block_stack:
return name
n = ""
for b in self.block_stack:
block_type, block_name = b[self.BLOCK_TYPE], b[self.BLOCK_NAME]
if block_type in ["file", "enum"]:
continue
if block_type not in ["struct", "class", "namespace"]:
print "Error at %d: there are non-valid entries in the current block stack " % (self.lineno, self.block_stack)
sys.exit(-1)
if block_name:
n += block_name + "."
return n + name
def parse_stmt(self, stmt, end_token):
"""
parses the statement (ending with ';' or '}') or a block head (ending with '{')
The function calls parse_class_decl or parse_func_decl when necessary. It returns
<block_type>, <block_name>, <parse_flag>, <declaration>
where the first 3 values only make sense for blocks (i.e. code blocks, namespaces, classes, enums and such)
"""
stack_top = self.block_stack[-1]
context = stack_top[self.BLOCK_TYPE]
stmt_type = ""
if end_token == "{":
stmt_type = "block"
if context == "block":
print "Error at %d: should not call parse_stmt inside blocks" % (self.lineno,)
sys.exit(-1)
if context == "class" or context == "struct":
while 1:
colon_pos = stmt.find(":")
if colon_pos < 0:
break
w = stmt[:colon_pos].strip()
if w in ["public", "protected", "private"]:
if w == "public":
stack_top[self.PUBLIC_SECTION] = True
else:
stack_top[self.PUBLIC_SECTION] = False
stmt = stmt[colon_pos+1:].strip()
break
# do not process hidden class members and template classes/functions
if not stack_top[self.PUBLIC_SECTION] or stmt.startswith("template"):
return stmt_type, "", False, None
if end_token == "{":
if stmt.startswith("class") or stmt.startswith("struct"):
stmt_type = stmt.split()[0]
classname, bases, modlist = self.parse_class_decl(stmt)
decl = []
if ("CV_EXPORTS_W" in stmt) or ("CV_EXPORTS_AS" in stmt):
decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, []]
if bases:
decl[1] = ": " + " ".join(bases)
return stmt_type, classname, True, decl
if stmt.startswith("enum"):
return "enum", "", True, None
if stmt.startswith("namespace"):
stmt_list = stmt.split()
return stmt_list[0], stmt_list[1], True, None
if stmt.startswith("extern") and "\"C\"" in stmt:
return "namespace", "", True, None
if end_token == "}" and context == "enum":
decl = self.parse_enum(stmt)
return "enum", "", False, decl
if end_token == ";" and stmt.startswith("typedef"):
# TODO: handle typedef's more intelligently
return stmt_type, "", False, None
paren_pos = stmt.find("(")
if paren_pos >= 0:
# assume it's function or method declaration,
# since we filtered off the other places where '(' can normally occur:
# - code blocks
# - function pointer typedef's
decl = self.parse_func_decl(stmt)
# we return parse_flag == False to prevent the parser to look inside function/method bodies
# (except for tracking the nested blocks)
return stmt_type, "", False, decl
if (context == "struct" or context == "class") and end_token == ";" and stmt:
# looks like it's member declaration; append the members to the class declaration
class_decl = stack_top[self.CLASS_DECL]
if ("CV_PROP" in stmt): # or (class_decl and ("/Map" in class_decl[2])):
var_modlist = []
if "CV_PROP_RW" in stmt:
var_modlist.append("/RW")
stmt = self.batch_replace(stmt, [("CV_PROP_RW", ""), ("CV_PROP", "")]).strip()
var_list = stmt.split(",")
var_type, var_name1, modlist, argno = self.parse_arg(var_list[0], -1)
var_list = [var_name1] + [i.strip() for i in var_list[1:]]
for v in var_list:
class_decl[3].append([var_type, v, "", var_modlist])
return stmt_type, "", False, None
# something unknown
return stmt_type, "", False, None
def find_next_token(self, s, tlist, p=0):
"""
Finds the next token from the 'tlist' in the input 's', starting from position 'p'.
Returns the first occured token and its position, or ("", len(s)) when no token is found
"""
token = ""
tpos = len(s)
for t in tlist:
pos = s.find(t, p)
if pos < 0:
continue
if pos < tpos:
tpos = pos
token = t
return token, tpos
def parse(self, hname):
"""
The main method. Parses the input file.
Returns the list of declarations (that can be print using print_decls)
"""
decls = []
f = open(hname, "rt")
linelist = list(f.readlines())
f.close()
# states:
SCAN = 0 # outside of a comment or preprocessor directive
COMMENT = 1 # inside a multi-line comment
DIRECTIVE = 2 # inside a multi-line preprocessor directive
state = SCAN
self.block_stack = [["file", hname, True, True, None]]
block_head = ""
self.lineno = 0
for l0 in linelist:
self.lineno += 1
#print self.lineno
l = l0.strip()
if state == SCAN and l.startswith("#"):
state = DIRECTIVE
# fall through to the if state == DIRECTIVE check
if state == DIRECTIVE:
if not l.endswith("\\"):
state = SCAN
continue
if state == COMMENT:
pos = l.find("*/")
if pos < 0:
continue
l = l[pos+2:]
state = SCAN
if state != SCAN:
print "Error at %d: invlid state = %d" % (self.lineno, state)
sys.exit(-1)
while 1:
token, pos = self.find_next_token(l, [";", "\"", "{", "}", "//", "/*"])
if not token:
block_head += " " + l
break
if token == "//":
block_head += " " + l[:pos]
break
if token == "/*":
block_head += " " + l[:pos]
pos = l.find("*/", pos+2)
if pos < 0:
state = COMMENT
break
l = l[pos+2:]
continue
if token == "\"":
pos2 = pos + 1
while 1:
t2, pos2 = self.find_next_token(l, ["\\", "\""], pos2)
if t2 == "":
print "Error at %d: no terminating '\"'" % (self.lineno,)
sys.exit(-1)
if t2 == "\"":
break
pos2 += 2
block_head += " " + l[:pos2+1]
l = l[pos2+1:]
continue
stmt = (block_head + " " + l[:pos]).strip()
stmt = " ".join(stmt.split()) # normalize the statement
stack_top = self.block_stack[-1]
decl = None
if stack_top[self.PROCESS_FLAG]:
# even if stack_top[PUBLIC_SECTION] is False, we still try to process the statement,
# since it can start with "public:"
stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token)
if decl:
if stmt_type == "enum":
for d in decl:
decls.append(d)
else:
decls.append(decl)
else:
stmt_type, name, parse_flag = "block", "", False
if token == "{":
if stmt_type == "class":
public_section = False
else:
public_section = True
self.block_stack.append([stmt_type, name, parse_flag, public_section, decl])
if token == "}":
if not self.block_stack:
print "Error at %d: the block stack is empty" % (self.lineno,)
self.block_stack[-1:] = []
if pos+1 < len(l) and l[pos+1] == ';':
pos += 1
block_head = ""
l = l[pos+1:]
return decls
def print_decls(self, decls):
"""
Prints the list of declarations, retrieived by the parse() method
"""
for d in decls:
print d[0], d[1], ";".join(d[2])
for a in d[3]:
print " ", a[0], a[1], a[2],
if a[3]:
print "; ".join(a[3])
else:
print
if __name__ == '__main__':
parser = CppHeaderParser()
decls = []
for hname in opencv_hdr_list:
decls += parser.parse(hname)
parser.print_decls(decls)
print len(decls)

View File

@@ -0,0 +1,486 @@
#ifndef _OPENCV_API_EXTRA_HPP_
#define _OPENCV_API_EXTRA_HPP_
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/calib3d/calib3d.hpp"
namespace cv
{
template<typename _Tp>
static inline void mv2vv(const vector<Mat>& src, vector<vector<_Tp> >& dst)
{
size_t i, n = src.size();
dst.resize(src.size());
for( i = 0; i < n; i++ )
src[i].copyTo(dst[i]);
}
///////////////////////////// core /////////////////////////////
CV_WRAP_AS(getTickCount) static inline double getTickCount_()
{
return (double)getTickCount();
}
CV_WRAP_AS(getCPUTickCount) static inline double getCPUTickCount_()
{
return (double)getCPUTickCount();
}
CV_WRAP void randShuffle(const Mat& src, CV_OUT Mat& dst, double iterFactor=1.)
{
src.copyTo(dst);
randShuffle(dst, iterFactor, 0);
}
CV_WRAP static inline void SVDecomp(const Mat& src, CV_OUT Mat& w, CV_OUT Mat& u, CV_OUT Mat& vt, int flags=0 )
{
SVD::compute(src, w, u, vt, flags);
}
CV_WRAP static inline void SVBackSubst( const Mat& w, const Mat& u, const Mat& vt,
const Mat& rhs, CV_OUT Mat& dst )
{
SVD::backSubst(w, u, vt, rhs, dst);
}
CV_WRAP static inline void mixChannels(const vector<Mat>& src, vector<Mat>& dst,
const vector<int>& fromTo)
{
if(fromTo.empty())
return;
CV_Assert(fromTo.size()%2 == 0);
mixChannels(&src[0], (int)src.size(), &dst[0], (int)dst.size(), &fromTo[0], (int)(fromTo.size()/2));
}
CV_WRAP static inline bool eigen(const Mat& src, bool computeEigenvectors,
CV_OUT Mat& eigenvalues, CV_OUT Mat& eigenvectors,
int lowindex=-1, int highindex=-1)
{
return computeEigenvectors ? eigen(src, eigenvalues, eigenvectors, lowindex, highindex) :
eigen(src, eigenvalues, lowindex, highindex);
}
CV_WRAP static inline void fillConvexPoly(Mat& img, const Mat& points,
const Scalar& color, int lineType=8,
int shift=0)
{
CV_Assert(points.checkVector(2, CV_32S) >= 0);
fillConvexPoly(img, (const Point*)points.data, points.rows*points.cols*points.channels()/2, color, lineType, shift);
}
CV_WRAP static inline void fillPoly(Mat& img, const vector<Mat>& pts,
const Scalar& color, int lineType=8, int shift=0,
Point offset=Point() )
{
if( pts.empty() )
return;
AutoBuffer<Point*> _ptsptr(pts.size());
AutoBuffer<int> _npts(pts.size());
Point** ptsptr = _ptsptr;
int* npts = _npts;
for( size_t i = 0; i < pts.size(); i++ )
{
const Mat& p = pts[i];
CV_Assert(p.checkVector(2, CV_32S) >= 0);
ptsptr[i] = (Point*)p.data;
npts[i] = p.rows*p.cols*p.channels()/2;
}
fillPoly(img, (const Point**)ptsptr, npts, (int)pts.size(), color, lineType, shift, offset);
}
CV_WRAP static inline void polylines(Mat& img, const vector<Mat>& pts,
bool isClosed, const Scalar& color,
int thickness=1, int lineType=8, int shift=0 )
{
if( pts.empty() )
return;
AutoBuffer<Point*> _ptsptr(pts.size());
AutoBuffer<int> _npts(pts.size());
Point** ptsptr = _ptsptr;
int* npts = _npts;
for( size_t i = 0; i < pts.size(); i++ )
{
const Mat& p = pts[i];
CV_Assert(p.checkVector(2, CV_32S) >= 0);
ptsptr[i] = (Point*)p.data;
npts[i] = p.rows*p.cols*p.channels()/2;
}
polylines(img, (const Point**)ptsptr, npts, (int)pts.size(), isClosed, color, thickness, lineType, shift);
}
CV_WRAP static inline void PCACompute(const Mat& data, CV_OUT Mat& mean,
CV_OUT Mat& eigenvectors, int maxComponents=0)
{
PCA pca;
pca.mean = mean;
pca.eigenvectors = eigenvectors;
pca(data, Mat(), 0, maxComponents);
pca.mean.copyTo(mean);
pca.eigenvectors.copyTo(eigenvectors);
}
CV_WRAP static inline void PCAProject(const Mat& data, const Mat& mean,
const Mat& eigenvectors, CV_OUT Mat& result)
{
PCA pca;
pca.mean = mean;
pca.eigenvectors = eigenvectors;
pca.project(data, result);
}
CV_WRAP static inline void PCABackProject(const Mat& data, const Mat& mean,
const Mat& eigenvectors, CV_OUT Mat& result)
{
PCA pca;
pca.mean = mean;
pca.eigenvectors = eigenvectors;
pca.backProject(data, result);
}
/////////////////////////// imgproc /////////////////////////////////
CV_WRAP static inline void HuMoments(const Moments& m, CV_OUT vector<double>& hu)
{
hu.resize(7);
HuMoments(m, &hu[0]);
}
CV_WRAP static inline Mat getPerspectiveTransform(const vector<Point2f>& src, const vector<Point2f>& dst)
{
CV_Assert(src.size() == 4 && dst.size() == 4);
return getPerspectiveTransform(&src[0], &dst[0]);
}
CV_WRAP static inline Mat getAffineTransform(const vector<Point2f>& src, const vector<Point2f>& dst)
{
CV_Assert(src.size() == 3 && dst.size() == 3);
return getAffineTransform(&src[0], &dst[0]);
}
CV_WRAP static inline void calcHist( const vector<Mat>& images, const vector<int>& channels,
const Mat& mask, CV_OUT Mat& hist,
const vector<int>& histSize,
const vector<float>& ranges,
bool accumulate=false)
{
int i, dims = (int)histSize.size(), rsz = (int)ranges.size(), csz = (int)channels.size();
CV_Assert(images.size() > 0 && dims > 0);
CV_Assert(rsz == dims*2 || (rsz == 0 && images[0].depth() == CV_8U));
CV_Assert(csz == 0 || csz == dims);
float* _ranges[CV_MAX_DIM];
if( rsz > 0 )
{
for( i = 0; i < rsz/2; i++ )
_ranges[i] = (float*)&ranges[i*2];
}
calcHist(&images[0], (int)images.size(), csz ? &channels[0] : 0,
mask, hist, dims, &histSize[0], rsz ? (const float**)_ranges : 0,
true, accumulate);
}
CV_WRAP void calcBackProject( const vector<Mat>& images, const vector<int>& channels,
const Mat& hist, CV_OUT Mat& dst,
const vector<float>& ranges,
double scale=1 )
{
int i, dims = hist.dims, rsz = (int)ranges.size(), csz = (int)channels.size();
CV_Assert(images.size() > 0);
CV_Assert(rsz == dims*2 || (rsz == 0 && images[0].depth() == CV_8U));
CV_Assert(csz == 0 || csz == dims);
float* _ranges[CV_MAX_DIM];
if( rsz > 0 )
{
for( i = 0; i < rsz/2; i++ )
_ranges[i] = (float*)&ranges[i*2];
}
calcBackProject(&images[0], (int)images.size(), csz ? &channels[0] : 0,
hist, dst, rsz ? (const float**)_ranges : 0, scale, true);
}
static void addChildContour(const vector<Mat>& contours,
const Mat& hierarchy,
int i, vector<CvSeq>& seq,
vector<CvSeqBlock>& block)
{
size_t count = contours.size();
for( ; i >= 0; i = ((const Vec4i*)hierarchy.data)[i][0] )
{
const vector<Point>& ci = contours[i];
cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
!ci.empty() ? (void*)&ci[0] : 0, (int)ci.size(),
&seq[i], &block[i] );
const Vec4i h_i = ((const Vec4i*)hierarchy.data)[i];
int h_next = h_i[0], h_prev = h_i[1], v_next = h_i[2], v_prev = h_i[3];
seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0;
seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0;
seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0;
seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0;
if( v_next >= 0 )
addChildContour(contours, hierarchy, v_next, seq, block);
}
}
//! draws contours in the image
CV_WRAP static inline void drawContours( Mat& image, const vector<Mat>& contours,
int contourIdx, const Scalar& color,
int thickness=1, int lineType=8,
const Mat& hierarchy=Mat(),
int maxLevel=INT_MAX, Point offset=Point() )
{
CvMat _image = image;
size_t i = 0, first = 0, last = contours.size();
vector<CvSeq> seq;
vector<CvSeqBlock> block;
if( !last )
return;
seq.resize(last);
block.resize(last);
for( i = first; i < last; i++ )
seq[i].first = 0;
if( contourIdx >= 0 )
{
CV_Assert( 0 <= contourIdx && contourIdx < (int)last );
first = contourIdx;
last = contourIdx + 1;
}
for( i = first; i < last; i++ )
{
const Mat& ci = contours[i];
int ci_size = ci.checkVector(2, CV_32S);
CV_Assert( ci_size >= 0 );
cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
ci_size > 0 ? ci.data : 0, ci_size, &seq[i], &block[i] );
}
if( hierarchy.empty() || maxLevel == 0 )
for( i = first; i < last; i++ )
{
seq[i].h_next = i < last-1 ? &seq[i+1] : 0;
seq[i].h_prev = i > first ? &seq[i-1] : 0;
}
else
{
int hsz = hierarchy.checkVector(4, CV_32S);
size_t count = last - first;
CV_Assert((size_t)hsz == contours.size());
if( count == contours.size() )
{
for( i = first; i < last; i++ )
{
const Vec4i& h_i = ((const Vec4i*)hierarchy.data)[i];
int h_next = h_i[0], h_prev = h_i[1], v_next = h_i[2], v_prev = h_i[3];
seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0;
seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0;
seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0;
seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0;
}
}
else
{
int child = ((const Vec4i*)hierarchy.data)[first][2];
if( child >= 0 )
{
addChildContour(contours, hierarchy, child, seq, block);
seq[first].v_next = &seq[child];
}
}
}
cvDrawContours( &_image, &seq[first], color, color, contourIdx >= 0 ?
-maxLevel : maxLevel, thickness, lineType, offset );
}
CV_WRAP static inline void approxPolyDP( const Mat& curve,
CV_OUT Mat& approxCurve,
double epsilon, bool closed )
{
if( curve.depth() == CV_32S )
{
vector<Point> result;
approxPolyDP(curve, result, epsilon, closed);
Mat(result).copyTo(approxCurve);
}
else if( curve.depth() == CV_32F )
{
vector<Point2f> result;
approxPolyDP(curve, result, epsilon, closed);
Mat(result).copyTo(approxCurve);
}
else
CV_Error(CV_StsUnsupportedFormat, "");
}
CV_WRAP static inline void convexHull( const Mat& points, CV_OUT Mat& hull, bool returnPoints=true, bool clockwise=false )
{
if( !returnPoints )
{
vector<int> h;
convexHull(points, h, clockwise);
Mat(h).copyTo(hull);
}
else if( points.depth() == CV_32S )
{
vector<Point> h;
convexHull(points, h, clockwise);
Mat(h).copyTo(hull);
}
else if( points.depth() == CV_32F )
{
vector<Point2f> h;
convexHull(points, h, clockwise);
Mat(h).copyTo(hull);
}
}
CV_WRAP static inline void fitLine( const Mat& points, CV_OUT vector<float>& line,
int distType, double param, double reps, double aeps )
{
if(points.channels() == 2 || points.cols == 2)
{
line.resize(4);
fitLine(points, *(Vec4f*)&line[0], distType, param, reps, aeps);
}
else
{
line.resize(6);
fitLine(points, *(Vec6f*)&line[0], distType, param, reps, aeps);
}
}
CV_WRAP static inline int estimateAffine3D( const Mat& from, const Mat& to,
CV_OUT Mat& dst, CV_OUT Mat& outliers,
double param1 = 3.0, double param2 = 0.99 )
{
vector<uchar> outliers_vec;
int res = estimateAffine3D(from, to, dst, outliers_vec, param1, param2);
Mat(outliers_vec).copyTo(outliers);
return res;
}
CV_WRAP static inline void cornerSubPix( const Mat& image, Mat& corners,
Size winSize, Size zeroZone,
TermCriteria criteria )
{
int n = corners.checkVector(2, CV_32F);
CV_Assert(n >= 0);
if( n == 0 )
return;
CvMat _image = image;
cvFindCornerSubPix(&_image, (CvPoint2D32f*)corners.data, n, winSize, zeroZone, criteria);
}
/////////////////////////////// calib3d ///////////////////////////////////////////
CV_WRAP static inline void convertPointsHomogeneous( const Mat& src, CV_OUT Mat& dst )
{
int n;
if( (n = src.checkVector(2)) >= 0 )
dst.create(n, 2, src.depth());
else if( (n = src.checkVector(3)) >= 0 )
dst.create(n, 3, src.depth());
else
CV_Error(CV_StsBadSize, "");
CvMat _src = src, _dst = dst;
cvConvertPointsHomogeneous(&_src, &_dst);
}
/*
//! initializes camera matrix from a few 3D points and the corresponding projections.
CV_WRAP static inline Mat initCameraMatrix2D( const vector<Mat>& objectPoints,
const vector<Mat>& imagePoints,
Size imageSize, double aspectRatio=1. )
{
vector<vector<Point3f> > _objectPoints;
vector<vector<Point2f> > _imagePoints;
mv2vv(objectPoints, _objectPoints);
mv2vv(imagePoints, _imagePoints);
return initCameraMatrix2D(_objectPoints, _imagePoints, imageSize, aspectRatio);
}
CV_WRAP static inline double calibrateCamera( const vector<Mat>& objectPoints,
const vector<Mat>& imagePoints,
Size imageSize,
CV_IN_OUT Mat& cameraMatrix,
CV_IN_OUT Mat& distCoeffs,
vector<Mat>& rvecs, vector<Mat>& tvecs,
int flags=0 )
{
vector<vector<Point3f> > _objectPoints;
vector<vector<Point2f> > _imagePoints;
mv2vv(objectPoints, _objectPoints);
mv2vv(imagePoints, _imagePoints);
return calibrateCamera(_objectPoints, _imagePoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, flags);
}
CV_WRAP static inline double stereoCalibrate( const vector<Mat>& objectPoints,
const vector<Mat>& imagePoints1,
const vector<Mat>& imagePoints2,
CV_IN_OUT Mat& cameraMatrix1, CV_IN_OUT Mat& distCoeffs1,
CV_IN_OUT Mat& cameraMatrix2, CV_IN_OUT Mat& distCoeffs2,
Size imageSize, CV_OUT Mat& R, CV_OUT Mat& T,
CV_OUT Mat& E, CV_OUT Mat& F,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+
TermCriteria::EPS, 30, 1e-6),
int flags=CALIB_FIX_INTRINSIC )
{
vector<vector<Point3f> > _objectPoints;
vector<vector<Point2f> > _imagePoints1;
vector<vector<Point2f> > _imagePoints2;
mv2vv(objectPoints, _objectPoints);
mv2vv(imagePoints1, _imagePoints1);
mv2vv(imagePoints2, _imagePoints2);
return stereoCalibrate(_objectPoints, _imagePoints1, _imagePoints2, cameraMatrix1, distCoeffs1,
cameraMatrix2, distCoeffs2, imageSize, R, T, E, F, criteria, flags);
}
CV_WRAP static inline float rectify3Collinear( const Mat& cameraMatrix1, const Mat& distCoeffs1,
const Mat& cameraMatrix2, const Mat& distCoeffs2,
const Mat& cameraMatrix3, const Mat& distCoeffs3,
const vector<Mat>& imgpt1, const vector<Mat>& imgpt3,
Size imageSize, const Mat& R12, const Mat& T12,
const Mat& R13, const Mat& T13,
CV_OUT Mat& R1, CV_OUT Mat& R2, CV_OUT Mat& R3,
CV_OUT Mat& P1, CV_OUT Mat& P2, CV_OUT Mat& P3, CV_OUT Mat& Q,
double alpha, Size newImgSize,
CV_OUT Rect* roi1, CV_OUT Rect* roi2, int flags )
{
vector<vector<Point2f> > _imagePoints1;
vector<vector<Point2f> > _imagePoints3;
mv2vv(imgpt1, _imagePoints1);
mv2vv(imgpt3, _imagePoints3);
return rectify3Collinear(cameraMatrix1, distCoeffs1,
cameraMatrix2, distCoeffs2,
cameraMatrix3, distCoeffs3,
_imagePoints1, _imagePoints3, imageSize,
R12, T12, R13, T13, R1, R2, R3, P1, P2, P3,
Q, alpha, newImgSize, roi1, roi2, flags);
}
*/
}
#endif