python 使用ctypes加载(C/C++)动态库

一、简单使用

ctypes — Python 的外部函数库 【中文文档】
字符串传递

ctypes 定义了一些和C兼容的基本数据类型:

ctypes 类型 C 类型 Python 类型
c_bool _Bool bool (1)
c_char char 单字符字节串对象
c_wchar wchar_t 单字符字符串
c_byte char int
c_ubyte unsigned char int
c_short short int
c_ushort unsigned short int
c_int int int
c_uint unsigned int int
c_long long int
c_ulong unsigned long int
c_longlong __int64 或 long long int
c_ulonglong unsigned __int64 或 unsigned long long int
c_size_t size_t int
c_ssize_t ssize_tPy_ssize_t int
c_float float float
c_double double float
c_longdouble long double float
c_char_p char* (以 NUL 结尾) 字节串对象或 None
c_wchar_p wchar_t* (以 NUL 结尾) 字符串或 None
c_void_p void* int 或 None
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>

#define DLLEXPORT extern "C" __declspec(dllexport)  
DLLEXPORT float __stdcall add(int a, float b) {
    
    
	printf("a=%d\n", a);
	printf("b=%f\n", b);
	return a + b;
}


DLLEXPORT char* __stdcall get_ascii_str(char* path)
{
    
    
	std::cout << "path:" << path << std::endl;
	char* ret;
	ret = (char*)malloc(24);
	strcpy(ret, "hello word123,./");
	return ret;
}


DLLEXPORT char* __stdcall get_utf8_str(char* path)
{
    
    
	std::cout << "path:" << path << std::endl;
	char* ret;
	ret = (char*)malloc(24);
	strcpy(ret, "你好hello word123,./");
	return ret;
}


//构建字符串数组,2个元素
typedef struct struct_str_arr
{
    
    
	const char* str_ptr[2];
} str_arr;

struct_str_arr* str_arr_ptr = (struct_str_arr*)malloc(sizeof(str_arr));

DLLEXPORT struct_str_arr* __stdcall get_str_list(int n, char* b[2])
{
    
    
	for (int i = 0; i < n; i++)
	{
    
    
		printf("%s", *(b + i));
		printf("\n");
	}
	str_arr_ptr->str_ptr[0] = "你好";
	str_arr_ptr->str_ptr[1] = "hell";
	return str_arr_ptr;
}

test.py

# -*- coding: utf-8 -*-
from ctypes import *

# ==================================
# dll =CDLL("./ctype_test1.dll")
# dll = cdll.LoadLibrary("./ctype_test1.dll")
# dll = windll.LoadLibrary("./ctype_test1.dll")
# ==================================

dll = PyDLL("./ctype_test1.dll")
dll.add.argtypes=[c_int,c_float]
dll.add.restype=c_float
a=c_int(10)
b=c_float(20.5)
res= dll.add(a,b)
print(res)


print("#######################################")
dll.get_ascii_str.argtypes=[c_char_p]
dll.get_ascii_str.restype=c_char_p

tex= b"dsf123,./"
text = c_char_p(tex)
rt_str=dll.get_ascii_str(text)
print(rt_str)


dll.get_utf8_str.argtypes=[c_char_p]
dll.get_utf8_str.restype=c_char_p

tex= "你好呀dsf123,./".encode()
text = c_char_p(tex)

rt_str=dll.get_utf8_str(text)
print(rt_str.decode('gbk'))


print("#######################################")
# 返回的数据
class StructPointer(Structure):  
    _fields_ = [("str_ptr", c_char_p * 2)]  


dll.get_str_list.restype = POINTER(StructPointer)
str1 = c_char_p(bytes("nihao", 'utf-8'))
str2 = c_char_p(bytes("shijie", 'utf-8'))
a = (c_char_p*2)(str1, str2)
ret_ptr =dll.get_str_list(2, a)
print(ret_ptr.contents.str_ptr[0].decode("gbk"))
print(ret_ptr.contents.str_ptr[1].decode("gbk"))

二、结构体

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <iostream>
#include <opencv2/opencv.hpp>


#ifdef _MSC_VER
#define DLL_EXPORT extern "C" __declspec(dllexport) 
#else
#define DLL_EXPORT extern "C"
#endif


DLL_EXPORT float __stdcall add(int a, float b) {
    
    
	printf("a=%d\n", a);
	printf("b=%f\n", b);
	return a + b;
}


DLL_EXPORT void add_point(float* a, float* b, float* c)
{
    
    
	*c = *a + *b;
	*a = 129.7;
}


//作为返回值返回
DLL_EXPORT uchar* mattostring(uchar* src_data, int rows, int cols, int* size)
{
    
    
	cv::Mat dst = cv::Mat(cv::Size(cols, rows), CV_8UC3, cv::Scalar(255, 255, 255));
	dst.data = src_data;
	circle(dst, cv::Point(60, 60), 10, cv::Scalar(255, 0, 0));

	std::vector<uchar> data_encode;
	cv::imencode(".png", dst, data_encode);
	std::string str_encode(data_encode.begin(), data_encode.end());
	uchar* char_r = new uchar[str_encode.size() + 10];
	*size = str_encode.size() + 10;
	memcpy(char_r, str_encode.data(), sizeof(char) * (str_encode.size()));
	return char_r;
}

//作为入参指针传递
DLL_EXPORT void draw_circle(int rows, int cols, unsigned char* src_data, unsigned char* ret_data)
{
    
    
	cv::Mat src = cv::Mat(rows, cols, CV_8UC3, src_data);           // uchar* 转cvMat
	cv::circle(src, cv::Point(60, 60), 10, cv::Scalar(255, 0, 0));  // 画图
	memcpy(ret_data, src.data, rows * cols * 3);                    // 将Mat转换成unsigned char
}

test.py

from ctypes import *
import cv2
import numpy as np
from PIL import Image

MYDLL= CDLL("./x64/Release/ctype_test2.dll", winmode=0)



x1 = c_float(1.9)
x2 = c_float(10.1)
x3 = c_float(0)
MYDLL.add_point(byref(x1),byref(x2),byref(x3))
print("x1=",x1)
print("x2=",x2)
print("x3=",x3)


image=cv2.imread("./20220818142610.png")
rows = image.shape[0]
cols = image.shape[1]
channels =3
print("[cols*rows*channels]",cols*rows*channels)


MYDLL.mattostring.argtypes = (POINTER(c_ubyte), c_int,c_int, POINTER(c_int))  # c_char_p也可以
MYDLL.mattostring.restype = c_void_p                                          # POINTER(c_ubyte) 跟c_void_p都可以
#MYDLL.mattostring.restype = POINTER(c_uint64)                                # POINTER(c_ubyte) 跟c_void_p都可以
MYDLL.draw_circle.argtypes=[c_int,c_int,POINTER(c_ubyte),POINTER(c_ubyte)]
MYDLL.draw_circle.restype=c_void_p



srcPointer=image.ctypes.data_as(POINTER(c_ubyte))    #方式1.1
# srcPointer=image.ctypes.data_as(c_char_p)          #方式1.2
# srcPointer = image.astype(np.uint8).tostring()     #方式2

size = c_int(0)
a = MYDLL.mattostring(srcPointer,rows,cols,byref(size))
#b = string_at(a,cols*rows*channels)                 # 类似于base64
print("[size]=",size.value)
b = string_at(a,size.value)                          # 类似于base64
# b = string_at(a,99132)                             # 类似于base64

nparr = np.frombuffer(b, np.uint8)
img_decode= cv2.imdecode(nparr,cv2.IMREAD_COLOR)     #转cvMat
cv2.imshow("img_decode", img_decode) 
cv2.waitKey(0)
cv2.destroyAllWindows()
img_decode=Image.fromarray(img_decode[:,:,::-1])     # 由于直接cv2.imshow()显示出来的图是错误的,保存或者转为Image格式,显示正确
img_decode.show()


ret_img = np.zeros(dtype=np.uint8, shape=(rows, cols, 3))
retPoint = ret_img.ctypes.data_as(POINTER(c_ubyte))
MYDLL.draw_circle(rows, cols, srcPointer, retPoint)
cv2.imshow("ret_img", ret_img) 
cv2.waitKey(0)
cv2.destroyAllWindows()

ret_img_out = Image.fromarray(ret_img[:,:,::-1])  # 参数指针传递,不需要从uchar*转换,只需要取他的源头数据即可.
ret_img_out.show()

三、Mat2string

#include <iostream>
#include <memory.h>
#include <string>
#include <opencv2/opencv.hpp>



void Mat_to_string(cv::Mat& image, std::string& Imagestring) 
{
    
    
	std::vector<uchar> buff;
	cv::imencode(".jpg", image, buff);
	std::string image_string(reinterpret_cast<char*>(&buff[0]), buff.size());
	Imagestring = image_string;
}


void string_to_Mat(std::string& Imagestring, cv::Mat& image)
{
    
    
	std::vector<char> vec_data(Imagestring.c_str(), Imagestring.c_str() + Imagestring.size());
	cv::Mat dst = cv::imdecode(vec_data, cv::IMREAD_UNCHANGED);
	image = dst;
}


int main(int argc, char* argv[])
{
    
    
	cv::Mat image = cv::imread("E:\\Desktop\\20220818142610.png");
	if (image.empty())
	{
    
    
		std::cout << "image is empty" << std::endl;
	}

	std::string Imagestring;
	Mat_to_string(image, Imagestring);
	cv::Mat dst;
	string_to_Mat(Imagestring, dst);

	cv::imshow("dst", dst);
	cv::waitKey(0);
	cv::destroyAllWindows();
	return 0;
}

示例,传递ndarray给cpp,并返回string/ndarray

#pragma once
#ifdef __cplusplus
extern "C"
{
    
    
#endif

#ifdef _WIN32
        #ifndef _TEST_EXPORT_API
                #define _TEST_API  __declspec(dllexport)
        #else
                #define _TEST_API __declspec(dllimport)
        #endif
#else
        #define _TEST_API
#endif

        typedef void* TESTHANDLE;
        typedef  char BOOL;

#ifndef NULL
#define NULL 0
#endif
#define TRUE    1
#define FALSE   0


        _TEST_API void  TESTLableDetect(TESTHANDLE handle, unsigned char* imgPtr, int height, int width, int step, char* result)
        {
    
    
                cv::Mat image = cv::Mat(height, width, CV_8UC3, imgPtr, step);
                TESTLable * pAslObj = (TESTLable*)handle;
                std::string result_string;
                if (pAslObj)
                        pAslObj->detect(image, result_string);
                strncpy(result, result_string.c_str(), result_string.size());
        }

        _TEST_API void  TESTDetect(TESTHANDLE handle, unsigned char* imgPtr, int height, int width, int step, unsigned char* retPtr)
        {
    
    
                cv::Mat image = cv::Mat(height, width, CV_8UC3, imgPtr, step);
                cv::Mat outImage;
                TEST* pTESTObj = (TEST*)handle;
                std::string result_string;
                if (pTESTObj)
                        pTESTObj->detect(image, outImage);
                std::memcpy(retPtr, outImage.data, height * width);
        }

#ifdef __cplusplus
}
#endif
class TEST:
    def __init__(self, tres_path, label_path):
        self.MYDLL = CDLL("./libtest.so")

        #############################################
        #            input output arg
        #############################################
        self.MYDLL.TESTInit.argtypes = [c_char_p, c_char_p]
        self.MYDLL.TESTInit.restype = POINTER(c_ubyte)

        self.MYDLL.TESTDetect.argtypes = [POINTER(c_ubyte), POINTER(c_ubyte), c_int, c_int, c_int, c_char_p]
		self.MYDLL.TEST2Detect.argtypes = [POINTER(c_ubyte), POINTER(c_ubyte), c_int, c_int, c_int, POINTER(c_ubyte)]
        self.MYDLL.TESTDetect.restype = c_void_p

        self.MYDLL.TESTRelease.argtypes = [POINTER(c_ubyte)]
        self.MYDLL.TESTRelease.restype = c_void_p
        self.ASLgcnHandle = self.MYDLL.TESTInit(c_char_p(tres_path),c_char_p(label_path))

    def predict_test(self, image):
        height, width, channels = image.shape
        if 4 == channels:
            image = cv2.cvtColor(image, cv2.COLOR_BGRA2BGR)
        elif 1 == channels:
            image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
        src_pointer = image.ctypes.data_as(POINTER(c_ubyte))
        result = create_string_buffer(550)
        self.MYDLL.TESTDetect(self.ASLgcnHandle, src_pointer, height, width, width * channels, result)
        return result.value.decode('utf-8')
		
    def predict_test2(self, image):
        height, width = image.shape[:2]
        image_resized = cv2.resize(image, (512, 512))
        src_pointer = image_resized.ctypes.data_as(POINTER(c_ubyte))

        ret_img = np.zeros((512, 512), dtype=np.uint8)
        retPoint = ret_img.ctypes.data_as(POINTER(c_ubyte))

        self.MYDLL.TEST2Detect(self.mvss_Handle, src_pointer, 512, 512, 512*3, retPoint)

猜你喜欢

转载自blog.csdn.net/wsp_1138886114/article/details/126517299