【问题标题】:Exposing OpenCV-based C++ function with Mat/Numpy conversion to Python通过将 Mat/Numpy 转换为 Python 公开基于 OpenCV 的 C++ 函数
【发布时间】:2012-11-24 13:54:19
【问题描述】:

我在尝试使用 Numpy ndarray 将链接到 OpenCV 并使用 OpenCV 的 Mat 数据类型的动态 C++ 库函数公开到 Python 2.7 时遇到了问题.

我想出了一个类似于lightalchemist's solution here 的解决方案,我也尝试过使用 boost::python 和 boost::numpy(也链接到 Python 2.7)described in this SO question.

现在我坚持前者。我已经到了可以在 iPython 中加载模块的地步,并且我看到一个我正在尝试使用 inspect 模块移植的函数,我什至可以调用它并且它甚至可以执行。但是,当我尝试使用 NumpyAllocator (see lightalchemist's solution) 类将 Mat 对象转换回 ndarray 时,就会出现问题。 首先,当我尝试从外部 C++ 可执行文件中调用 pyopencv_from 函数,并且它使用 NumpyAllocator 进行编码时,它会出现段错误

PyEnsureGIL gil;

,每次都没有消息。 Lightalchemist 的解决方案不在 pyopencv_to 中使用它(编辑:如果传入的 ndarray 已经分配),它似乎可以工作。但是,官方的 OpenCV cv2.cpp 也确实使用了分配器,所以如果我尝试使用该函数,甚至无法将输入的 ndarray 转换为 Mat。

当我尝试使用 iPython 中的模块时,它会看到该函数。再次,它正确执行它(将进度打印到控制台),但是当它到达 pyopencv_from 时,它会出现段错误并终止 iPython shell。

编辑:我使用与 lightalchemist 完全相同的来源,只是我公开了一个函数,与官方 OpenCV 端口的方式相同:

static PyMethodDef methods[] = {
{"findEdgesCGTG", (PyCFunction)pycvex_findEdgesCGTG, METH_KEYWORDS, "findEdgesCGTG(source) -> edgeGradient, edgeOrientations"},
    {NULL, NULL}
};
extern "C"
#if defined WIN32 || defined _WIN32
__declspec(dllexport)
#endif
void initcvex()
{
  import_array();
  PyObject* m = Py_InitModule(MODULESTR, methods);
  PyObject* d = PyModule_GetDict(m);
  opencv_error = PyErr_NewException((char*)MODULESTR".error", NULL, NULL);
  PyDict_SetItemString(d, "error", opencv_error);
}

有人知道如何解决这个转换问题吗?

【问题讨论】:

    标签: python opencv numpy python-2.7 boost-python


    【解决方案1】:

    问题不在于

    PyEnsureGIL gil;
    

    声明。仅当我尝试使用外部 C++ 函数时,这才不起作用。当我在这里尝试将两个输出值合并为一个时,问题实际上发生了:

    return Py_BuildValue("(NN)", pyopencv_from(edgeGrad), pyopencv_from(edgeOri));
    

    临时解决方法是使用以下语句:

    return pyopencv_from(edgeGrad);
    

    编辑: 对不起,我又搞砸了。 Py_BuildValue 工作得很好。刚刚再次测试了我的功能,它运行良好。一定是我上次测试时忘记放return关键字了,所以它给了我“没有设置异常的错误返回”。

    这是完整的功能代码(我希望它对任何将 OpenCV 东西移植到 python 的人有用)

    static PyObject* pycvex_findEdgesCGTG(PyObject* , PyObject* args, PyObject* kw)
    {
        PyObject* pyobj_source = NULL;
        Mat source;
        Mat edgeGrad;
        Mat edgeOri;
        const char* keywords[] = { "src", NULL };
        if( PyArg_ParseTupleAndKeywords(args, kw, "O:findEdgesCGTG", (char**)keywords, &pyobj_source) &&
            pyopencv_to(pyobj_source, source));
        {
            ERRWRAP2(findEdgesCGTG(source,edgeGrad,edgeOri));
            return Py_BuildValue("(NN)", pyopencv_from(edgeGrad), pyopencv_from(edgeOri));
        }
        return NULL;
    }
    

    更新:

    这里是github repo 和我为使用 OpenCV 的 Mat 类以尽可能少的痛苦公开代码而编写的开放 C++ 代码。这适用于 OpenCV 3.X

    对于 OpenCV 2.X,您可以使用 this code / Yati Sagade 的示例。如果您想使用 opencv Mat 类公开函数而不用担心显式转换,很容易将我的代码中的 Boost 转换器与 Yati 代码中的转换函数相适应。

    【讨论】:

    • 嗨。也许您可以提供更多上下文,例如您的构建参数、调用代码等。您提到在 iPython 中运行代码时会崩溃。将它作为独立运行,即使用普通的 python 解释器怎么样?在那种情况下它也会崩溃吗?
    • @lightalchemist,我将在问题中发布构建参数和代码。谢谢你回到我身旁。它在 ipython 中并没有真正崩溃(只是外部测试可执行文件),只是给了我“没有设置异常的错误返回”。
    猜你喜欢
    • 2016-12-30
    • 1970-01-01
    • 1970-01-01
    • 2015-06-27
    • 2019-10-23
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多