You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
459 lines
13 KiB
OpenEdge ABL
459 lines
13 KiB
OpenEdge ABL
%{
|
|
#define SWIG_FILE_WITH_INIT
|
|
|
|
#if ((PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 6) || \
|
|
(PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION > 0) || \
|
|
(PY_MAJOR_VERSION > 3))
|
|
#define CAPSULES_SUPPORTED
|
|
#endif
|
|
%}
|
|
|
|
%include "numpy.i"
|
|
%init %{
|
|
import_array();
|
|
%}
|
|
|
|
%fragment("OKAPI_Fragments", "header",
|
|
fragment="NumPy_Fragments")
|
|
{
|
|
// convert NumPy type to OpenCV type
|
|
int numpy_type_to_mat_type(PyArrayObject *array, int channels)
|
|
{
|
|
switch (array_type(array)) {
|
|
case NPY_BYTE: return CV_MAKETYPE(CV_8S, channels);
|
|
case NPY_UBYTE: return CV_MAKETYPE(CV_8U, channels);
|
|
case NPY_SHORT: return CV_MAKETYPE(CV_16S, channels);
|
|
case NPY_USHORT: return CV_MAKETYPE(CV_16U, channels);
|
|
case NPY_INT: return CV_MAKETYPE(CV_32S, channels);
|
|
//case NPY_UINT: // does not exist
|
|
//case NPY_LONG: // does not exist
|
|
//case NPY_ULONG: // does not exist
|
|
case NPY_FLOAT: return CV_MAKETYPE(CV_32F, channels);
|
|
case NPY_DOUBLE: return CV_MAKETYPE(CV_64F, channels);
|
|
default:
|
|
PyErr_Format(PyExc_TypeError,
|
|
"Unsupported datatype: %s.",
|
|
typecode_string(array_type(array)));
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// convert OpenCV type to NumPy type
|
|
int mat_type_to_numpy_type(int type)
|
|
{
|
|
// convert numpy type to CV type
|
|
switch (CV_MAT_DEPTH(type)) {
|
|
case CV_8S: return NPY_BYTE;
|
|
case CV_8U: return NPY_UBYTE;
|
|
case CV_16S: return NPY_SHORT;
|
|
case CV_16U: return NPY_USHORT;
|
|
case CV_32S: return NPY_INT;
|
|
//case NPY_UINT: // does not exist
|
|
//case NPY_LONG: // does not exist
|
|
//case NPY_ULONG: // does not exist
|
|
case CV_32F: return NPY_FLOAT;
|
|
case CV_64F: return NPY_DOUBLE;
|
|
default:
|
|
PyErr_Format(PyExc_TypeError,
|
|
"Unsupported OpenCV datatype: %d (depth: %d).",
|
|
type, CV_MAT_DEPTH(type));
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void delete_mat(void *ptr)
|
|
{
|
|
// printf("deleting underlying mat at %p\n", ptr);
|
|
cv::Mat *m = static_cast<cv::Mat*>(ptr);
|
|
assert (m != NULL);
|
|
delete m;
|
|
}
|
|
|
|
%#ifdef CAPSULES_SUPPORTED
|
|
void delete_mat_capsule(PyObject *obj)
|
|
{
|
|
// printf("deleting underlying mat at %p\n", ptr);
|
|
cv::Mat *m = static_cast<cv::Mat*>(PyCapsule_GetPointer(obj, NULL));
|
|
assert (m != NULL);
|
|
delete m;
|
|
}
|
|
%#endif
|
|
|
|
cv::Mat* array_to_mat(PyObject* input)
|
|
{
|
|
PyArrayObject* array = obj_to_array_no_conversion(input, NPY_NOTYPE);
|
|
if (array == NULL) {
|
|
// error message is set by obj_to_array_no_conversion
|
|
return NULL;
|
|
}
|
|
|
|
// check if array has 2 or 3 dimensions
|
|
int ndims = array_numdims(array);
|
|
int channels, type;
|
|
if (ndims == 2)
|
|
channels = 1;
|
|
else if (ndims == 3) {
|
|
channels = array_size(array, 2);
|
|
// check number of channels
|
|
if (channels > 4) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"Array can have a maximum of 4 channels. Input as %d.", channels);
|
|
return NULL;
|
|
}
|
|
}
|
|
else {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"Array must be 2- or 3-dimensional. Input is %d-dimensional.", ndims);
|
|
return NULL;
|
|
}
|
|
|
|
// convert NumPy type to OpenCV type
|
|
if ((type = numpy_type_to_mat_type(array, channels)) == -1)
|
|
return NULL;
|
|
|
|
// check that array is in C order
|
|
for (int i = 0; i < ndims-1; ++i) {
|
|
if (PyArray_STRIDE(array, i) < PyArray_STRIDE(array, i+1)) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"Array is not in C order: stride of dim %d: %ld < stride of dim %d: %ld",
|
|
i, PyArray_STRIDE(array, i), i+1, PyArray_STRIDE(array, i+1));
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// use stride of first dimension as stepsize
|
|
// and check strides of other dimensions
|
|
int step = ((PyArrayObject *)array)->strides[0];
|
|
if (PyArray_STRIDE(array, 1) != channels * PyArray_ITEMSIZE(array)) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"Array cannot have strides in other than 1st dimension (rows). Dim 2: %ld vs %d",
|
|
PyArray_STRIDE(array, 1), channels * PyArray_ITEMSIZE(array));
|
|
return NULL;
|
|
}
|
|
|
|
// create new view onto the data
|
|
return new cv::Mat(array_size(array, 0), array_size(array, 1), type, array_data(array), step);
|
|
}
|
|
|
|
PyObject* mat_to_array(const cv::Mat& mat)
|
|
{
|
|
// handle empty mat
|
|
if (mat.empty()) {
|
|
npy_intp dims[1] = { 0 };
|
|
int type = mat_type_to_numpy_type(mat.type());
|
|
PyObject* array = PyArray_EMPTY(1, dims, type, 0);
|
|
return array;
|
|
}
|
|
|
|
npy_intp dims[3] = { mat.rows, mat.cols, mat.channels() };
|
|
npy_intp strides[3] = { mat.step, mat.elemSize(), mat.elemSize1()};
|
|
int ndims = (mat.channels() > 1) ? 3 : 2;
|
|
int type = mat_type_to_numpy_type(mat.type());
|
|
int flags = NPY_WRITEABLE;
|
|
if (mat.isContinuous())
|
|
flags |= NPY_C_CONTIGUOUS;
|
|
PyObject* array = PyArray_New(&PyArray_Type, ndims, dims, type,
|
|
strides, mat.data, 0, flags, NULL);
|
|
return array;
|
|
}
|
|
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
/// const cv::Mat&
|
|
///////////////////////////////////////
|
|
%typecheck(SWIG_TYPECHECK_POINTER,
|
|
fragment="OKAPI_Fragments")
|
|
const cv::Mat&
|
|
{
|
|
$1 = is_array($input) || PySequence_Check($input);
|
|
}
|
|
%typemap(in, numinputs=1,
|
|
fragment="OKAPI_Fragments")
|
|
const cv::Mat&
|
|
{
|
|
$1 = array_to_mat($input);
|
|
if ($1 == NULL)
|
|
SWIG_fail;
|
|
}
|
|
%typemap(freearg,
|
|
fragment="OKAPI_Fragments")
|
|
const cv::Mat&
|
|
{
|
|
if ($1 != NULL)
|
|
delete $1;
|
|
}
|
|
%typemap(argout,
|
|
fragment="OKAPI_Fragments")
|
|
const cv::Mat&
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
/// cv::Mat
|
|
///////////////////////////////////////
|
|
%typecheck(SWIG_TYPECHECK_POINTER,
|
|
fragment="OKAPI_Fragments")
|
|
cv::Mat
|
|
{
|
|
$1 = is_array($input) || PySequence_Check($input);
|
|
}
|
|
%typemap(in, numinputs=1,
|
|
fragment="OKAPI_Fragments")
|
|
cv::Mat
|
|
(cv::Mat* mat)
|
|
{
|
|
mat = array_to_mat($input);
|
|
if (mat == NULL)
|
|
SWIG_fail;
|
|
$1 = *mat;
|
|
}
|
|
%typemap(freearg,
|
|
fragment="OKAPI_Fragments")
|
|
cv::Mat
|
|
{
|
|
if (mat$argnum != NULL)
|
|
delete mat$argnum;
|
|
}
|
|
%typemap(argout,
|
|
fragment="OKAPI_Fragments")
|
|
cv::Mat
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
/// cv::Mat*
|
|
///////////////////////////////////////
|
|
%typecheck(SWIG_TYPECHECK_POINTER,
|
|
fragment="OKAPI_Fragments")
|
|
cv::Mat*
|
|
{
|
|
$1 = is_array($input) || PySequence_Check($input);
|
|
}
|
|
%typemap(in, numinputs=1,
|
|
fragment="OKAPI_Fragments")
|
|
cv::Mat*
|
|
(uchar* data_ptr)
|
|
{
|
|
$1 = array_to_mat($input);
|
|
if ($1 == NULL)
|
|
SWIG_fail;
|
|
// save dataptr to check whether it changed
|
|
data_ptr = $1->data;
|
|
}
|
|
%typemap(freearg,
|
|
fragment="OKAPI_Fragments")
|
|
cv::Mat*
|
|
{
|
|
if ($1 != NULL)
|
|
delete $1;
|
|
}
|
|
%typemap(argout,
|
|
fragment="OKAPI_Fragments")
|
|
cv::Mat*
|
|
{
|
|
// check if the underlying data changed
|
|
if (data_ptr$argnum != $1->data) {
|
|
// TODO don't fail if we can reallocate the underlying memory
|
|
// (not always possible due to the way NumPy does reference counting)
|
|
PyErr_Format(PyExc_RuntimeError,
|
|
"Underlying data changed. Please make sure that the "
|
|
"input data is of correct size and type: %d %d %d",
|
|
$1->rows, $1->cols, $1->type());
|
|
SWIG_fail;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
/// cv::Mat&
|
|
///////////////////////////////////////
|
|
%typecheck(SWIG_TYPECHECK_POINTER,
|
|
fragment="OKAPI_Fragments")
|
|
cv::Mat&
|
|
{
|
|
$1 = is_array($input) || PySequence_Check($input);
|
|
}
|
|
%typemap(in, numinputs=1,
|
|
fragment="OKAPI_Fragments")
|
|
cv::Mat&
|
|
(uchar* data_ptr)
|
|
{
|
|
$1 = array_to_mat($input);
|
|
if ($1 == NULL)
|
|
SWIG_fail;
|
|
// save dataptr to check whether it changed
|
|
data_ptr = $1->data;
|
|
}
|
|
%typemap(freearg,
|
|
fragment="OKAPI_Fragments")
|
|
cv::Mat&
|
|
{
|
|
if ($1 != NULL)
|
|
delete $1;
|
|
}
|
|
%typemap(argout,
|
|
fragment="OKAPI_Fragments")
|
|
cv::Mat&
|
|
{
|
|
// check if the underlying data changed
|
|
if (data_ptr$argnum != $1->data) {
|
|
// TODO don't fail if we can reallocate the underlying memory
|
|
// (not always possible due to the way NumPy does reference counting)
|
|
PyErr_Format(PyExc_RuntimeError,
|
|
"Underlying data changed. Please make sure that the "
|
|
"input data is of correct size and type: %d %d %d",
|
|
$1->rows, $1->cols, $1->type());
|
|
SWIG_fail;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
/// return cv::Mat
|
|
///////////////////////////////////////
|
|
%typemap(out,
|
|
fragment="NumPy_Fragments")
|
|
cv::Mat
|
|
{
|
|
PyObject* array = mat_to_array($1);
|
|
if (array == NULL)
|
|
SWIG_fail;
|
|
|
|
// add a reference to the underlying cv::Mat so
|
|
// that the memory is not freed before the NumPy array
|
|
// is released or reassigned
|
|
cv::Mat *m = new cv::Mat($1);
|
|
// printf("created new mat object at %p\n", m);
|
|
%#ifdef CAPSULES_SUPPORTED
|
|
PyArray_BASE(array) = PyCapsule_New(m, NULL, delete_mat_capsule);
|
|
%#else
|
|
PyArray_BASE(array) = PyCObject_FromVoidPtr(m, delete_mat);
|
|
%#endif
|
|
|
|
$result = array;
|
|
}
|
|
|
|
%typemap(out,
|
|
fragment="NumPy_Fragments")
|
|
const cv::Mat&
|
|
{
|
|
PyObject* array = mat_to_array(*$1);
|
|
if (array == NULL)
|
|
SWIG_fail;
|
|
|
|
// add a reference to the underlying cv::Mat so
|
|
// that the memory is not freed before the NumPy array
|
|
// is released or reassigned
|
|
cv::Mat *m = new cv::Mat(*$1);
|
|
// printf("created new mat object at %p\n", m);
|
|
%#ifdef CAPSULES_SUPPORTED
|
|
PyArray_BASE(array) = PyCapsule_New(m, NULL, delete_mat_capsule);
|
|
%#else
|
|
PyArray_BASE(array) = PyCObject_FromVoidPtr(m, delete_mat);
|
|
%#endif
|
|
|
|
$result = array;
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
// vector<cv::Mat>
|
|
///////////////////////////////////////
|
|
%define %vector_typemap(T)
|
|
%typecheck(SWIG_TYPECHECK_POINTER,
|
|
fragment="OKAPI_Fragments")
|
|
const std::vector<T> &
|
|
{
|
|
$1 = PySequence_Check($input);
|
|
}
|
|
%typemap(in,
|
|
fragment="OKAPI_Fragments")
|
|
const std::vector<T> &
|
|
(std::vector<T*> relvec)
|
|
{
|
|
if (!PySequence_Check($input)) {
|
|
printf("NO SEQUENCE\n");
|
|
SWIG_fail;
|
|
}
|
|
|
|
Py_ssize_t length = PySequence_Size($input);
|
|
$1 = new std::vector<cv::Mat>(length);
|
|
for (Py_ssize_t ii = 0; ii < length; ++ii) {
|
|
cv::Mat *tmp = array_to_mat(PySequence_GetItem($input, ii));
|
|
if (tmp == NULL) {
|
|
printf("%ld no array\n", ii);
|
|
SWIG_fail;
|
|
}
|
|
$1->at(ii) = *tmp;
|
|
relvec.push_back(tmp);
|
|
}
|
|
}
|
|
%typemap(freearg,
|
|
fragment="OKAPI_Fragments")
|
|
const std::vector<T> &
|
|
{
|
|
if ($1 != NULL)
|
|
delete $1;
|
|
for (size_t ii = 0; ii < relvec$argnum.size(); ++ii)
|
|
delete relvec$argnum[ii];
|
|
}
|
|
%enddef
|
|
|
|
|
|
///////////////////////////////////////
|
|
// okapi::bstring
|
|
///////////////////////////////////////
|
|
%typemap(out) okapi::bstring
|
|
{
|
|
$result = PyByteArray_FromStringAndSize((const char*) &$1[0], $1.size());
|
|
}
|
|
|
|
|
|
///////////////////////////////////////
|
|
// buffers
|
|
///////////////////////////////////////
|
|
%typemap(in) (const void *buffer, std::size_t buffer_size) {
|
|
if (PyByteArray_Check($input)) {
|
|
$1 = (void *) PyByteArray_AsString($input);
|
|
$2 = PyByteArray_Size($input);
|
|
}
|
|
%#if PY_MAJOR_VERSION < 3
|
|
else if (PyString_Check($input)) {
|
|
$1 = (void *) PyString_AsString($input);
|
|
$2 = PyString_Size($input);
|
|
}
|
|
%#endif
|
|
else {
|
|
PyErr_SetString(PyExc_ValueError, "Expecting a bytearray");
|
|
return NULL;
|
|
}
|
|
}
|
|
%typemap(typecheck) (const void *buffer, std::size_t buffer_size) {
|
|
$1 = (PyByteArray_Check($input) || PyString_Check($input)) ? 1 : 0;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////
|
|
// boost::filesystem::path
|
|
///////////////////////////////////////
|
|
%typecheck(SWIG_TYPECHECK_POINTER)
|
|
const boost::filesystem::path &
|
|
{
|
|
$1 = PyUnicode_Check($input) || PyBytes_Check($input);
|
|
}
|
|
%typemap(in) const boost::filesystem::path &
|
|
{
|
|
if (PyUnicode_Check($input))
|
|
{
|
|
PyObject *bytes = PyUnicode_AsEncodedString($input, Py_FileSystemDefaultEncoding, "surrogateescape");
|
|
$1 = new boost::filesystem::path(PyBytes_AsString(bytes));
|
|
Py_CLEAR(bytes);
|
|
}
|
|
else if (PyBytes_Check($input))
|
|
{
|
|
$1 = new boost::filesystem::path(PyBytes_AsString($input));
|
|
}
|
|
}
|
|
%typemap(freearg) const boost::filesystem::path
|
|
{
|
|
delete $1;
|
|
}
|