首页 > 系统相关 >pybind11使用记录---ubuntu下使用cmake编译c++工程为python库

pybind11使用记录---ubuntu下使用cmake编译c++工程为python库

时间:2022-08-25 19:55:52浏览次数:179  
标签:cmake python py c++ SOURCE pybind11 pcc


前言:

因为最近c++下的工程需要在python下调用,所以需要把c++编译成可供python调用的库,记录一下具体做法:

编译c++有多种方法,因为我的是cmake构建的工程,所以直接在cmake的基础上编译成python库(c++中用了第三方库opencv和boost)


 下载编译pybind11

下载pybind11:git clone https://github.com/pybind/pybind11.git

安装pytest: pip install pytest

编译:

 
  cd pybind11   mkdir build   cd build   cmake ..   cmake --build . --config Release --target check
 
 

操作C++代码

我的做法是将编译好的pybind11文件夹拷贝到了c++工程目录下(这样是方便在编译c++的时候能找到pybind11,当然你也可以通过其他方式,只要能找到pybind11就行)

 (我只封装了所需要的函数接口)

将你需要的函数接口定义在一个.cpp文件中,比如说,我在pcc.cpp文件中定义了两个函数(该包含的.h文件就正常包含):

int pcc_encoder() 和 int pcc_decoder()

然后在此文件中加入如下代码:

 
  #include <pybind11/pybind11.h>       namespace py = pybind11;   PYBIND11_PLUGIN(Pypcc) {   py::module m("Pypcc", "pcc python module");       m.def("pcc_encoder", &pcc_encoder, "Encoder the pointcloud data");   m.def("pcc_decoder", &pcc_decoder, "Decoder the pointcloud data");       return m.ptr();   }
 
 

 其中比较重要的是这两句:

m.def("pcc_encoder", &pcc_encoder, "Encoder the pointcloud data");

m.def("pcc_decoder", &pcc_decoder, "Decoder the pointcloud data");

这两句代码表明了可供python调用的函数接口,没有在此操作的函数python是找不到的

 修改CMakeLists.txt

(只需改动几处即可,第三方库的include和链接基本和c++编译一样)

 
  PROJECT(compression)   CMAKE_MINIMUM_REQUIRED(VERSION 2.1.8)       add_definitions(-std=c++11)       find_package(Boost COMPONENTS system thread program_options)   find_package(OpenCV QUIET)       set(LIBRARY_OUTPUT_PATH ../)       set(dso_SOURCE_FILES   ${PROJECT_SOURCE_DIR}/src/decoder.cpp   ${PROJECT_SOURCE_DIR}/src/encoder.cpp   ${PROJECT_SOURCE_DIR}/src/utils.cpp   ${PROJECT_SOURCE_DIR}/src/io.cpp   ${PROJECT_SOURCE_DIR}/src/pcc_module.cpp   )       #add_library(pcc SHARED ${dso_SOURCE_FILES})       include_directories(   ${PROJECT_SOURCE_DIR}/include   ${OpenCV_INCLUDE_DIRS}   ${Boost_INCLUDE_DIRS}   )       add_subdirectory(pybind11)   pybind11_add_module(Pypcc ${PROJECT_SOURCE_DIR}/src/pcc.cpp ${dso_SOURCE_FILES})   #add_executable(pcc_test ${PROJECT_SOURCE_DIR}/src/pcc_test.cpp ${dso_SOURCE_FILES})   #add_executable(pcc_test ${PROJECT_SOURCE_DIR}/src/pcc_test.cpp)   target_link_libraries(Pypcc PRIVATE   ${Boost_LIBRARIES}   ${OpenCV_LIBS}   )
 
 

可以看到只需要修改原本文件的几个地方就可以:

set(LIBRARY_OUTPUT_PATH ../)

这个的意思是设置生成的python库的位置

 

add_subdirectory(pybind11)

这个是用来增加pybind11的目录,因为之前我把pybind11放在了c++的工程目录下,所以可以直接顺利找到

 

pybind11_add_module(Pypcc ${PROJECT_SOURCE_DIR}/src/pcc.cpp ${dso_SOURCE_FILES})

这个的意思对应于编译c++的add_executable命令,就是说把哪些文件编译成python库,Pypcc是取的库的名字

 

target_link_libraries(Pypcc PRIVATE

  ${Boost_LIBRARIES}

  ${OpenCV_LIBS}

)

这里是链接第三方库,注意要加上PRIVATE

 然后按照一般的c++编译步骤就可以了(进入到新建的build文件夹,执行cmake .. 再执行make),编译完成之后我们可以看到在指定目录下生成.so文件

 编写python调用文件

 
  import Pypcc #导入.so模块   Pypcc.XXX() #调用模块的函数
 
 

这里说明一下:因为我的.so文件放在了和.py文件同一目录下,所以可以直接导入

 遇到的问题:

  •  因为我的.so文件是在python3.6的环境下编译的,所以python2.7环境下导入报出没有这个模块的错误,原因到底是编译c++环境的原因,还是一开始编译pybind11默认的python环境的原因?后续可以验证一下

这个问题已经解决了:

在编译自己的c++项目的时候,一般来说需要在build中先cmake ..生成makefile文件,如果在这里我们不指定python版本的时候,就会寻找到默认的python版本,比如在我的环境下执行cnake ..,有如下信息输出:

 
  -- Found PythonInterp: /usr/bin/python3.6 (found version "3.6.9")   -- Found PythonLibs: /usr/lib/x86_64-linux-gnu/libpython3.6m.so
 
 

说明此时的python版本是3.6 ,而如果我们想利用pyhton2.7(其他版本也一样,前提是系统里安装了相应的python版本或者虚拟环境),那么在cmake ..的时候就要指定python为2.7版本:在python2.7安装的位置找到库文件/头文件/可执行文件

 
  cmake -DPYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython2.7.so \   -DPYTHON_INCLUDE_DIR=/usr/include/python2.7 \   -DPYTHON_EXECUTABLE=/usr/bin/python2.7 \   ..
 
 

 这时候给出的cmake信息为:

 
  1.   -- Found PythonInterp: /usr/bin/python2.7 (found version "2.7.17")
  2.   -- Found PythonLibs: /usr/lib/x86_64-linux-gnu/libpython2.7.so
 
 

 然后执行make命令,就会生成可供python2.7导入调用的库

  • 因为我需要传二维数组给这个参数,考虑到python和c++之间用纯c语言“沟通”可能会好一点,所以打算以这样的方式传参:

float points[][4]

int nums

但是在编译的时候报出错误:

cannot convert ‘pybind11::detail::type_caster<float, void>::cast_op_type<float (*&&)[4]> {aka float*}’ to ‘float (*)[4]’ in argument passing

看到有人说pybind11不支持这种指针类型???这里还没弄清楚

后面我的解决方法是使用STL vector进行传参的,c++中的STL与python是有类型对应的:

前提是要在之前的.cpp文件中包含一个头文件

#include <pybind11/stl.h>
 

 

  • 在c++中,一般在.h中声明一个函数的时候,可以赋给参数默认值,这样在调用的时候如果默认值的参数没有传进来,那么函数就是用其默认值,但是如果某个函数作为python接口供python调用,即使在c++中声明了默认值,python调用的时候也要将全部参数传参,否则会出现参数不匹配的错误

与opencv通信

 最近遇到的问题是希望使用Python cv2读取图片,然后将其传入到c++中处理,这实际上涉及到opencv读取图像在Python和C++中的转换问题.

在C++中读取的图片类型是cv::Mat, 这是opencv中定义的类型,使用起来很方便,在Python中读取的图片类型是numpy.ndarray类,也就是第三方库numpy的类型, 因此需要定义函数对其进行转换,这里引用了https://blog.csdn.net/non_hercules/article/details/105095153/ 的工作:

 
  //在c++中代码中将cv::Mat与py::array_t<unsigned char>进行转换   //py::array_t<unsigned char>就是c++中接收到的Python传过来的图像的类型       /*   Python->C++ Mat   */           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;   }       //注意,在c++中应包含 #include<pybind11/numpy.h>
 
   

标签:cmake,python,py,c++,SOURCE,pybind11,pcc
From: https://www.cnblogs.com/lidabo/p/16625524.html

相关文章

  • mac上sublime的配置,支持c++11且支持输入
    支持c++11且可从终端输入在sublime下打开tools然后newbuildsystem,在出来的文件中写入如下:{"cmd":["bash","-c","g++'${file}'-std=c++11-stdlib=libc++......
  • cmake引入opencv和qt
    cmake_minimum_required(VERSION3.14)project(CMake_demoLANGUAGESCXX)set(CMAKE_INCLUDE_CURRENT_DIRON)set(CMAKE_AUTOUICON)set(CMAKE_AUTOMOCON)set(CMA......
  • python基础——闭包 装饰器
    闭包函数嵌套,即外部函数嵌套一个内部函数;外部函数返回内部函数引用;内部函数使用外部函数的变量或者形参#简单演示#deff1(x):##deff2():#prin......
  • pythoncom 无法import win32api、win32con、win32com、win32gui 问题一次解决!方法合集
    最近写项目发现pythoncom导入win32api、win32con、win32com、win32gui等win32相关的包都会出现或多或少问题,Google一大堆不靠谱的方法试了个遍。特此记录一下解决办法......
  • C++类型转换
    const_cast一般用于去除const属性,将常量转变为非常量 dynamic_cast一般用于多态转换,有运行时安全检测 static_cast对比dynamic_cast没有运行时安全检测非同一继......
  • 阅读《计算机图形学编程(使用OpenGL和C++)》8 - 纹理贴图
    纹理贴图就是将图片贴到模型上,让模型看起来更真实。纹理贴图非常重要,因此硬件也为它提供了支持,使得它具备了实现实时的照片级真实感的超高性能。纹理单元是专为纹理设计的......
  • python selenium使用无头模式执行用例
    什么是无头模式?HeadlessBrowser模式是浏览器的无界面状态,即在不打开浏览器界面的情况下使用浏览器。该模式的好处如下:1)可以加快web自动化测试的执行时间,对于web自动化......
  • mitudesk的python日记1
    1.python是一种解释性语言,是一行一行阅读的,在使用编译模式而非控制台模式时,会生成中间文件pyc2.Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变......
  • 将python打包成exe
    1.PyInstallerpass2.AutoPYtoEXE2.1简单说明简介:使用简单的图形界面将.py转换为.exe。时间:jul9,2018~Aug9,2022python版本:3.6 ~3.102.2安装(1)通过Pypi安......
  • python基础-GIL
    python速度慢的原因动态类型语言,边解释边执行GIL,无法利用多核CPU并发执行GIL同步线程的一种机制,使得任何时刻仅有一个线程在执行。在多核心处理器上,使用GIL的解释器......