python调用C++ DLL

article/2025/6/26 11:30:00
使用C++创建动态链接库:

dllmain.cpp

#include <windows.h>
#include <string>
#include <vector>
#include "opencv2/opencv.hpp"BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {return TRUE;
}extern "C" __declspec(dllexport) void ProcessImage(unsigned char* data, int width, int height, int channels, int* result);extern "C" __declspec(dllexport) void image_ocr_cropped_c(cv::Mat image,const char* rectangle_message,const char*  model_path,const char*  model_name,int buffer_size,char* out_buffer,const char*  device_name = "cuda",int device_index = 0,float detect_thres = -1.0);extern "C" __declspec(dllexport) void image_ocr_cropped_c_adapter(unsigned char* data, int width, int height, int channels,const char* rectangle_message,const char* model_path,const char* model_name,int buffer_size,char* output_buffer,const char* device_name,int device_index,float detect_thres);

process_image.cpp

#define NOMINMAX
#include <windows.h>
#include <opencv2/opencv.hpp>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm> extern "C" __declspec(dllexport) void ProcessImage(unsigned char* data, int width, int height, int channels, int* result)
{try {// 构造 Mat 对象cv::Mat img(height, width, CV_8UC(channels), data);// 转灰度图cv::Mat gray;if (channels == 3) {cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);}else {gray = img.clone();}// 保存图像cv::imwrite("output_gray.jpg", gray);// 返回灰度图的尺寸result[0] = gray.cols; // widthresult[1] = gray.rows; // height}catch (...) {result[0] = -1;result[1] = -1;}
}// 导出函数接口(兼容 C 调用)
extern "C" __declspec(dllexport) void image_ocr_cropped_c(cv::Mat image, const char* rectangle_message, const char*  model_path, const char*  model_name, int buffer_size, char* out_buffer, const char*  device_name = "cuda", int device_index = 0, float detect_thres = -1.0)
{std::vector<cv::Rect> rectangles;std::string input(rectangle_message);// 分割不同的矩形组size_t start = 0;while (true) {size_t rectStart = input.find("Rectangle", start);if (rectStart == std::string::npos) break;size_t braceStart = input.find('{', rectStart);size_t braceEnd = input.find('}', braceStart);if (braceStart == std::string::npos || braceEnd == std::string::npos) break;std::string rectStr = input.substr(braceStart + 1, braceEnd - braceStart - 1);// 分割矩形组内的各个多边形size_t polyStart = 0;while (true) {size_t colonPos = rectStr.find(':', polyStart);if (colonPos == std::string::npos) break;size_t semicolonPos = rectStr.find(';', colonPos);if (semicolonPos == std::string::npos) {semicolonPos = rectStr.length();}std::string polyStr = rectStr.substr(colonPos + 1, semicolonPos - colonPos - 1);//std::vector<int> coords = extractNumbers(polyStr);std::vector<int> coords;std::stringstream ss;for (char ch : polyStr) {if (isdigit(ch) || ch == '-') {ss << ch;}else if (ss.tellp() > 0) {int num;ss >> num;coords.push_back(num);ss.clear();ss.str("");}}// 处理最后一个数字if (ss.tellp() > 0) {int num;ss >> num;coords.push_back(num);}if (coords.size() >= 8) { // 至少4个点// 计算包围所有点的最小矩形int minX = coords[0], maxX = coords[0];int minY = coords[1], maxY = coords[1];for (size_t i = 2; i < coords.size(); i += 2) {int x = coords[i];int y = coords[i + 1];minX = std::min(minX, x);maxX = std::max(maxX, x);minY = std::min(minY, y);maxY = std::max(maxY, y);}cv::Rect rect(minX, minY, maxX - minX, maxY - minY);rectangles.push_back(rect);}polyStart = semicolonPos + 1;}start = braceEnd + 1;}//std::vector<cv::Rect> rectangles = parseRectangles_c(rectangle_message);// 打印所有矩形for (size_t i = 0; i < rectangles.size(); ++i) {cv::Rect roi = rectangles[i];std::cout << "Rectangle " << i + 1 << ": x=" << roi.x << ", y=" << roi.y<< ", w=" << roi.width << ", h=" << roi.height << std::endl;// 检查 ROI 是否在图像范围内if (roi.x >= 0 && roi.y >= 0 &&roi.x + roi.width <= image.cols &&roi.y + roi.height <= image.rows) {// 裁剪图像cv::Mat cropped = image(roi);// 显示或保存裁剪后的图像std::string windowName = "Cropped Image " + std::to_string(i + 1);cv::imshow(windowName, cropped);// 可选:保存裁剪后的图像到文件cv::imwrite("cropped_" + std::to_string(i + 1) + ".jpg", cropped);}}strncpy_s(out_buffer, buffer_size, rectangle_message, _TRUNCATE);return;
}extern "C" __declspec(dllexport) void image_ocr_cropped_c_adapter(unsigned char* data, int width, int height, int channels,const char* rectangle_message,const char* model_path,const char* model_name,int buffer_size,char* output_buffer,const char* device_name,int device_index,float detect_thres
)
{try {// 构造 Matcv::Mat image(height, width, CV_8UC(channels), data);// 调用原有函数image_ocr_cropped_c(image,rectangle_message,model_path,model_name,buffer_size,output_buffer,device_name,device_index,detect_thres);}catch (...) {strncpy_s(output_buffer, 1024, "Error during processing", buffer_size);}
}

生成对应的动态链接库ImageProcessorDll.dll

文件结构:

./
└── test_cv_dll.py
├── ImageProcessorDll.dll
├── opencv_world454.dll
└── test1.jpeg
Python调用:
import cv2
import ctypes
import os
# 加载 DLL
dll_path = r'.\ImageProcessorDll.dll'
# 确保路径存在
assert os.path.exists(dll_path), f"DLL 文件不存在:{dll_path}"# 加载 DLL
try:dll = ctypes.CDLL(dll_path)
except Exception as e:print("加载 DLL 出错:", e)exit(1)# 读取图像
img = cv2.imread('test1.jpeg')  # BGR 格式# 获取图像信息
height, width, channels = img.shape
print(f"Original image size: {width}x{height}")# 图像数据转为指针
data = img.ctypes.data_as(ctypes.POINTER(ctypes.c_ubyte))# 输出缓冲区
buffer_size = 4096
output_buffer = ctypes.create_string_buffer(buffer_size)print("===========================ProcessImage()========================================")
# 定义函数参数类型
dll.ProcessImage.argtypes = [ctypes.POINTER(ctypes.c_ubyte),ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.POINTER(ctypes.c_int)
]# 结果数组用于接收尺寸
result = (ctypes.c_int * 2)()
# 调用 DLL 函数
dll.ProcessImage(data, width, height, channels, result)
# 输出处理后的尺寸
print(f"Gray image size: {result[0]}x{result[1]}")print("=====================image_ocr_cropped_c_adapter()================================")
# 定义新接口的 argtypes
dll.image_ocr_cropped_c_adapter.argtypes = [ctypes.POINTER(ctypes.c_ubyte),  # imageDatactypes.c_int,                    # widthctypes.c_int,                    # heightctypes.c_int,                    # channelsctypes.c_char_p,                 # rectangle_messagectypes.c_char_p,                 # model_pathctypes.c_char_p,                 # model_namectypes.c_size_t,                 # buffer_sizectypes.c_char_p,                 # output_bufferctypes.c_char_p,                 # device_namectypes.c_int,                    # device_indexctypes.c_float,                  # detect_thres
]
dll.image_ocr_cropped_c_adapter.restype = None# 调用适配器函数
dll.image_ocr_cropped_c_adapter(data,width,height,channels,b"Rectangle1:{50:(604,1420),(893,1420),(604,1511),(893,1511);50:(1758,1408),(2026,1408),(1758,1495),(2026,1495);20.0:(2319,865),(2589,865),(2319,956),(2589,956);20.0:(2313,1408),(2596,1408),(2313,1497),(2596,1497);}",b"K",                    # model_pathb"test",				 # model_namebuffer_size,			 # buffer_sizeoutput_buffer,			 # output_bufferb"cuda",				 # device_name0,						 # device_index-1.0					 # detect_thres
)result = output_buffer.value.decode('utf-8')
print("OCR Result:\n", result)
Original image size: 3264x2448
=============ProcessImage()===============
Gray image size: 3264x2448
=====================image_ocr_cropped_c_adapter()================================
Rectangle 1: x=604, y=1420, w=289, h=91
Rectangle 2: x=1758, y=1408, w=268, h=87
Rectangle 3: x=2319, y=865, w=270, h=91
Rectangle 4: x=2313, y=1408, w=283, h=89
OCR Result:Rectangle1:{50:(604,1420),(893,1420),(604,1511),(893,1511);50:(1758,1408),(2026,1408),(1758,1495),(2026,1495);20.0:(2319,865),(2589,865),(2319,956),(2589,956);20.0:(2313,1408),(2596,1408),(2313,1497),(2596,1497);}

在这里插入图片描述


http://www.hkcw.cn/article/koipUEuprl.shtml

相关文章

多米尼加坍塌事故死亡人数升至234人 全国哀悼日持续六天

当地时间5月31日,多米尼加医疗中心报告称,一名在俱乐部屋顶坍塌事故中的重症患者不幸去世,使得该事故的死亡人数上升至234人。这起事故发生在4月8日凌晨,地点是多米尼加首都圣多明各的一家俱乐部。当时俱乐部内正在举行知名歌手的演出,突然倒塌的屋顶导致许多人被埋在废墟…

姜广涛仅剩光合积木一家公司存续 配音演员告别引发关注

5月31日,多名配音演员宣布离开光合积木,未来将以自由人的身份继续参与配音工作,但与光合积木仍会保持项目上的合作。姜广涛也发文表示自己仍在学习的路上,并祝愿同事们在配音道路上继续前行,开启新的篇章。企查查数据显示,姜广涛目前仅关联一家存续状态的企业——北京光合…

刘楚昕称请允许我暂时沉默 获奖感言感动无数人

近日,作家刘楚昕创作的小说《泥潭》获漓江文学奖虚构类奖,获奖感言回忆去世女友感动无数人。刘楚昕通过漓江文学节官方微博写信回应网友:请允许我暂时沉默。责任编辑:0764

以媒:援助混乱凸显加沙居民困境 人道主义的讽刺剧

这年头的人道主义救援似乎充满了各种弯弯绕绕。加沙南部拉法的物资分发现场,表面上宣称要发出46.2万份食品包,沙特和阿联酋出钱,以色列做东,但实际上大部分实际受援的人被排除在外。联合国和老牌援助组织被排挤,分发权交给了私人企业和美国雇佣军。这种操作让人怀疑其真实…

我眼中技术文档的演进图谱:从windows开发手册到 AI 智能体的知识传承

-----一位25年的技术亲历者的时代观察 序 2000 年毕业进入科研所时&#xff0c;我未曾想过 CRT 显示器与泛黄的《Windows 宝典》会成为技术启蒙的坐标。从调试 MFC 控件的桌面开发起步&#xff0c;到 Web1.0 时代与 IE6 兼容性博弈的战术文档&#xff0c;再到 Kubernetes 部…

AI重塑银行客户服务:洞察呼叫中心与CRM的智能化变革

摘要: 随着银行业数字化转型的浪潮奔涌向前,人工智能(AI)正以前所未有的深度和广度渗透至客户服务的核心地带——呼叫中心与客户关系管理(CRM)系统。这不仅是一场技术革新,更是一场围绕客户体验、运营效率和业务增长的战略升级。本文将剖析AI在银行呼叫中心与CRM中的典型…

巴啦啦小魔仙凌妈妈曝片酬:1500一天 童年回忆再聚首

《巴啦啦小魔仙》中的凌妈妈和凌爸爸在时隔17年后重聚,两人的变化不大,依然显得年轻。网友们纷纷表示,仿佛看到了自己的童年电子爸妈合体。凌妈妈的扮演者左左感慨时间飞逝,尽管多年未拍戏,但她对自己能留下这样一个经典角色感到满足。他们还透露了当年拍摄时的片酬情况,…

李昀锐关晓彤《耀眼》捂眼路透 甜蜜互动引爆网络

近日,一组李昀锐与关晓彤在拍摄现场的路透照片在网络上引起热议。照片中,关晓彤身穿浅蓝色连衣裙,突然伸手捂住李昀锐的眼睛,后者嘴角微扬的瞬间被镜头捕捉,青春气息十足。这组被称为“捂眼路透”的未公开剧照在社交平台迅速传播,相关话题阅读量已突破3亿。两人正在合作拍…

市民称在周大福买到假金项链 送修发现材质异常

5月29日,张女士称她在2020年于贵安奥特莱斯购物广场的周大福门店购买了两条金项链。今年4月,她将这两条项链送至东百中心周大福门店进行保养和修复时,发现链子过火后发黑。经鉴定确认并非黄金材质。张女士要求退货并按照“假一赔三”标准赔偿,但至今未获解决。东百中心周大…

吴宣仪喜欢听话不乱闹的粉丝 积极支持朋友

吴宣仪在评区回复粉丝对自己在《浪姐》的助战嘉宾选了刘宇的不满,让大家不要把私欲加到她身上,她的朋友来应该热烈欢迎,她喜欢积极听话不乱闹的粉丝责任编辑:0882

省纪委回应县委书记建豪华厕所 劳民伤财“形象工程”

刚摘掉深度贫困县的帽子,时任县委书记李德明就斥资上千万元,建了10个豪华水冲公厕。日前,吉林省纪委监委公开通报了4起形式主义、官僚主义典型问题,其中提到省农业农村厅原厅长、白城市通榆县委原书记李德明搞劳民伤财的“形象工程”。2023年,李德明升任省农业农村厅厅长,…

外卖骑手们的“流量”副业 解锁隐藏赚钱技能

送外卖只能赚辛苦钱?凌晨3点,95后骑手小林在朋友圈晒出上月收入截图——1.8万,评论区瞬间炸锅。当同行还在为单价下跌焦虑时,他已悄悄解锁了骑手职业的“隐藏副本”。跨平台接单是资深骑手的黄金组合。北京骑手老张透露:“利用美团午高峰、饿了么晚高峰和闪送夜间急单,单…

印尼西爪哇省山体滑坡已致17人死亡 地质灾害频发

当地时间5月31日,印尼西爪哇省芝拉朋县一处采砂场发生山体滑坡事故,导致17名矿工遇难。印尼地质结构复杂,强降雨频发,因此山体滑坡等地质灾害时有发生。责任编辑:0882

刘浩存王安宇吻戏借位遭吐槽 揭秘背后三重真相

当《陷入我们的热恋》第8集“图书馆偷亲”镜头切到刘浩存与王安宇鼻尖相距0.1毫米的特写时,全网炸开了锅——这已经是她连续第三部剧用借位吻戏挑战观众的忍耐极限。从《脱轨》的“拇指吻”到《热恋》的“空气吻”,刘浩存的吻戏玄学堪称内娱未解之谜,而这背后藏着三重惊人真…

肖战张婧仪《藏海传》吻戏太戳心 权谋与情愫交织

古装权谋大剧《藏海传》最新剧情中,藏海(肖战饰)与香暗荼(张婧仪饰)的一场意外吻戏在社交平台上引发热议。这场充满权谋与情愫交织的亲密戏份不仅成为角色关系的重大转折点,还让观众直呼“复仇CP的暧昧感拉满”。这场戏发生在藏海识破香暗荼真实身份的关键时刻,两人在枕…

女子被迫吸二手烟痛苦猛洗澡 烟味噩梦何时休

一位女子长期被迫吸入二手烟,下班后总是急着洗澡,仿佛这样就能洗掉一身的“烟味噩梦”,这让人感到非常心疼。二手烟的危害不容小觑。世界卫生组织统计显示,每年约有120万非吸烟者因二手烟死亡,其中许多与工作场所暴露有关。在中国,2018年的成人烟草调查显示,非吸烟者的二…

国防大学副校长驳斥:中方不接受无端指责

5月31日傍晚,针对美西方等个别国家在新加坡香格里拉对话会上对中国的无端指责,中国人民解放军国防大学代表团团长、国防大学副校长兼教育长胡钢锋少将在会议上发言批驳。他表示,不接受对中方的无端指责,有关内容无中生有,煽动对抗,企图搞乱亚太,不得人心,也不可能得逞。…

撒贝宁全家千岛湖打水仗 奶爸流量引关注

“哎哟!撒老师,您也来打水仗啦?”这不是综艺节目录制现场,而是5月31日的千岛湖“贪玩节”。撒贝宁被游客用水枪“围攻”,一身T恤贴在身上,腹肌线条若隐若现,比节目里的他还要“上头”。谁说央视主持人就得一本正经?这一天,撒贝宁彻底“放飞自我”,带着妻子李白和一对…

63岁老人跳河轻生 武警官兵紧急救援 生死营救12分钟

5月30日上午10点25分,在四川成都南浦东路万里桥段,一名老人从府南河南侧跳河轻生。接到执勤哨兵的通报后,武警四川总队成都支队11名官兵迅速赶赴现场,展开了一场生死营救。执勤哨兵听到群众呼救声后立即查看,发现有人落水,随即通过无线电报告。当时,孟凯带领10名战士携带…

这部口碑神作堕落了 创意凋零警示录

看完《爱,死亡和机器人》第四季,感觉浪费了宝贵的一个多小时。豆瓣评分跌至4.8的历史最低分,相较于前三季可谓“雪崩式”溃败。这部曾被视为动画、科幻剧乃至游戏CG融合标杆的作品,如今竟堕落到如此地步,观众的不满是有道理的。从立项伊始,《爱死机》就被定位为“全家桶快…