例程:Python通过ctypes调用DLL
此例程主要是用来备忘备查,记录一些常用的ctypes调用方式,包括:基本数据类型、指针、引用、数组、结构、类的书写方式。
ctypes官方资料
https://docs.python.org/3/library/ctypes.html
参考代码
C++代码
// PythonDll.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include <stdio.h>
#include <opencv2/opencv.hpp>
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS_GLOBALS
#pragma warning (disable: 4996)
using namespace std;
using namespace cv;
#define DLLEXPORT extern "C" __declspec(dllexport)
DLLEXPORT int add(int a, int b);
int add(int a, int b)
{
return a + b - 1;
}
DLLEXPORT char * sadd(char * a, char * b);
char * sadd(char * a, char * b)
{
char c[1024];
memset(c, 0, 1024);
strcpy(c, a);
char *p = (char *)(c + strlen(a));
strcpy(p, b);
return (char *)c;
}
DLLEXPORT void * imageResize(void * image, int h0, int w0, int channels, void * &dst, int h1, int w1, int inter = INTER_AREA)
{
Size sz0(w0, h0);
Size sz1(w1, h1);
int type = CV_8UC1;
if (channels == 3)
type = CV_8UC3;
Mat img(sz0, type, image);
/*
uchar* pxvec = img.ptr<uchar>(0);
int count = 0;
for (int row = 0; row < h0; row++)
{
pxvec = img.ptr<uchar>(row);
for (int col = 0; col < w0 * channels; col++)
{
pxvec[col] = ((uchar *)image)[count++];
}
}
*/
imwrite("n1.jpg", img);
Mat oa;
resize(img, oa, sz1, inter);
imwrite("n2.jpg", img);
dst = (void *)malloc(sizeof(uint8_t)*h1*w1*channels);
memcpy(dst, oa.data, sizeof(uint8_t)*h1*w1*channels);
return dst;
}
DLLEXPORT void imageReizeRelease(void * data) {
free(data);
}
typedef struct tagPerson {
char name[20];
char *nickname;
char sex;
float height;
int age;
} Person;
class BaseBox {
public:
uint32_t boxsize = 0;
uint32_t boxtype = 0;
};
DLLEXPORT int setPersonBox(Person p0, BaseBox bb0, Person &p1, BaseBox &bb1) {
strcpy(p1.name, "bob baby");
bb1.boxsize = 5;
return 10;
}
Python代码
from ctypes import *
import numpy as np
import cv2
import os
dllpath = os.getcwd() + "/PythonDll.dll"
fd = cdll.LoadLibrary(dllpath)
x = fd.add(3, 2)
sadd = fd.sadd
sadd.argtypes = [c_char_p, c_char_p]
sadd.restype = c_char_p
# arg0 = bytes("Sam", "gbk")
# arg1 = bytes(" Sha", "gbk")
y = sadd("Sam Sha".encode("utf-8"), " ,Hello!".encode("utf-8"))
print(y.decode())
imageResize = fd.imageResize
imageReizeRelease = fd.imageReizeRelease
img1 = cv2.imread("dlrb.jpg")
h0, w0, channels = img1.shape[0:3]
print("height: {} , width: {}, channels: {}".format(h0, w0, channels))
h1 = (int)(h0 * 0.3)
w1 = (int)(w0 * 0.3)
arg1 = np.array(img1, dtype=np.uint8)
arg1 = arg1.ctypes.data_as(c_void_p)
# arg1 = img1.ctypes.data_as(c_void_p)
arg2 = pointer(c_uint8(0))
imageResize.restype = POINTER(c_uint8)
pointer = imageResize(arg1, h0, w0, channels, byref(arg2), h1, w1)
# array = np.array(np.fromiter(pointer, dtype=np.uint8, count=h1 * w1 * channels))
array = np.array(np.fromiter(arg2, dtype=np.uint8, count=h1 * w1 * channels))
img2 = array.reshape((h1, w1, channels))
cv2.imwrite("n.jpg", img2)
cv2.imshow("img2", img2)
imageReizeRelease(pointer)
CharArrayType = c_char * 20
class Person(Structure):
_fields_ = [("name", CharArrayType),("nickname",c_char_p),("sex", c_char),("height", c_float),("age", c_int)]
class BaseBox(Structure):
_fields_ = [("boxsize", c_int),("boxtype", c_int)]
setPersonBox = fd.setPersonBox
p0 = Person("sam".encode("utf-8"),"sam sha".encode("utf-8"),b'm',178.0,48)
bb0 = BaseBox(3,4)
p1 = Person("bob".encode("utf-8"),"bob sha".encode("utf-8"),b'm',188.0,22)
bb1 = BaseBox(7,8)
v = setPersonBox(p0,bb0,byref(p1),byref(bb1))
cv2.waitKey()
cv2.destroyAllWindows()
经验分享
VC调试DLL的设置
打开VC项目的Properties,配置Debugging的Command指向python.exe,Command Arguments指向demo.py,如果必要设置Working Directory。