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


    一、简单使用

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

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

    ctypes 类型C 类型Python 类型
    c_bool_Boolbool (1)
    c_charchar单字符字节串对象
    c_wcharwchar_t单字符字符串
    c_bytecharint
    c_ubyteunsigned charint
    c_shortshortint
    c_ushortunsigned shortint
    c_intintint
    c_uintunsigned intint
    c_longlongint
    c_ulongunsigned longint
    c_longlong__int64 或 long longint
    c_ulonglongunsigned __int64 或 unsigned long longint
    c_size_tsize_tint
    c_ssize_tssize_tPy_ssize_tint
    c_floatfloatfloat
    c_doubledoublefloat
    c_longdoublelong doublefloat
    c_char_pchar* (以 NUL 结尾)字节串对象或 None
    c_wchar_pwchar_t* (以 NUL 结尾)字符串或 None
    c_void_pvoid*int 或 None
    #include
    #include
    #include
    #include
    
    #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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    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"))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    二、结构体

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    
    #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
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    三、Mat2string

    #include 
    #include 
    #include 
    #include 
    
    
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    示例,传递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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    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)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
  • 相关阅读:
    不同深度的埋点事件如何微妙地改变广告系列的成本
    javaEE7
    nginx502常见502错误问题解决办法
    springboot基于Android的校园综合服务App平台的设计毕业设计源码181040
    【NLP入门教程】二十三、循环神经网络(RNN)| 小白专场
    【记录】Python 之于 C/C++ 区别
    记一次 Visual Studio 2022 卡死分析
    linux之ftp服务-1
    [附源码]计算机毕业设计软考刷题小程序Springboot程序
    博客系统(升级(Spring))(二)获取当前用户信息、对密码进行加密、设置统一数据格式、设置未登录拦截、线程池
  • 原文地址:https://blog.csdn.net/wsp_1138886114/article/details/126517299