昨日接到一个需求,说是用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

tar -xvf 3.4.8.tar.gz

cd opencv-3.4.8

mkdir build

cd build

cmake ..

make

make install

全程无报错,再进行依赖链接处理,OpenCV环境搭建完毕

静态库编译

代码试运行与编译

首先编写camke文件

vim CMakeLists.txt

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})

后:wq保存退出,先通过mkdir build创建build文件夹,再cd build然后通过cmake ..去创建cmake文件
之后输入make,结果报错为
make

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

原因为dllexport是windows平台下专用的语法,而在linux下编译时会自动导出so,因此这里只需要删除该部分即可
再次make,结果输出为
make

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

这里是由于代码的对相关的cv类定义不清楚,导致即使在windows下的msvc中可编译成功,在gcc下仍旧编译失败
只需要将MORPH_RECT前面的“cv::MorphShapes::”删除即可,再对代码中的其他类似参数也做同样处理。
后进行第三次make

cmake输出日志
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)

# 将图像数据的指针传递给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)

再做一些适配处理,输入Python3 main.py,图像正常生成,任务完成。

小结

虽说在修复问题上所花费时间不多,但是使用faulthandle以及gdb等调试工具准确定位错误段却花费了不少时间
起初本以为这会是一起比较好做的单子,但随即便被客户代码的抽象程度给震惊到了,甚至令人怀疑是否这段代码真的在windows上跑通过
不过也算积攒了一点python与cpp的交互经验,希望以后在处理ctype相关问题的时候,今日的经验能够多多少少发挥一点作用