separated opencv 1.x and opencv 2.x wrappers. moved tests/python/* to modules/python/test
This commit is contained in:
845
modules/python/src2/cv2.cpp
Normal file
845
modules/python/src2/cv2.cpp
Normal 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
759
modules/python/src2/gen2.py
Normal 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
683
modules/python/src2/hdr_parser.py
Executable 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)
|
||||
486
modules/python/src2/opencv_extra_api.hpp
Normal file
486
modules/python/src2/opencv_extra_api.hpp
Normal 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
|
||||
Reference in New Issue
Block a user