【PyBind11+anaconda+opencv+windows11+cmake+wsl+vscode】从入门到跑通。构建基于opencv c++的python接口

前言

为了使用C++ 编写python的扩展程序, 需要使用pybind11, pybind11使用比较简单,文档也比较详细。下面本人Windows系统上测试使用pybind11,本篇主要讲述简单样例与原理.平常使用的python实现都是cpython,所以使用C语言或者C++来写一些扩展的时候,就相当于在写cpython的插件。cpython的扩展关键在于要实现一个PyObject* PyInit_modulename(void)的函数,也叫initialization function,这个函数返回一个PyModuleDef 的instance。


开发/测试环境

Ubuntu系统

  • Ubuntu 18.04
  • pybind11
  • Anaconda3, with python 3.6
  • cmake

Windows系统

  • win10 64bit
  • Microsoft Visual Studio 2017
  • Anaconda3, with python 3.7

Pybind11

GitHub - pybind/pybind11: Seamless operability between C++11 and Python


安装配置

下载pybind11或者直接pip install pybind11
git clone https://github.com/pybind/pybind11.git

简单样例

添加一个c++ add算子

//ex.cpp
#include <pybind11/pybind11.h>

int add(int i, int j) {
    return i + j;
}

PYBIND11_MODULE(ex, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring
    m.def("add", &add, "A function which adds two numbers");
}

编译为so动态链接库,供pythonimport调用

#该编译命令会生成 ex.cpython-35m-x86_64-linux-gnu.so
g++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` ex.cpp -o gemfield`python3-config --extension-suffix`

python测试

>>> import ex
>>> ex.add(1,1)
2

那么看看PYBIND11_MODULE的宏展开之后执行了什么。

可以看到实现了PyObject *PyInit_ex()函数。

static void pybind11_init_ex(pybind11::module &); 
extern "C" __attribute__ ((visibility("default"))) PyObject *PyInit_ex() { 
    { 
        const char *compiled_ver ="3.8"; 
        const char *runtime_ver = Py_GetVersion(); 
        size_t len = std::strlen(compiled_ver); 
        if (std::strncmp(runtime_ver, compiled_ver, len) != 0 || (runtime_ver[len] >= '0' && runtime_ver[len] <= '9')) { 
            PyErr_Format(PyExc_ImportError, "Python version mismatch: module was compiled for Python %s, " "but the interpreter version is incompatible: %s.", compiled_ver, runtime_ver); 
            return nullptr; 
        } 
    } 
    auto m = pybind11::module("ex"); 
    try { 
        pybind11_init_ex(m); 
        return m.ptr(); 
    } catch (pybind11::error_already_set &e) { 
        PyErr_SetString(PyExc_ImportError, e.what()); 
        return nullptr; 
    } catch (const std::exception &e) { 
        PyErr_SetString(PyExc_ImportError, e.what()); 
        return nullptr; 
    } 
}

void pybind11_init_ex(pybind11::module &m){
    m.doc() = "pybind11 example plugin";
    m.def("add", &add, "A function which adds two numbers");
}

面向对象编写类

如何对c++类进行python绑定呢

#include <pybind11/pybind11.h>
#include <iostream>

extern "C" bool initav(const char* url);
class EXClass{
    public:
        EXClass(const std::string &url) : url(url){initav(url.c_str());}
        const std::string &getFrame() const;

    private:
        std::string url;
};

const std::string& EXClass::getFrame() const
{
    std::cout<< url << std::endl;
    return url;
}

PYBIND11_MODULE(cxvlass, m) {
    pybind11::class_<EXClass>(m, "EXClass")
        .def(pybind11::init<const std::string &>())
        .def("getFrame", &SYSZUXav::getFrame);
}

编译

g++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` syszuxav.cpp -o syszuxav`python3-config --extension-suffix`

同样展开宏查看,可以看到还是实现了

可以看到实现了PyObject *PyInit_exclass()函数。

extern "C" bool initav(const char* url);
class EXClass{
    public:
        EXClass(const std::string &url) : url(url){initav(url.c_str());}
        const std::string &getFrame() const;

    private:
        std::string url;
};

const std::string& EXClass::getFrame() const
{
    std::cout<< url << std::endl;
    return url;
}

static void pybind11_init_exclass(pybind11::module &); 
extern "C" __attribute__ ((visibility("default"))) PyObject *PyInit_exclass() 
{ 
    { 
        const char *compiled_ver = "3.8"; 
        const char *runtime_ver = Py_GetVersion(); 
        size_t len = std::strlen(compiled_ver); 
        if (std::strncmp(runtime_ver, compiled_ver, len) != 0 || (runtime_ver[len] >= '0' && runtime_ver[len] <= '9')) { 
            PyErr_Format(PyExc_ImportError, "Python version mismatch: module was compiled for Python %s, \
                    but the interpreter version is incompatible: %s.", compiled_ver, runtime_ver); 
            return nullptr;
        } 
    } 
    auto m = pybind11::module("exclass"); 
    try { 
        pybind11_init_exclass(m); 
        return m.ptr(); 
    } catch (pybind11::error_already_set &e) { 
        PyErr_SetString(PyExc_ImportError, e.what()); 
        return nullptr; 
    } catch (const std::exception &e) { 
        PyErr_SetString(PyExc_ImportError, e.what()); 
        return nullptr; 
    } 
} 
void pybind11_init_syszuxav(pybind11::module &m)
{
    pybind11::class_<SYSZUXav>(m, "SYSZUXav").def(pybind11::init<const std::string &>()).def("getFrame", &SYSZUXav::getFrame);
}

后续将会结合pip setup+opencv详细说明如何构建python package c++

猜你喜欢

转载自blog.csdn.net/weixin_43953700/article/details/123760942