前言
由于这个尝试花了一些时间,所以记录下来。由于我是尝试的很多理论地方不大懂,我把我尝试成功的部门记录下来,希望对大家有所帮助。
我的环境是windows10 + vs2015
创建 vs dll project
python所有不同的调用方式都需要先建一个dll project。
-
新建一个c++工程,选择DLL、导出符号和空项目(如下图);
IMG20180612_131008.png - c++ 默认的解决平台是32位的,如果python是64位的,需要把c++ 解决平台修改为64位;
python 调用 c++普通函数
为了写文档,尝试了以下链接中的简单例子,可行。
https://blog.csdn.net/sloanqin/article/details/51505478
python 调用 struct
最开始尝试struct是以下链接中的例子,可行。
https://blog.csdn.net/iceboy314159/article/details/53192175
python 调用 class
pro.h 文件
#include <opencv2/opencv.hpp>
#ifndef _pro_header_2014_
#define _pro_header_2014_
#ifdef EXPORT_PRO_DLL
#define PRO_API __declspec(dllexport)
#else
#define PRO_API __declspec(dllimport)
#endif
class Foo
{
public:
Foo(cv::Mat);
void bar();
int* foobar(cv::Mat);
private:
cv::Mat val;
};
extern "C"
{
PRO_API Foo* Foo_new(int rows, int cols, unsigned char* imgdata);
PRO_API void Foo_bar(Foo* foo);
PRO_API int* Foo_foobar(Foo* foo, int rows, int cols, unsigned char* imgdata);
}
#endif // !_pro_header_2014_
pro.cpp 文件
#define EXPORT_PRO_DLL
#include "pro.h"
#include "string.h"
#include<iostream>
using namespace std;
Foo::Foo(cv::Mat n)
{
val = n;
}
void Foo::bar()
{
std::cout << "Value is " << val << std::endl;
}
int* Foo::foobar(cv::Mat n)
{
int *data = new int[2];
data[0] = 1;
data[1] = 2;
return data;
}
PRO_API Foo* Foo_new(int rows,int cols, unsigned char* imgdata) {
cv::Mat img(rows, cols, CV_8UC3, (void *)imgdata);
return new Foo(img);
}
PRO_API void Foo_bar(Foo* foo) { foo->bar(); }
PRO_API int* Foo_foobar(Foo* foo, int rows, int cols, unsigned char* imgdata) {
cv::Mat img(rows, cols, CV_8UC3, (void *)imgdata);
return foo->foobar(img);
}
python code, 其中的图像读入,需要根据你自己的修改
from ctypes import *
class Foo(object):
def __init__(self, img):
lib.Foo_new.argtypes = [c_int,c_int,POINTER(c_ubyte)]
lib.Foo_new.restype = c_void_p
lib.Foo_bar.argtypes = [c_void_p]
lib.Foo_bar.restype = c_void_p
lib.Foo_foobar.argtypes = [c_void_p,c_int,c_int,POINTER(c_ubyte)]
lib.Foo_foobar.restype = POINTER(c_int)
(rows, cols) = (img.shape[0], img.shape[1])
self.obj = lib.Foo_new(rows, cols,img.ctypes.data_as(POINTER(c_ubyte)))
def bar(self):
lib.Foo_bar(self.obj)
def foobar(self, img):
(rows, cols) = (img.shape[0], img.shape[1])
return lib.Foo_foobar(self.obj, rows, cols,img.ctypes.data_as(POINTER(c_ubyte)))
if __name__ == '__main__':
root_path = 'E:/tracking/data/Girl'
imglist = scan_image(os.path.join(root_path, 'img'))
for imgname in imglist:
img = cv2.imread(os.path.join(root_path, 'img', imgname))
f = Foo(img)
f.bar()
rect = f.foobar(img)
print(rect[0],rect[1])
后记
- 以上代码包含了Mat的处理和数组的处理,其中rect应该是返回cv::Rect类型,由于不会处理,所以转换成了int 数组类型,如果你有更优雅的方法,请赐教。
- argtypes ,restype 分别是参数类型和返回值类型的定义,在类中是必不可少的,而且必须对应。比如c_float写成 c_int,结果就会不一样或者报错。
参考文章
class 调用:
http://www.auctoris.co.uk/2017/04/29/calling-c-classes-from-python-with-ctypes/
Mat 处理方式:
https://stackoverflow.com/questions/19031836/get-background-model-from-backgroundsubtractormog2-in-python
网友评论