yawei 2020-05-04
C++ 是一种编译型(compiled)语言,设计重点是性能、效率和使用灵活性,偏向于系统编程、嵌入式、资源受限的软件和系统。
Python是一种解释型(interpreted)语言,同样也支持不同的编程范式。Python 内置了常用数据结构(str, tuple, list, dict),简洁的语法、丰富的内置库(os,sys,urllib,...)和三方库(numpy, tf, torch ...),功能强大。最为重要的是和能够和多种服务(flask…)和tensorflow、pytorch等无缝联合,从而方便将你的算法开放出去。
一方面,我们需要编译型语言(C++)性能;一方面,也需要解释型语言(Python)的灵活。这时,pybind11 可以用作 C++ 和 Python 之间沟通的桥梁。
Pybind11 是一个轻量级只包含头文件的库,用于 Python 和 C++ 之间接口转换,可以为现有的 C++ 代码创建 Python 接口绑定。Pybind11 通过 C++ 编译时的自省来推断类型信息,来最大程度地减少传统拓展 Python 模块时繁杂的样板代码, 已经实现了 STL 数据结构、智能指针、类、函数重载、实例方法等到Python的转换,其中函数可以接收和返回自定义数据类型的值、指针或引用。
由于在Windows上和在Linux上使用会有较大不同,所以我这里将分为两个部分来说明问题,本文为下篇,具体说明Linux+Cmake实现。
我认为在Linux上使用python调用c++函数更有现实价值,毕竟许多新的服务、深度运算等都是运行在linux上的。具体步骤可以参考如下。
下载pybind11<span>git clone https://github.com/pybind/pybind11.git</span>
安装pytest<span>pip install pytest</span>
编译安装。这个地方我建议你首先将下载下来的pybind11备份一份
<code>
<code><span>cd pybind11</span>
<code>
<code>
<span>mkdir build</span><br /><span>cd build</span><br /><span>cmake ..</span><br /><span>cmake </span><span>--</span><span>build . </span><span>--</span><span>config Release </span><span>--</span><span>target check</span>
<code>
<span> </span>
<span>$ c</span><span>++</span> <span>-</span><span>O3 </span><span>-</span><span>Wall </span><span>-</span><span>shared </span><span>-</span><span>std</span><span>=</span><span>c</span><span>++</span><span>11</span> <span>-</span><span>fPIC </span><span>`</span><span>python3 </span><span>-</span><span>m pybind11 </span><span>--</span><span>includes</span><span>`</span><span> example.cpp </span><span>-</span><span>o example</span><span>`</span><span>python3</span><span>-</span><span>config </span><span>--</span><span>extension</span><span>-</span><span>suffix</span><span>`</span>
cmake_minimum_required(VERSION 2.8.12)<br />project(example) <br /><br />add_subdirectory(pybind11)<br />pybind11_add_module(example example.cpp)
cmake .<br />make
import example<br />example.add(3, 4)<br />[out]: 7
<span>project(example) </span>
<span>cmake_minimum_required(VERSION 2.8.12)</span>
<span>find_package(OpenCV REQUIRED) </span>
<span>include_directories(${OpenCV_INCLUDE_DIRS})</span>
<span>add_subdirectory(pybind11)</span>
<span><br /></span>
<span>pybind11_add_module(example example.cpp)</span>
<span>target_link_libraries(example PRIVATE ${OpenCV_LIBS})</span>
<code>
<code>project(example)<br />cmake_minimum_required(VERSION 2.8.12)<br /> <br />find_package(OpenCV REQUIRED)<br />include_directories(${OpenCV_INCLUDE_DIRS})<br />add_subdirectory(pybind11)<br /> <br />SET(SOURCES<br /> ${CMAKE_CURRENT_SOURCE_DIR}/example.cpp<br />)<br /> <br />pybind11_add_module(example ${SOURCES})<br /><span>target_link_libraries(example </span>PRIVATE <span>${OpenCV_LIBS})</span>
<code>
<span>简单分析一下这段Cmake,除了必须的项目名称等以外,就是简单地去寻找OpenCV等的地址,而后将lib输入进去。</span><span>pybind11_add_module相当于建立项目,使用Set方法方便批量处理。</span>
<span>其中注意两点:</span>
<span>1、</span><span>target_link_libraries(example PRIVATE ${OpenCV_LIBS}) 放最后</span>
<span>2、</span><span>xample PRIVATE</span><span> 不可缺少,否则报这个错</span>
<span>成功调用结果,</span><span>注意绝对地址。</span>
project(example) <br />cmake_minimum_required(VERSION 2.8.12)<br /><br />find_package(OpenCV REQUIRED) <br />include_directories(${OpenCV_INCLUDE_DIRS})<br />add_subdirectory(pybind11)<br /><br />SET(SOURCES<br /> ${CMAKE_CURRENT_SOURCE_DIR}/example.cpp<br /> ${CMAKE_CURRENT_SOURCE_DIR}/mat_warper.h<br /> ${CMAKE_CURRENT_SOURCE_DIR}/mat_warper.cpp<br />)<br /> <br />pybind11_add_module(example ${SOURCES})<br />target_link_libraries(example PRIVATE ${OpenCV_LIBS})<br />
tar -xvf GOPyWarper0429.tar
mkdir build
cd build
cmake .. <br />make<br />cp GOPyWarper.cpython-36m-x86_64-linux-gnu.so ../demo
cd ../demo
python3 main.py
import cv2<br />import GOPyWarper<br />import numpy as np<br /><br />#获取图片,彩色3通道。<br />#中文和空格不支持<br />src = cv2.imread(‘pip.jpg‘,1) <br /><br />#GO_FindPips<br />#输入mat,输出为list(point1,point2,……),其中point代表一个找到的圆心。.<br />varCircles = GOPyWarper.GO_FindPips(src)<br />#print(varCircles)<br /><br />#GO_Resize<br />#输入mat,输出为规则化后文件大小<br />varResize = GOPyWarper.GO_Resize(src)<br /><br />#绘图<br />dst=cv2.resize(src,((int)(varResize[0]),(int)(varResize[1])),interpolation=cv2.INTER_CUBIC)<br />for i in varCircles[:]:<br /> cv2.circle(dst,(i[0],i[1]),5,(0,255,0),-1)<br /> <br />cv2.imshow("dst",dst)<br />cv2.waitKey(0)
-virtual-machine:~/sandbox$ tar -cvf GOPyWarper0430.tar GOPyWarper0430<br />......<br />-virtual-machine:~/sandbox$ cd GOPyWarper0430<br />-virtual-machine:~/sandbox/GOPyWarper0430$ mkdir build<br />-virtual-machine:~/sandbox/GOPyWarper0430$ cd build<br />-virtual-machine:~/sandbox/GOPyWarper0430/build$ cmake ..<br />......<br />-virtual-machine:~/sandbox/GOPyWarper0430/build$ make <br />Scanning dependencies of target GOPyWarper<br />[ 20%] Building CXX object CMakeFiles/GOPyWarper.dir/src/GOPyWarper.cpp.o<br />[ 40%] Building CXX object CMakeFiles/GOPyWarper.dir/src/mat_warper.cpp.o<br />[ 60%] Building CXX object CMakeFiles/GOPyWarper.dir/src/GOCVHelper_2019_11_29.cpp.o<br />[ 80%] Building CXX object CMakeFiles/GOPyWarper.dir/src/GOFindPips.cpp.o<br />[100%] Linking CXX shared module GOPyWarper.cpython-36m-x86_64-linux-gnu.so<br />[100%] Built target GOPyWarper<br />-virtual-machine:~/sandbox/GOPyWarper0430/build$ cp GOPyWarper.cpython-36m-x86_64-linux-gnu.so ../demo/<br />-virtual-machine:~/sandbox/GOPyWarper0430/build$ cd ../demo/<br />-virtual-machine:~/sandbox/GOPyWarper0430/demo$ python3 main.py <br />
-virtual-machine:~/workstation/GOPyWarper0430$ cd build/<br />-virtual-machine:~/workstation/GOPyWarper0430/build$ cmake ..<br />-- Found OpenCV: /usr/local (found version "4.3.0") <br />-- Found PythonInterp: /usr/bin/python3.8 (found version "3.8.2") <br />-- Found PythonLibs: /usr/lib/x86_64-linux-gnu/libpython3.8.so<br />-- pybind11 v2.5.dev1<br />-- Performing Test HAS_FLTO<br />-- Performing Test HAS_FLTO - Success<br />-- LTO enabled<br />-- Configuring done<br />-- Generating done<br />-- Build files have been written to: /home/helu/workstation/GOPyWarper0430/build<br />-virtual-machine:~/workstation/GOPyWarper0430/build$ make<br />Scanning dependencies of target GOPyWarper<br />[ 20%] Building CXX object CMakeFiles/GOPyWarper.dir/src/GOPyWarper.cpp.o<br />[ 40%] Building CXX object CMakeFiles/GOPyWarper.dir/src/mat_warper.cpp.o<br />[ 60%] Building CXX object CMakeFiles/GOPyWarper.dir/src/GOCVHelper_2019_11_29.cpp.o<br />[ 80%] Building CXX object CMakeFiles/GOPyWarper.dir/src/GOFindPips.cpp.o<br />[100%] Linking CXX shared module GOPyWarper.cpython-38-x86_64-linux-gnu.so<br />[100%] Built target GOPyWarper<br />-virtual-machine:~/workstation/GOPyWarper0430/build$
GaussBlur | windows实体机 c++原生 | ubuntu虚拟机 opencv_python | ubuntu虚拟机 pbind11 |
1次 | 32 | 34 | 40 |
重复100次 | 2819 | 3740 | 3891 |
int main() {<br /> string path = "e:/template/lena.jpg";<br /> cv::Mat src = cv::imread(path);<br /> Mat dst;<br /> <br /> //开始计时<br /> double dstart = (double)cv::getTickCount();<br /> for (int i=0;i<=100;i++)<br /> {<br /> cv::GaussianBlur(src, dst, cv::Size(101, 101), 1.0, 1.0);<br /> printf("%d times %f ms\n", i,1000 * (getTickCount() - dstart) / getTickFrequency());<br /> <br /> }<br /> cv::waitKey(0);<br /> return 0;<br />}
import cv2<br />import GOPyWarper<br />import numpy as np<br /><br /><br />src = cv2.imread(‘/home/helu/images/lena.jpg‘,1) <br />dstart = cv2.getTickCount()<br /><br />for i in range(100):<br /> blur = cv2.GaussianBlur(src,(101,101),1.0,None,1.0,borderType=4)<br /> print(1000 * ( cv2.getTickCount() - dstart) /cv2.getTickFrequency())
import cv2<br />import GOPyWarper<br />import numpy as np<br /><br />#获取图片,彩色3通道。<br />#中文和空格不支持<br />src = cv2.imread(‘/home/helu/images/lena.jpg‘,1) <br />dstart = cv2.getTickCount()<br /><br />for i in range(100):<br /> blur = GOPyWarper.test_gaussblur(src)<br /> print(1000 * ( cv2.getTickCount() - dstart) /cv2.getTickFrequency())