在科学计算和数据处理领域,Python以其简单易用和丰富的生态系统而闻名。然而,在性能方面,C++通常比Python更高效。为了充分发挥两种语言的优势,我们可以使用Pybind11将C++代码绑定到Python,从而在Python中调用C++代码,实现高性能和易用性的完美结合。
Pybind11是一个用于创建Python绑定的轻量级库,它使得将C++代码绑定到Python非常简单。在本文中,我们将演示如何使用Pybind11将简单的C++函数绑定到Python,并在Python中调用这些函数。
打开Clion 编写配置文件CMakeLists.txt
注意:如果在拓展中需要使用 opencv 需要自己编译。网上很多教程。
并且用visual studio 编译 opencv, 生成lib 文件
项目结构:
// example.cpp
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <Eigen/Dense>
#include <opencv2/opencv.hpp>
namespace py = pybind11;
int add(int a, int b) {
return a + b;
}
py::list List(const py::list &l) {
py::list li;
for (int i = 0; i < l.size(); ++i)li.append(i);
li.append("str");
return li;
}
std::tuple<float, float> Tuple(float a, float b) {
// return std::make_tuple(a, b);
return {a, b};
}
std::tuple<double, double>
center(py::array_t<uint16_t> &np_arr) {
py::buffer_info buf = np_arr.request();
cv::Mat image(static_cast<int>(buf.shape[0]), static_cast<int>(buf.shape[1]),
CV_16UC1, (unsigned char *) buf.ptr);
cv::Moments m = moments(image, true);
double cx = m.m10 / m.m00;
double cy = m.m01 / m.m00;
return std::make_tuple(cx, cy);
}
std::tuple<Eigen::MatrixXd, double>
imageSun(Eigen::MatrixXd image, double energy = 1) {
image.array() += energy;
return std::make_tuple(image, image.sum());
}
PYBIND11_MODULE(example, m) {
m.doc() = "python example";
m.def("add", &add, "add 加法");
m.def("List", &List, py::arg("l") = nullptr, "传入List 返回List");
m.def("Tuple", &Tuple, py::arg("a"), py::arg("b"), "返回Tuple");
m.def("center",
¢er,
py::arg("image"),
"returns(center_x center_y)");
m.def("imageSun", &imageSun,
py::arg("image"),
py::arg("energy") = 1,// 默认参数=1
"returns(numpy_arr sum)");
}
// exampleclass.cpp
#include <string>
#include <pybind11/pybind11.h>
// ------------------
// regular C++ header
// ------------------
// parent class
class Animal {
public:
virtual std::string talk(int n_times) = 0;
};
// derived class
class Dog : public Animal {
public:
std::string talk(int n_times) override;
};
// derived class
class Cat : public Animal {
public:
std::string talk(int n_times) override;
};
// function that takes the parent and all derived classes
std::string talk(Animal &animal, int n_times = 1);
// ----------------
// regular C++ code
// ----------------
inline std::string Dog::talk(int n_times) {
std::string result;
for (int i = 0; i < n_times; ++i)
result += "woof! ";
return result;
}
inline std::string Cat::talk(int n_times) {
std::string result;
for (int i = 0; i < n_times; ++i)
result += "meow! ";
return result;
}
std::string talk(Animal &animal, int n_times) {
return animal.talk(n_times);
}
// -----------------------------
// Python interface - trampoline
// -----------------------------
class PyAnimal : public Animal {
public:
// inherit the constructors
using Animal::Animal;
// trampoline (one for each virtual function)
std::string talk(int n_times) override {
PYBIND11_OVERLOAD_PURE(
std::string, /* Return type */
Animal, /* Parent class */
talk, /* Name of function in C++ (must match Python name) */
n_times /* Argument(s) */
);
}
};
// ----------------
// Python interface
// ----------------
namespace py = pybind11;
PYBIND11_MODULE(exampleclass, m) {
py::class_<Animal, PyAnimal>(m, "Animal")
.def(py::init<>())
.def("talk", &Animal::talk);
py::class_<Dog, Animal>(m, "Dog")
.def(py::init<>());
py::class_<Cat, Animal>(m, "Cat")
.def(py::init<>());
m.def("talk", &talk, py::arg("animal"), py::arg("n_times") = 1);
}
# python setup.py sdist bdist_wheel
from setuptools import setup, Extension
module1 = Extension(
'PyExample.example',
include_dirs=['D:/library/include'],
sources=['PyExample/example.cpp'],
extra_compile_args=['-std:c++17', '-Zc:__cplusplus', '-permissive-', '-utf-8'],
)
module2 = Extension(
'PyExample.exampleclass',
include_dirs=['D:/library/include'],
sources=['PyExample/exampleclass.cpp'],
library_dirs=['D:/library/lib'],
libraries=['opencv_world480'],
extra_compile_args=['-std:c++17', '-Zc:__cplusplus', '-permissive-', '-utf-8'],
)
setup(
name='PyExample',
version='0.1',
packages=['PyExample'],
ext_modules=[module1, module2],
)
编译:
python setup.py sdist bdist_wheel
安装:
pip install Py***-0.0.0.tar.gz
或者
pip install Py***-0.0.0-cp311-cp311-win_amd64.whl
python 使用: