【PyBind11+anaconda+opencv+windows11+cmake+wsl+vscode】从入门到跑通。构建基于opencv c++的python package
如何安装请详见上文
【PyBind11+anaconda+opencv+windows11+cmake+wsl+vscode】从入门到跑通。构建基于opencv c++的python接口_子韵如初的博客-CSDN博客w不需要安装啥x11 、 xming直接mobxterm可以搞定点击右上角的X server打开可视化服务器然后 apt install x11-apps -yxclock 搞定从mobxterm可以看到display的端口X11显示可视化的原理是就是通过X协议,类似于http对linux于windows上进行通信。那么他们通信的ip地址就是这个DISPLAY=localhost:10.0比如一个XClinet要在屏幕 上输出一个圆,X应用程序只负责...https://blog.csdn.net/weixin_43953700/article/details/123760942计算机视觉-Paper&Code - 知乎V100 is all u needhttps://www.zhihu.com/column/c_1488286320929333249
第一步: 首先在C/C++ IDE中编写C/C++函数,然后采用pybind11封装为python可调用的包装函数, 之后采用C/C++编译器编译器生成.pyd文件
第二步:将生成的.pyd文件复制到python工程中,之后作为python module import导入使用
存在的问题
不同操作系统下直接调用生成的pyd可能会出错,不能跨平台调用
在上述过程中,pyd动态链接库的生成是在本地PC上,但是如果想在不同的操作系统、硬件平台上调用之前生成的pyd,显然是会出错的。比如在windows上编译生成了一个python扩展.pyd, 但是Ubuntu系统想调用这个python扩展就不行了。
解决方案
为了使得C/C++创建的python扩展可以跨平台使用,那么最简单的办法就是直接发布源码, 然后在该操作系统、硬件平台上编译生成python扩展。
因此本节内容利用python setuptools 方式实现
首先配置cmake编译不依赖外部工程链接
ex.cpp
#include<pybind11/pybind11.h>
#include<pybind11/numpy.h>
#include<fstream>
#include<iostream>
namespace py = pybind11;
class Matrix
{
public:
Matrix() {};
Matrix(int rows, int cols) {
this->m_rows = rows;
this->m_cols = cols;
m_data = new float[rows*cols];
}
~Matrix() {};
private:
int m_rows;
int m_cols;
float* m_data;
public:
float* data() { return m_data; };
int rows() { return m_rows; };
int cols() { return m_cols; };
};
void save_2d_numpy_array(py::array_t<float, py::array::c_style> a, std::string file_name) {
std::ofstream out;
out.open(file_name, std::ios::out);
std::cout << a.ndim() << std::endl;
for (int i = 0; i < a.ndim(); i++)
{
std::cout << a.shape()[i] << std::endl;
}
for (int i = 0; i < a.shape()[0]; i++)
{
for (int j = 0; j < a.shape()[1]; j++)
{
if (j == a.shape()[1]-1)
{
//访问读取,索引 numpy.ndarray 中的元素
out << a.at(i, j)<< std::endl;
}
else {
out << a.at(i, j) << " ";
}
}
}
}
PYBIND11_MODULE(numpy_demo, m) {
m.doc() = "Simple numpy demo";
py::class_<Matrix>(m,"Matrix",py::buffer_protocol())
.def_buffer([](Matrix& mm)->py::buffer_info {
return py::buffer_info(
mm.data(), //Pointer to buffer, 数据指针
sizeof(float), //Size of one scalar, 每个元素大小(byte)
py::format_descriptor<float>::format(), //python struct-style foramt descriptor
2, //Number of dims, 维度
{mm.rows(), mm.cols()}, //strides (in bytes)
{sizeof(float) * mm.cols(),sizeof(float)}
);
});
m.def("save_2d_numpy_array", &save_2d_numpy_array);
}
setup.py使用pip安装install,生成numpy_demo.cpython-38-x86_64-linux-gnu.so
python setup.py build_ext --inplace build_ext: 给python编译一个c、c++的拓展 -–inplace: 忽略build-lib,将编译后的扩展放到源目录中,与纯Python模块放在一起
from setuptools import setup
from setuptools import Extension
example_module = Extension(name='numpy_demo', # 模块名称
sources=['ex.cpp'], # 源码
include_dirs=[r'/root/anaconda3/envs/py3/lib/python3.8/site-packages/pybind11/include']
)
setup(ext_modules=[example_module])
# build_ext:build C/C++ extensions (compile/link to build directory),给python编译一个c、c++的拓展
# –inplace:ignore build-lib and put compiled extensions into the source directory alongside your pure Python modules,忽略build-lib,将编译后的扩展放到源目录中,与纯Python模块放在一起
# python setup.py build_ext --inplace
test.py测试
import numpy as np
import numpy_demo
from numpy_demo import Matrix
res = numpy_demo.save_2d_numpy_array(np.zeros(shape=[4,7], dtype=np.float32), './data.dat')
print(Matrix.__dict__)
print(Matrix)
如果需要引用opencv怎么做
上面c++的拓展,只是使用了pybind11
因此继续编辑c++代码
main.cpp
#include<iostream>
#include<vector>
#include<opencv2/opencv.hpp>
#include<pybind11/pybind11.h>
#include<pybind11/numpy.h>
#include<pybind11/stl.h>
#include"wrapper.h"
namespace py = pybind11;
py::array_t<unsigned char> test_rgb_to_gray(py::array_t<unsigned char>& input) {
cv::Mat img_rgb = numpy_uint8_3c_to_cv_mat(input);
cv::Mat dst;
cv::cvtColor(img_rgb, dst, cv::COLOR_RGB2GRAY);
return cv_mat_uint8_1c_to_numpy(dst);
}
/*
@return Python list
*/
py::list test_pyramid_image(py::array_t<unsigned char>& input) {
cv::Mat src = numpy_uint8_1c_to_cv_mat(input);
std::vector<cv::Mat> dst;
cv::buildPyramid(src, dst, 4);
py::list out;
for (int i = 0; i < dst.size(); i++)
{
out.append<py::array_t<unsigned char>>(cv_mat_uint8_1c_to_numpy(dst.at(i)));
}
return out;
}
PYBIND11_MODULE(cv_demo1, m) {
m.doc() = "Simple opencv demo";
m.def("test_rgb_to_gray1", &test_rgb_to_gray);
m.def("test_gray_canny1", &test_gray_canny);
m.def("test_pyramid_image1", &test_pyramid_image);
}
wrapper.h
#ifndef WRAPPER_H_
#include<opencv2/opencv.hpp>
#include<pybind11/pybind11.h>
#include<pybind11/numpy.h>
namespace py = pybind11;
cv::Mat numpy_uint8_1c_to_cv_mat(py::array_t<unsigned char>& input);
cv::Mat numpy_uint8_3c_to_cv_mat(py::array_t<unsigned char>& input);
py::array_t<unsigned char> cv_mat_uint8_1c_to_numpy(cv::Mat & input);
py::array_t<unsigned char> cv_mat_uint8_3c_to_numpy(cv::Mat & input);
#endif // !WRAPPER_H_
wrapper.cpp
#include"wrapper.h"
#include <pybind11/numpy.h>
cv::Mat numpy_uint8_1c_to_cv_mat(py::array_t<unsigned char>& input) {
if (input.ndim() != 2)
throw std::runtime_error("1-channel image must be 2 dims ");
py::buffer_info buf = input.request();
cv::Mat mat(buf.shape[0], buf.shape[1], CV_8UC1, (unsigned char*)buf.ptr);
return mat;
}
cv::Mat numpy_uint8_3c_to_cv_mat(py::array_t<unsigned char>& input) {
if (input.ndim() != 3)
throw std::runtime_error("3-channel image must be 3 dims ");
py::buffer_info buf = input.request();
cv::Mat mat(buf.shape[0], buf.shape[1], CV_8UC3, (unsigned char*)buf.ptr);
return mat;
}
/*
C++ Mat ->numpy
*/
py::array_t<unsigned char> cv_mat_uint8_1c_to_numpy(cv::Mat& input) {
py::array_t<unsigned char> dst = py::array_t<unsigned char>({ input.rows,input.cols }, input.data);
return dst;
}
py::array_t<unsigned char> cv_mat_uint8_3c_to_numpy(cv::Mat& input) {
py::array_t<unsigned char> dst = py::array_t<unsigned char>({ input.rows,input.cols,3}, input.data);
return dst;
}
setup.py
其中需要注意的是
- include_dirs:指定pybind11,和opencv include的路径
- library_dirs:指定使用的动态库,静态库的路径
- libraries:指定使用的库名称,原文章是将opencv编译成了opencv_world库的
from setuptools import Extension
from setuptools import setup
__version__ = '0.0.1'
# 扩展模块
ext_module = Extension(
# 模块名称
name='cv_demo1',
# 源码
sources=[r'wrapper.cpp', r'main.cpp'],
# 包含头文件
include_dirs=[r'/usr/local/include',
r'/root/anaconda3/envs/py3/lib/python3.8/site-packages/pybind11/include' ],
# 库目录
library_dirs=[r'/usr/local/lib'],
# 链接库文件
libraries=[r'opencv_core', r'opencv_imgproc'],
language='c++'
)
setup(
name='cv_demo1',
description='A simaple demo',
ext_modules=[ext_module],
install_requires=['numpy']
)
python setup.py build_ext --inplace编辑成so文件,编写test.py查看结果
test.py
import cv_demo1 as cv_demo
import numpy as np
import cv2
import matplotlib.pyplot as plt
# help(cv_demo)
image = cv2.imread('./8.jpg', cv2.IMREAD_GRAYSCALE)
# rgb to gray
plt.figure('rgb->gray')
img_gray = cv_demo.test_rgb_to_gray1(cv2.imread('./8.jpg'))
plt.imshow(img_gray)
plt.show()
总体代码结构如下
更多推荐
所有评论(0)