参考
参考1:python调用dll数据映射
参考2:Mat,uchar*,uchar[]之间的相互转换
参考3:Mat数据在Python和C++中传递
背景
python可以使用 ctypes 模块调用 c 函数、c 的变量类型(包括结构体类型、指针类型),但是ctype只支持C标准,所以一些C++的标准是不能用的,比如函数重载、Mat类型。Mat并不是c的语法,所以一般转换为uchar进行传递。
转换表:
python获取类型指针API
Mat,uchar*,uchar[]之间的相互转换
Mat加载、结构体返回实现过程
首先在DLL文件中声明结构体并实现uchar*到Mat之间的转换,然后在python中定义一个类接收结构体,加载dll文件并定义函数输入输出参数,调用函数获取返回的结构体参数。详细请见代码
DLL(C++)
// Dll2.cpp: 定义 DLL 应用程序的导出函数。
#define EXPORT __declspec(dllexport)
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
typedef struct NLDJ_TC_Out
{
int test0;
float test1;
int test2[4];
}NLDJ_TC_Out;
class TestDLL {
public:
void get_mat(uchar* matrix, int rows, int cols, int channels);
uchar* send_mat();
};
void TestDLL::get_mat(uchar* matrix, int rows, int cols, int channels) {
cout<<rows<<cols<<channels;
Mat dst = Mat(Size(cols, rows), CV_8UC3, Scalar(255, 255, 255));
dst.data = matrix;
imshow("dst", dst);
cv::waitKey(0);
}
# mat数据发送
uchar* TestDLL::send_mat(){
Mat input_mat = imread("D:\\image\\bopian\\0.bmp");
resize(input_mat, input_mat, Size(input_mat.cols / 4, input_mat.rows / 4), INTER_LINEAR);
int height = input_mat.cols;//512
int width = input_mat.rows;//612
uchar* buffer = (uchar*)malloc(sizeof(uchar) * height * width*3);
memcpy(buffer, input_mat.data, height * width * 3);
return buffer;
}
extern "C" {
TestDLL td;
EXPORT NLDJ_TC_Out test_in(uchar* matrix, int rows, int cols, int channels) {
td.get_mat(matrix,rows,cols,channels);
// 返回结构体
NLDJ_TC_Out result;
result.test0 = 1;
result.test1 = 2.2;
for (int i = 0; i < 4; i++) {
result.test2[i] = i;
}
return result;
}
EXPORT uchar* send_mat() {
return td.send_mat();
}
}
python调用代码
from ctypes import *
import cv2 # opencv读取的格式是BGR
# python中将结构体定义为类
class Struct_NLDJ_TC_Out(Structure):
_fields_ = [("test0", c_int), ("test1", c_float), ("test2", c_int * 4)]
# dll加载,接口参数定义
lib = cdll.LoadLibrary("E:\\Dll1.dll")
lib.test_in.argtypes = (POINTER(c_ubyte), c_int, c_int, c_int)
lib.test_in.restype = Struct_NLDJ_TC_Out
lib.send_mat.restype = POINTER(c_ubyte)
# mat数据传入及结构体获取
img = cv2.imread('D:\\image\\bopian\\0.bmp')
img = cv2.resize(img, (0, 0), fx = 1 / 2, fy = 1 / 2)
cols = img.shape[1]
rows = img.shape[0]
channels = 3
pubyIm = img.ctypes.data_as(POINTER(c_ubyte))
# 调用DLL中函数
djTCVarOut = lib.test_in(pubyIm, rows, cols, channels)
print(djTCVarOut.test2[1])
# mat结构体获取
# 从指针指向的地址中读取数据,并转为numpy array
dll_mat = np.array(np.fromiter(pointer, dtype = np.uint8, count = 512 * 612 * 3))
dll_mat = dll_mat.reshape((512, 612, 3))
cv2.imshow('array_mat1', dll_mat)
cv2.waitKey()