SWIG教程:Python调用C++写的OpenCV简单程序

最近,项目涉及到 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` 这段代码就可以指定了。

发表评论

您的电子邮箱地址不会被公开。