栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

将ndarray转换为cv :: Mat的最简单方法是什么?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

将ndarray转换为cv :: Mat的最简单方法是什么?

如kyamagu所建议,您可以使用OpenCV的官方python包装器代码,尤其是

pyopencv_to
and
pyopencv_from

我一直在像您一样处理所有依赖项和生成的头文件。然而,可以通过

cv2.cpp
像光炼金术士在这里那样“清洁”以仅保留必要的东西来降低其复杂性。您将需要使其适应您的需求和所使用的OpenCV版本,但其代码与我使用的基本相同。

#include <Python.h>#include "numpy/ndarrayobject.h"#include "opencv2/core/core.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;}class PyAllowThreads{public:    PyAllowThreads() : _state(Pyeval_SaveThread()) {}    ~PyAllowThreads()    {        Pyeval_RestoreThread(_state);    }private:    PyThreadState* _state;};class PyEnsureGIL{public:    PyEnsureGIL() : _state(PyGILState_Ensure()) {}    ~PyEnsureGIL()    {        PyGILState_Release(_state);    }private:    PyGILState_STATE _state;};#define ERRWRAP2(expr) try {     PyAllowThreads allowThreads;     expr; } catch (const cv::Exception &e) {     PyErr_SetString(opencv_error, e.what());     return 0; }using namespace cv;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*)"x78x56x34x12")*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)    {        PyEnsureGIL gil;        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 )        {      _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*, uchar*)    {        PyEnsureGIL gil;        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( PyInt_Check(o) )    {        double v[] = {PyInt_AsLong((PyObject*)o), 0., 0., 0.};        m = Mat(4, 1, CV_64F, v).clone();        return true;    }    if( PyFloat_Check(o) )    {        double v[] = {PyFloat_AsDouble((PyObject*)o), 0., 0., 0.};        m = Mat(4, 1, CV_64F, v).clone();        return true;    }    if( PyTuple_Check(o) )    {        int i, sz = (int)PyTuple_Size((PyObject*)o);        m = Mat(sz, 1, CV_64F);        for( i = 0; i < sz; i++ )        { PyObject* oi = PyTuple_GET_ITEM(o, i); if( PyInt_Check(oi) )     m.at<double>(i) = (double)PyInt_AsLong(oi); else if( PyFloat_Check(oi) )     m.at<double>(i) = (double)PyFloat_AsDouble(oi); else {     failmsg("%s is not a numerical tuple", name);     m.release();     return false; }        }        return true;    }    if( !PyArray_Check(o) )    {        failmsg("%s is not a numpy array, neither a scalar", name);        return false;    }    bool needcopy = false, needcast = false;    int typenum = PyArray_TYPE(o), new_typenum = typenum;    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 ? CV_32S :    typenum == NPY_INT32 ? CV_32S :    typenum == NPY_FLOAT ? CV_32F :    typenum == NPY_DOUBLE ? CV_64F : -1;    if( type < 0 )    {        if( typenum == NPY_INT64 || typenum == NPY_UINT64 || type == NPY_LONG )        { needcopy = needcast = true; new_typenum = NPY_INT; type = CV_32S;        }        else        { 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);    bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX;    for( int i = ndims-1; i >= 0 && !needcopy; i-- )    {        // these checks handle cases of        //  a) multi-dimensional (ndims > 2) arrays, as well as simpler 1- and 2-dimensional cases        //  b) transposed arrays, where _strides[] elements go in non-descending order        //  c) flipped arrays, where some of _strides[] elements are negative        if( (i == ndims-1 && (size_t)_strides[i] != elemsize) || (i < ndims-1 && _strides[i] < _strides[i+1]) ) needcopy = true;    }    if( ismultichannel && _strides[1] != (npy_intp)elemsize*_sizes[2] )        needcopy = true;    if (needcopy)    {        if( needcast ) o = (PyObject*)PyArray_Cast((PyArrayObject*)o, new_typenum);        else o = (PyObject*)PyArray_GETConTIGUOUS((PyArrayObject*)o);        _strides = PyArray_STRIDES(o);    }    for(int i = 0; i < ndims; i++)    {        size[i] = (int)_sizes[i];        step[i] = (size_t)_strides[i];    }    // handle degenerate case    if( ndims == 0) {        size[ndims] = 1;        step[ndims] = elemsize;        ndims++;    }    if( ismultichannel )    {        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);        if (!needcopy)        { 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){    if( !m.data )        Py_RETURN_NONE;    Mat temp, *p = (Mat*)&m;    if(!p->refcount || p->allocator != &g_numpyAllocator)    {        temp.allocator = &g_numpyAllocator;        ERRWRAP2(m.copyTo(temp));        p = &temp;    }    p->addref();    return pyObjectFromRefcount(p->refcount);}

清理

cv2.cpp
文件后,以下是一些Cython代码,负责转换。请注意该
import_array()
函数的定义和调用(这是NumPy函数,定义在其中的标头中
cv2.cpp
),这对于定义使用的宏是必要的
pyopencv_to
,如果不调用它,则会遇到lightalchemist指出的分段错误。

from cpython.ref cimport PyObject# Declares OpenCV's cv::Mat classcdef extern from "opencv2/core/core.hpp":    cdef cppclass Mat:        pass# Declares the official wrapper conversion functions + NumPy's import_array() functioncdef extern from "cv2.cpp":    void import_array()    PyObject* pyopencv_from(const _Mat&)    int pyopencv_to(PyObject*, _Mat&)# Function to be called at initializationcdef void init():    import_array()# Python to C++ conversioncdef Mat nparrayToMat(object array):    cdef Mat mat    cdef PyObject* pyobject = <PyObject*> array    pyopencv_to(pyobject, mat)    return <Mat> mat# C++ to Python conversioncdef object matTonparray(Mat mat):    return <object> pyopencv_from(mat)

注意:由于

import_array
宏中有一个奇怪的return语句,在编译时由于某种原因我在Fedora 20上遇到了NumPy
1.8.0错误,我不得不手动将其删除以使其工作,但我在NumPy的1.8中找不到此return语句.0 GitHub源代码



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/645042.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号