最近,项目涉及到 Python 和 C++ 混合编程,需要 Python 调用 C++ 函数,经过不断的踩坑发现,SWIG(http://www.swig.org) 是目前来说比较友好和容易实现的。
环境:Ubuntu 16.04,OpenCV 3.4.0(include contrib)
OpenCV 编译安装请参考我另一篇教程:Ubuntu 16.04 编译安装 opencv-3.4.4 & opencv_contrib-3.4.4
首先,我们有一段检测图片角点的源码,文件名 example.cpp
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{
Mat srcImage = imread("1.jpg", 0);
imshow("原始图", srcImage);
Mat cornerStrength;
cornerHarris(srcImage, cornerStrength, 2, 3, 0.01);
Mat harrisCorner;
threshold(cornerStrength, harrisCorner, 0.00001, 255, THRESH_BINARY);
imshow("角点二值图", harrisCorner);
waitKey(0);
return 0;
}
要编译这段源码,opencv 环境是必不可少的,我们先直接编译运行一下
$ g++ -o example example.cpp `pkg-config opencv --cflags --libs`
$ ./example
红圈内的三个文件说明:
1.jpg:待检测的图片;
example:编译生成的可执行文件;
example.cpp:源码
那么问题来了,我们现在要用 Python 调用这段代码,怎么做?
我们采取的方法是,利用 SWIG 将 example.cpp 编译成 so 动态库文件,供python 直接调用,具体做法如下:
源码我们要稍微修改一下,将函数名 main 改为 show,其他的也行,反正不能是 main 函数:
example.cpp
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int show()
{
Mat srcImage = imread("1.jpg", 0);
imshow("原始图", srcImage);
Mat cornerStrength;
cornerHarris(srcImage, cornerStrength, 2, 3, 0.01);
Mat harrisCorner;
threshold(cornerStrength, harrisCorner, 0.00001, 255, THRESH_BINARY);
imshow("角点二值图", harrisCorner);
waitKey(0);
return 0;
}
example.h
int show();
example.i (SWIG 接口文件)
%module example
%{
#define SWIG_FILE_WITH_INIT
#include "example.h"
%}
%include "example.h"
我写了一个简单的 Makefile 文件,可以直接编译成 so 动态库文件
all: swig _example.so
_example.so: example_wrap.cxx example.cpp
g++ -shared -fPIC -o _example.so example_wrap.cxx example.cpp -I/home/lidaping/anaconda3/include/python3.6m `pkg-config opencv --cflags --libs`
swig:
swig -c++ -python example.i
clean:
rm -rf _example.so example_wrap.cxx example.py __pycache__
对 Makefile 简单说明一下
# 用 swig 将源码封装成 example_wrap.cxx、example.py 供下一步操作
$ swig -c++ -python example.i
# g++ 编译,`pkg-config opencv --cflags --libs` 实现调用 opencv 的头文件目录和库文件目录,-I/home/lidaping/anaconda3/include/python3.6m 实现调用 python 的头文件目录
$ g++ -shared -fPIC -o _example.so example_wrap.cxx example.cpp -I/home/lidaping/anaconda3/include/python3.6m `pkg-config opencv --cflags --libs`
编译:
$ make
进入 Python 调用 _example.so 动态库文件
$ python
>>> import example
>>> example.show()
是不是很简单?值得注意的是,我们编译含有 opencv 头文件的 C++ 源码的时候,需要给编译器指定 opencv 头文件和库文件的目录,`pkg-config opencv –cflags –libs` 这段代码就可以指定了。