Python调用C++编写的OpenCV函数

Python调用C++编写的函数,利用OpenCV的方法

  • 原理
  • 配置方法
    • 环境注意事项
    • 配置步骤
  • 使用


有时常常遇到两种语言切换的问题,比如在C++中实现了一个图像处理算法,将其封装为一个函数,该函数的输入输出类型为OpenCV中常用的类型如cv::Mat等,需要在Python中调用,这时可以愉快地利用OpenCV生成Python包的方法。

原理

利用OpenCV生成Python包的原理,将我们写的C++程序编译成Python包(本文介绍的是在Windows环境下,使用VS,Python 64位,其他环境按需修改即可,主要是几个文件)
原理参考 How OpenCV-Python Bindings Works?

参考learnopencv,本文介绍了cv2.cpp的修改方法,与参考有些区别,改动少一些

配置方法

环境注意事项

  1. Python位数,和使用的VS编译器位数要相同,本文测试的都是64位
  2. 本文介绍的OpenCV版本是4.0.1,其他版本按需修改(主要是几个文件,支持生成Python包的OpenCV版本应该都是可以的)

配置步骤

  • cv2.cpp,pycompat.hpp,gen2.py,hdr_parser.py这几个文件从OpenCV源码中拷贝出来,大致路径在moudules/python/src

  • 目录结构(要新建的后文介绍)

--cv2.cpp
--pycompat.hpp
--gen2.py
--hdr_parser.py
--headers.txt
--src
----pycvtest.h
----pycvtest.cpp
--pycvtest
  • pycvtest.h中写这些,注意命名空间必须使用cv,减少后续工作量,注意不要直接导入opencv.hpp,因为它导入了大量的库,如果不需要不用导入,按需修改,本例中只是用了core.hpp用来展示
#pragma once
//#include 
#include 

namespace cv {
     
    CV_EXPORTS_W void add_one_for_test(cv::InputArray t_in, cv::OutputArray t_out);
}
  • pycvtest.cpp中写这些
#include "pycvtest.h"

namespace cv {
     
    void add_one_for_test(cv::InputArray t_in, cv::OutputArray t_out)
    {
     
        cv::add(t_in, 1, t_out);
    }
  • 修改hdr_parser.py中的列表opencv_hdr_list,把我们要加的头文件写进去,其他都不要
opencv_hdr_list = [
	"src/pycvtest.h"
]
  • 注释gen2.py
if hdr.find('opencv2/') >= 0: #Avoid including the shadow files
   self.code_include.write( '#include "{0}"\n'.format(hdr[hdr.rindex('opencv2/'):]) )

改成

self.code_include.write( '#include "{0}"\n'.format(hdr[hdr.rindex('src/'):]) )

这个会影响好后生成的pyopencv_generated_include.h文件导入头文件的代码,生成后可查看,按需修改~

  • 新建headers.txt写头文件路径
src/pycvtest.h
  • 新建pycvtest文件夹,用于生成头文件~
  • 运行python gen2.py pycvtest headers.txt,这时看pycvtest文件夹,应该已经生成好了pyopencv开头的文件了
  • 在VS中新建DLL工程,注意事项(默认已经配置好了OpenCV
    – 添加cv2.cpp,pycompat.h,pycvtest.h,pycvtest.cpp
    – 添加include路径,就是刚刚生成以pyopencv_文件名开头的文件目录pycvtest
    – 属性中C/C++ 预处理器添加宏定义CVAPI_EXPORTS,必须写出来,不然不会导出
    – 添加Python库lib目录,大致是Python安装路径\Python35\libs
    – 添加Python包含include目录,大致是Python安装路径\Python35\include
    – 添加Numpy包含目录,大致是什么什么\Lib\site-packages\numpy\core\include
    – 属性常规选项卡,目标文件扩展名.pyd
    – 属性常规选项卡,目标文件名pycvtest

下面愉快地改cv2.cpp文件

  • 前面有个模板类PyOpenCV_Converter,里面的两个函数to from没有写,但是后面调用了,VS会编译不通过,我改的方法是注释取消,然后把函数定义写出来,函数内容什么都不用写就是下面这样,后面针对具体类型的模板函数会重载下面的pyopencv_topyopencv_from,所以不用担心,有更好改法的朋友请告知,谢谢~
template<typename T, class TEnable = void>  // TEnable is used for SFINAE checks
struct PyOpenCV_Converter
{
     
    static inline bool to(PyObject* obj, T& p, const char* name) {
     
        return true;
    }
    static inline PyObject* from(const T& src) {
     
        return nullptr;
    }
};
  • 注释掉
    // #include "opencv2/opencv_modules.hpp"
    因为它导入了太多包,按需修改~
  • 取消没有用到的宏定义,按需修改!
#undef HAVE_OPENCV_HIGHGUI
#undef HAVE_OPENCV_DNN
  • 注释掉没有使用的文件,按需修改~
//#include "pyopencv_custom_headers.h"
  • 最后重要步骤!把PyInit_cv2() 这个初始化包的函数名称改成自己的PyInit_pycvtest(),文件中的全都改一下,就改两个地方就行了,就函数声明那个位置

  • 然后编译吧~,因该主要地方都改了,有小错误按需修改。编译好之后就会编出个pycvtest.pyd

使用

拷贝需要的动态链接库到pyd文件夹,或者添加动态链接库的目录到Python运行目录,然后导入包,还有一种方法是先导入cv2然后再导入pycvtest,如下所示

import numpy as np
import cv2
import pycvtest as pct
a = np.array([[2, 3, 4]])
output = pct.add_one_for_test(a)
print(output)

好了~

你可能感兴趣的:(python-c++之间的调用,开发环境搭建,c++,python,opencv)