使用c#制作一个小型桌面程序
封装dll
首先使用visual stdio 创建Dll新项目,然后属性管理器导入自己的工程属性表(如果没有可以参考visual stdio 如何配置opencv等其他环境)
创建完成后 系统会自动生成一些文件,其中 pch.cpp 先不要修改,pch.h中先导入自己需要用到的库,下面是我的代码
pch.h
#pragma once
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>
#include <string>
现在编写我们的接口代码,我封装的是resnet18的代码:
首先添加源文件ResNetDll.cpp:
ResNetDll.cpp
#include "pch.h"
#include "ResNetDll.h"// 全局变量,用于存储模型路径和图像路径
static std::string g_imagePath;
static std::string g_modelPath;// 图像预处理函数
cv::Mat transformImage(const std::string& imagePath) {cv::Mat image = cv::imread(imagePath);if (image.empty()) {throw std::runtime_error("Failed to load image.");}cv::Mat resizedImage;cv::resize(image, resizedImage, cv::Size(224, 224));cv::Mat floatImage;resizedImage.convertTo(floatImage, CV_32F, 1.0 / 255.0);cv::Mat normalizedImage;cv::Scalar mean(0.485, 0.456, 0.406);cv::Scalar stdDev(0.229, 0.224, 0.225);cv::subtract(floatImage, mean, normalizedImage);cv::divide(normalizedImage, stdDev, normalizedImage);// 从 BGR 转换到 RGBcv::Mat rgbImage;cv::cvtColor(normalizedImage, rgbImage, cv::COLOR_BGR2RGB);return rgbImage;
}// 推理函数
const char* run_inference() {static std::string result;try {// 加载 ONNX 模型cv::dnn::Net net = cv::dnn::readNetFromONNX(g_modelPath);if (net.empty()) {result = "Failed to load the model.";return result.c_str();}// 预处理图像cv::Mat rgbImage = transformImage(g_imagePath);// 创建 blob 并设置为网络输入cv::Mat blob = cv::dnn::blobFromImage(rgbImage, 1.0, cv::Size(224, 224), cv::Scalar(), true, false);net.setInput(blob);// 执行推理cv::Mat output = net.forward();// 处理输出cv::Mat prob = output.reshape(1, 1); // 变换成 1D 张量cv::Point classIdPoint;double confidence;// 用来找到矩阵或图像中元素的最小值和最大值,以及它们所在的位置cv::minMaxLoc(prob, 0, &confidence, 0, &classIdPoint);int classId = classIdPoint.x;// 根据预测结果返回相应的标签result = "Predicted Class ID: " + std::to_string(classId) + " with confidence: " + std::to_string(confidence);return result.c_str();}catch (const std::exception& e) {result = "Error occurred during inference: " + std::string(e.what());return result.c_str();}
}// DLL 暴露的函数,用于设置图像路径
extern "C" RESNETDLL_API void set_image_path(const char* imagePath) {g_imagePath = imagePath;
}// DLL 暴露的函数,用于设置模型路径
extern "C" RESNETDLL_API void set_model_path(const char* modelPath) {g_modelPath = modelPath;
}// DLL 暴露的函数,运行推理
extern "C" RESNETDLL_API const char* run_resnet() {return run_inference();
}
ResNetDll.h:
#pragma once#ifdef RESNETDLL_EXPORTS
#define RESNETDLL_API __declspec(dllexport)
#else
#define RESNETDLL_API __declspec(dllimport)
#endifextern "C" {// 设置图像路径RESNETDLL_API void set_image_path(const char* imagePath);// 设置模型路径RESNETDLL_API void set_model_path(const char* modelPath);// 运行推理RESNETDLL_API const char* run_resnet();
}
点击生成dll,就封装成了windows动态库
制作Demo
创建.NET Framework新项目,将之前生成的dll放在Demo文件夹的bin ->debug或是 release中(看你自己用的什么模式),
新建NativeMethods.cs 这个文件用于 导入 dll中的接口函数或类
我的代码如下
NativeMethods.cs
using System;
using System.Runtime.InteropServices;namespace ResNetApp
{public static class NativeMethods{// 导入 DLL 中的 set_image_path 函数[DllImport("ResNetDll.dll", CallingConvention = CallingConvention.Cdecl)]public static extern void set_image_path(string imagePath);// 导入 DLL 中的 set_model_path 函数[DllImport("ResNetDll.dll", CallingConvention = CallingConvention.Cdecl)]public static extern void set_model_path(string modelPath);// 导入 DLL 中的 run_resnet 函数[DllImport("ResNetDll.dll", CallingConvention = CallingConvention.Cdecl)]public static extern IntPtr run_resnet();}
}
然后在窗口中拉入你想要的控件,这是我的窗口布局

布局完了之后会自动生成Form1.Designer.cs 的窗口设计代码,点击控件按F4 还可以修改他们的属性
Form1.cs
这个代码 编写你想要每个控件实现的功能:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;namespace ResNetApp
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void buttonSelectImage_Click(object sender, EventArgs e){OpenFileDialog openFileDialog = new OpenFileDialog();openFileDialog.Filter = "图像文件|*.bmp;*.jpg;*.jpeg;*.png";if (openFileDialog.ShowDialog() == DialogResult.OK){textBoxImagePath.Text = openFileDialog.FileName; // 显示选择的图像路径}}private void buttonSelectModel_Click(object sender, EventArgs e){OpenFileDialog openFileDialog = new OpenFileDialog();openFileDialog.Filter = "ONNX 模型文件|*.onnx";if (openFileDialog.ShowDialog() == DialogResult.OK){textBoxModelPath.Text = openFileDialog.FileName; // 显示选择的模型路径}}private void button1_Click(object sender, EventArgs e){try{string imagePath = textBoxImagePath.Text;string modelPath = textBoxModelPath.Text;if (string.IsNullOrEmpty(imagePath) || string.IsNullOrEmpty(modelPath)){textBox1.Text = "请选择图像和模型路径。";return;}textBox1.Text = "开始运行 ResNet ...";// 设置图像路径和模型路径NativeMethods.set_image_path(imagePath);NativeMethods.set_model_path(modelPath);// 调用 DLL 执行推理IntPtr resultPtr = NativeMethods.run_resnet();// 将返回的指针转换为字符串string result = Marshal.PtrToStringAnsi(resultPtr);// 显示结果textBox1.Text = result;}catch (Exception ex){textBox1.Text = "错误: " + ex.Message;}}}
}
Program.cs
我们还需要一个入口主程序
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;namespace ResNetApp
{static class Program{/// <summary>/// 应用程序的主入口点。/// </summary>[STAThread]static void Main(){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(new Form1());}}
}
完成之后点击生成 就可以在bin中出现的你的.exe文件咯,是不是很简单呀~[狗头]
相关文章:
使用c#制作一个小型桌面程序
封装dll 首先使用visual stdio 创建Dll新项目,然后属性管理器导入自己的工程属性表(如果没有可以参考visual stdio 如何配置opencv等其他环境) 创建完成后 系统会自动生成一些文件,其中 pch.cpp 先不要修改,pch.h中先导入自己需…...
Clip studio paint百度云下载:附安装包+教程
首先补一个介绍,Clip Studio Paint(即CSP):这是一款专业的绘画和漫画创作软件,拥有丰富的绘画工具,适合漫画创作者使用。其界面友好,工具齐全,能够满足漫画创作中的各种需求。 用过…...
从Yargs源码学习中间件的设计
yargs中间件介绍 yargs 是一个用于解析命令行参数的流行库,它能帮助开发者轻松地定义 CLI(命令行接口),并提供参数处理、命令组织、help文本自动生成等功能。今天我们来学习一下它对中间件的支持。 中间件的API详细信息࿰…...
高级I/O知识分享【epoll || Reactor ET,LT模式】
博客主页:花果山~程序猿-CSDN博客 文章分栏:Linux_花果山~程序猿的博客-CSDN博客 关注我一起学习,一起进步,一起探索编程的无限可能吧!让我们一起努力,一起成长! 目录 一,接口 epo…...
Matlab 的.m 文件批量转成py文件
在工作中碰到了一个问题,需要将原来用matlab gui做出来的程序改为python程序,因为涉及到很多文件,所以在网上搜了搜有没有直接能转化的库。参考了【Matlab】一键Matlab代码转python代码详细教程_matlab2python-CSDN博客 这位博主提到的matla…...
【软考】传输层协议TCP与UDP
目录 1. TCP1.1 说明1.2 三次握手 2. UDP3. 例题3.1 例题1 1. TCP 1.1 说明 1.TCP(Transmission Control Protocol,传输控制协议)是整个 TCP/IP 协议族中最重要的协议之一。2.它在IP提供的不可靠数据服务的基础上为应用程序提供了一个可靠的、面向连接的、全双工的…...
Arthas dashboard(当前系统的实时数据面板)
文章目录 二、命令列表2.1 jvm相关命令2.1.1 dashboard(当前系统的实时数据面板) 二、命令列表 2.1 jvm相关命令 2.1.1 dashboard(当前系统的实时数据面板) 使用场景: 在 Arthas 中,dashboard 命令用于提…...
微服务保护之熔断降级
在微服务架构中,服务之间的调用是通过网络进行的,网络的不确定性和依赖服务的不可控性,可能导致某个服务出现异常或性能问题,进而引发整个系统的故障,这被称为 微服务雪崩。为了防止这种情况发生,常用的一些…...
TomCat乱码问题
TomCat控制台乱码问题 乱码问题解决: 响应乱码问题 向客户端响应数据: package Servlet;import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servl…...
依赖库查看工具Dependencies
依赖库查看工具:Dependencies Dependencies 是一款 Windows 平台下的静态分析工具,用来分析可执行文件(EXE、DLL 等)所依赖的动态链接库(DLL)。它可以帮助开发者和系统管理员快速查找程序在运行时可能缺少的…...
Kafka 下载安装及使用总结
1. 下载安装 官网下载地址:Apache Kafka 下载对应的文件 上传到服务器上,解压 tar -xzf kafka_2.13-3.7.0.tgz目录结果如下 ├── bin │ └── windows ├── config │ └── kraft ├── libs ├── licenses └── site-docs官方文档…...
python实现多个pdf文件合并
打印发票时,需要将pdf合并成一个,单页两张打印。网上一些pdf合并逐渐收费,这玩意儿都能收费?自己写一个脚本使用。 实现代码: 输入pdf文件夹路径data_dir,统计目录下的“合并后的PDF”文件夹下,…...
2409js,学习js2
原文 全局对象 function sayHi() {alert("Hello"); }// 全局对象的函数. window.sayHi(); alert(window.innerHeight);更改背景 document.body.style.background "red";setTimeout(() > document.body.style.background "", 1000);当前地…...
SpellBERT: A Lightweight Pretrained Model for Chinese Spelling Check(EMNLP2021)
SpellBERT: A Lightweight Pretrained Model for Chinese Spelling Check(EMNLP2021) 一.概述 作者认为许多模型利用预定义的混淆集来学习正确字符与其视觉上相似或语音上相似的误用字符之间的映射,但映射可能是域外的。为此,我们提出了SpellBERT&…...
【机器学习】--- 决策树与随机森林
文章目录 决策树与随机森林的改进:全面解析与深度优化目录1. 决策树的基本原理2. 决策树的缺陷及改进方法2.1 剪枝技术2.2 树的深度控制2.3 特征选择的优化 3. 随机森林的基本原理4. 随机森林的缺陷及改进方法4.1 特征重要性改进4.2 树的集成方法优化4.3 随机森林的…...
[SAP ABAP] 创建域
我们可以使用事务码SE11创建域 输入要创建的域的名称,然后点击创建 输入简短描述,选择数据类型和输入字符数 激活并保存域,创建的域才能够生效 补充扩展练习 创建一个有关"性别"基本信息的域...
STM32 通过 SPI 驱动 W25Q128
目录 一、STM32 SPI 框图1、通讯引脚2、时钟控制3、数据控制逻辑4、整体控制逻辑5、主模式收发流程及事件说明如下: 二、程序编写1、SPI 初始化2、W25Q128 驱动代码2.1 读写厂商 ID 和设备 ID2.2 读数据2.3 写使能/写禁止2.4 读/写状态寄存器2.5 擦除扇区2.6 擦除整…...
C#进阶-基于雪花算法的订单号设计与实现
在现代电商系统和分布式系统中,高效地生成全局唯一的订单号是一个关键需求。订单号不仅需要唯一性,还需要具备一定的趋势递增性,以满足数据库索引和排序的需求。本文将介绍如何在C#中使用雪花算法(Snowflake)设计和实现…...
低版本SqlSugar的where条件中使用可空类型报语法错误
SQLServer数据表中有两列可空列,均为数值类型,同时在数据库中录入测试数据,Age和Height列均部分有值。 使用SqlSugar的DbFirst功能生成数据库表类,其中Age、Height属性均为可空类型。 开始使用的SqlSugar版本较低&…...
跨游戏引擎的H5渲染解决方案(腾讯)
本文是腾讯的一篇H5 跨引擎解决方案的精炼。 介绍 本文通过实现基于精简版的HTML5(HyperText Mark Language 5)来屏蔽不同引擎,平台底层的差异。 好处: 采用H5的开发方式,可以将开发和运营分离,运营部门自…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...
6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙
Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...
Unity VR/MR开发-VR开发与传统3D开发的差异
视频讲解链接:【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...
归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...
算法250609 高精度
加法 #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; char input1[205]; char input2[205]; int main(){while(scanf("%s%s",input1,input2)!EOF){int a[205]…...
