昨日接到一个需求,说是用python调用cpp的opencv库去做图像识别,目前已经在windows上跑通了,并且成功导出了dll
但是接下来还需要在linux上跑通,同时编译出可供目标平台使用的so动态库
目标平台:CentOS8 x86
依赖库版本:Python3.8 OpenCV3.4.8
OpenCV环境安装
wget https://github.com/opencv/opencv/archive/refs/tags/3.4.8.tar.gz全程无报错,再进行依赖链接处理,OpenCV环境搭建完毕tar -xvf 3.4.8.tar.gz
cd opencv-3.4.8
mkdir build
cd build
cmake ..
make
make install
静态库编译
代码试运行与编译
首先编写camke文件
vim CMakeLists.txt后:wq保存退出,先通过mkdir build创建build文件夹,再cd build然后通过cmake ..去创建cmake文件cmake_minimum_required(VERSION 2.8)
project(deshadow)
set( CMAKE_BUILD_TYPE “Debug” )
# Find OpenCV library
find_package(OpenCV REQUIRED)
# Add shared library target
add_library(deshadow SHARED imgae_deshadow.cpp)
include_directories(${OpenCV_INCLUDE_DIRS})
# Link with OpenCV library
target_link_libraries(deshadow ${OpenCV_LIBS})
#message(${OpenCV_LIBS})
之后输入make,结果报错为
make原因为dllexport是windows平台下专用的语法,而在linux下编译时会自动导出so,因此这里只需要删除该部分即可Scanning dependencies of target deshadow
[100%] Building CXX object CMakeFiles/deshadow.dir/imgae_deshadow.cpp.o
/lingkong/python/imgae_deshadow.cpp:21:11: error: expected constructor, destructor, or type conversion before ‘(’ token
__declspec(dllexport)
^
make[2]: *** [CMakeFiles/deshadow.dir/imgae_deshadow.cpp.o] Error 1
make[1]: *** [CMakeFiles/deshadow.dir/all] Error 2
make: *** [all] Error 2
再次make,结果输出为
make这里是由于代码的对相关的cv类定义不清楚,导致即使在windows下的msvc中可编译成功,在gcc下仍旧编译失败Scanning dependencies of target deshadow
[100%] Building CXX object CMakeFiles/deshadow.dir/imgae_deshadow.cpp.o
/lingkong/python/imgae_deshadow.cpp: In function ‘int Image_deshadow(std::string&, int, char*)’:
/lingkong/python/imgae_deshadow.cpp:174:42: error: ‘cv::MorphShapes’ is not a class or namespace
Mat element = getStructuringElement(cv::MorphShapes::MORPH_RECT, cv::Size(n, n));
^
make[2]: *** [CMakeFiles/deshadow.dir/imgae_deshadow.cpp.o] Error 1
make[1]: *** [CMakeFiles/deshadow.dir/all] Error 2
make: *** [all] Error 2
只需要将MORPH_RECT前面的“cv::MorphShapes::”删除即可,再对代码中的其他类似参数也做同样处理。
后进行第三次make
so库正常输出,编译成功
Python异常捕捉
接着进入python代码修改依赖库位置,同时pip下载对应依赖库
试运行报错 显示Segmentation fault,即在linux下python通过ctype调用c的常见段错误,
这里利用faulthandle库进行错误捕捉,定位到错误代码为
pbyteraw = np.zeros(size, dtype=np.uint8)可知是传参类型的问题,对代码进行修改:image = np.ascontiguous(image, dtype=image.dtype)
image_ctypes_ptr = cast(image.ctypes.data, POINTER(c_uint8))
lib.Image_deshadow(image_ctypes_ptr, ctypes.c_int(w), ctypes.c_int(h), ctypes.c_int(channels), ctypes.c_int(n),pbyteraw.ctypes.data_as(ctypes.POINTER(ctypes.c_uint8)))
再结合cpp处的对应函数:
int Image_deshadow(std::string &base64_src, int n, char* pout)
pbyteraw = np.zeros(size, dtype=np.uint8)再做一些适配处理,输入Python3 main.py,图像正常生成,任务完成。# 将图像数据的指针传递给C++函数
lib.Image_deshadow(image.ctypes.data_as(ctypes.POINTER(ctypes.c_uint8)), ctypes.c_int(w), ctypes.c_int(h), ctypes.c_int(channels), ctypes.c_int(n), pbyteraw.ctypes.data_as(ctypes.POINTER(ctypes.c_uint8)))
cpp:
int Image_deshadow(unsigned char* pimg, int w, int h, int channels, int n, unsigned char* pout)
小结
虽说在修复问题上所花费时间不多,但是使用faulthandle以及gdb等调试工具准确定位错误段却花费了不少时间
起初本以为这会是一起比较好做的单子,但随即便被客户代码的抽象程度给震惊到了,甚至令人怀疑是否这段代码真的在windows上跑通过
不过也算积攒了一点python与cpp的交互经验,希望以后在处理ctype相关问题的时候,今日的经验能够多多少少发挥一点作用