想用python调C++写的opencv代码,网上的资料都是模棱两可,连github上的opencv swig接口项目也没好好写说明。
花了两天踏平若干大坑,终于调通,顺手解决了开源库的bug,写下本文方便后人。
能用python调OpenCV,那么调普通的C++ dll更不成问题了,也可以参考本文。
关于swig生成python扩展,网上的方法一般是在cmd中完成的,需写个setup.py,用python的distutils编译生成python扩展。
但其实还可以用VS完成整个过程,我懒得学setup.py的写法,最后就采用的这种。
---------------------------------------------------------
环境:win10, VS2019,python3.6
C++代码:SwigTest.h, SwigTest.cpp ,放在配置好OpenCV的创建dll的工程中(Release, x64)
目标:把C++代码编译成python扩展,实现“import SwigTest”的调用
(def是空的,没它的话可以Release,但没法Debug)
swig下载:http://www.swig.org (我下的是swigwin-4.0.2)
OpenCV-Swig下载:https://github.com/renatoGarcia/opencv-swig(这是github上一个项目,下载后解压得到opencv-swig-master文件夹。这个项目是帮你写好了C++ OpenCV的swig接口文件,但里面有个bug,被我扒源码找到了,后面会教你改)
boost下载:https://www.boost.org
1,解压把swig.exe所在路径添加到环境变量path,这就是安装swig的全部操作了
2,添加python.h和python36.lib所在路径到系统变量。该操作必须重启VS后才能在VS中生效!
3,安装boost,方法见这篇https://blog.csdn.net/bxbjk/article/details/100760154,安装时间1~2小时
1,打开工程文件夹,我的是SwigTest,将..\opencv-swig-master\lib 下的 opencv.i 和 opencv文件夹 拷进来。
开个玩笑,这里有个bug要改,改完再拷。打开..\opencv-swig-master\lib\opencv\matx.i :
请找到这个位置,然后把红框框出的两根下划线删掉,否则就会出bug!
然后就可以拷了:
2,在 Visual Studio 新建一个 xxx.i
的文件。我这里命名为example.i, 这是swig的接口文件
由于我的SwigTest.cpp用到了vector
%module SwigTest
%include
%include "std_vector.i"
%include "std_string.i"
%cv_instantiate_all_defaults
%template(StrVector) std::vector;
%{
#include "SwigTest.h"
%}
%include "SwigTest.h"
将来编译 example.i 时,会调用刚拷过来的 opencv.i,然后 opencv.i 会去调其他的 .i 文件。
%template那句表示在python中用 StrVector类代替C++的vector
需要强调的是:通常如果C++里用到vectorxxx.i
文件里会有这么一行:
但是在OpenCV-Swig项目中,vector的接口是个坑,这一行必须删掉!
否则后面编译时会出现 C2084:函数**已有主体 的报错:
这是因为Opencv-Swig 里已经帮你写了vector
这里实现且仅实现了以下C++数据类型的vecotr向量转换:uint8_t, short, ushort, int, float, double
所以如果你的C++代码里有vector
vf = floatArray()
vf = (1.1, 3.14, 2.8)
至于vector
3,VS中右击SwigTest项目,做如下配置:
4,右击example.i -> 属性,项类型选择“自定义生成工具”,单击“应用”
然后在 自定义生成工具 -> 常规 -> 命令行 添加 swig.exe -c++ -python "%(FullPath)",
输出 中 添加 $(InputName)_wrap.cxx
1,右击example.i -> 编译。VS会报错,各个 .i文件找不到opencv的那些hpp,
随便打开一个mat.i看一下就知道,问题出在这儿:
这时你有两个选择:
a,在红框里补充core.hpp的完整路径(斜杠方向没有影响),每个.i文件的 #include <..../*.hpp> 都要补,比如我就是:
#include
b.直接把 ...\opencv\build\include\ 下的opencv2文件夹拷到当前工程目录。这个文件夹也就5Mb大小。
傻子都知道怎么选吧?
2,然后再次右击example.i -> 编译,得到example_wrap.cxx,把它加到你的VS项目中
3,VS 生成 -> 生成解决方案,静候片刻,看到工程文件夹下得到了两个宝贝:
SwigTest.py 和 _SwigTest.pyd 就是我们要的Python扩展了,大功告成。
参考这个帖子:how can I wrap return type `std::vector
C++的cv::Mat转python用 np.asarray()
python的Mat转C++的cv:Mat用 SwigTest.from_array()