使用c#制作一个小型桌面程序

news2024/9/21 19:46:37

封装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 转换到 RGB
    cv::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)
#endif

extern "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文件咯,是不是很简单呀~[狗头]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2144688.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python画笔案例-053 绘制海龟螺旋图

1、绘制海龟螺旋图 通过 python 的turtle 库绘制 海龟螺旋图&#xff0c;如下图&#xff1a; 2、实现代码 绘制海龟螺旋图&#xff0c;以下为实现代码&#xff1a; """海龟螺旋图.py""" import turtle from random import randintscreen turtl…

引入第三方字体图标icon

引入第三方字体图标icon 1.登录阿里巴巴icon库 2.点开ui提供的字体图标并下载 3.解压download 将font_4008950_i6fkbudh8ld文件放置项目中例如&#xff1a;放在assets文件夹下 4.然后再main.js中引入 import ‘/assets/font_4008950_i6fkbudh8ld/iconfont.css’; 5.项目中应…

Rsync未授权访问漏洞复现及彻底修复

一、什么是 Rsync&#xff1f; Rsync 是一种广泛使用的文件传输工具&#xff0c;它允许系统管理员和用户通过局域网&#xff08;LAN&#xff09;或广域网&#xff08;WAN&#xff09;在计算机之间同步文件和目录。Rsync 支持通过本地或远程 shell 访问&#xff0c;也可以作为守…

STM32——输入捕获

输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器&#xff0c;除了TIM6、TIM7&#xff0c;其他的定时器都有输入捕获的功能。应用场景是编码器。 测量频率 当捕获通道TIx 上出现上升沿时&#xff0c;发生第一次捕获&#xff0c;计数器CNT 的值会被锁存到捕获寄存…

Java中的红黑树(如果想知道Java中有关红黑树的知识点,那么只看这一篇就足够了!)

前言&#xff1a;红黑树作为一种自平衡的二叉搜索树&#xff0c;在计算机科学领域具有极其重要的地位。它通过颜色约束和旋转操作保持树的高度平衡&#xff0c;从而保证了查找、插入、删除等操作的高效性。红黑树广泛应用于操作系统的调度算法、数据库索引、Java集合框架等领域…

「全球大模型竞技场」更新:DeepSeek-V2.5全面领跑国内模型

原文&#xff1a;深度求索 DeepSeek 月初&#xff0c;我们发布并开源了 DeepSeek-V2.5&#xff0c;一个融合通用与代码能力的全新模型。 近日&#xff0c;LMSYS 组织的全球大模型竞技场&#xff08;ChatBotArena&#xff09;更新结果发布&#xff0c;DeepSeek-V2.5 排名位列国…

额定剩余动作电流继电器有什么功能?

ASJ系列剩余电流动作继电器可与低压断路器或低压接触器等组装成组合式的剩余电流动作保护器&#xff0c;为现代电力系统设计&#xff0c;旨在提高电力系统的安全性和可靠性。其技术和多功能特性使其成为电力管理和监测的理想选择。主要适用于交流50Hz&#xff0c;额定电压为400…

iPhone 16系列:熟悉的味道,全新的体验

来看看iPhone 16和Plus这两个新成员&#xff0c;实话说&#xff0c;它们和之前曝光的样子几乎完全一致。下面我们就一起来细数一下这次的几大变化吧。 外观设计&#xff1a;焕然一新 首先&#xff0c;最显眼的变化就是后置镜头模组的布局调整为了垂直排列。这一改变使得整个背…

29912分页

拆分地址&#xff1a; 003FDFB0 0000 0000 0011 1111 1101 1111 1011 000000 0*8 00 0000 001 -> 1*8 1 1111 1101 -> 1FD*8 1111 1011 0000 -> FB0PROCESS 883ef7c8 SessionId: 1 Cid: 09b0 Peb: 7ffdf000 ParentCid: 0588DirBase: bf2484a0 ObjectTable: 98…

将多个pdf合并成一个文件?这几种合并方法很好用!

如何将多个pdf合并成一个文件&#xff1f;面对日益增长的PDF文档&#xff0c;我们时常陷入管理困境&#xff0c;这不仅仅关乎于时间与精力的巨大消耗&#xff0c;因为这些孤立的PDF文件如同散落的拼图碎片&#xff0c;让关键信息的搜寻变得如同大海捞针&#xff0c;严重拖慢了工…

双指针算法:快速解决问题的小技巧(Java代码实现)

“人的一生是短暂的&#xff0c;但如果卑鄙地过这短暂的一生&#xff0c;那就太长了。” 文章目录 前言文章有误敬请斧正 不胜感恩&#xff01;双指针简介对撞指针快慢指针例题聪明的小羊肖恩神奇的数组盛最多的水 总结 前言 写在开始&#xff1a; 双指针算法是一种经典且高效…

“中秋快乐”文字横幅的MATLAB代码生成

中秋快乐呀朋友们&#xff01;&#xff01;&#xff01; 给大家带来一个好玩的代码&#xff0c;能够生成“中秋快乐”的横幅文字&#xff0c;比较简单&#xff0c;当然你也可以根据自己的需求去更改文字和背景&#xff0c;废话不多说&#xff0c;直接展示。 文字会一直闪烁&…

智能BI项目第三期

AIGC AI 提问技巧 为了让 Al 更好地理解我们的输入&#xff0c;并给出预期精确的输出&#xff0c;需要严格控制我们的提问词。 1.使用系统预设 控制输入格式(便于Al精确地理解我们的需求) 你是一个数据分析师和前端开发专家&#xff0c;接下来我会按照以下固定格式给你提供…

《深度学习》PyTorch框架 优化器、激活函数讲解

目录 一、深度学习核心框架的选择 1、TensorFlow 1&#xff09;概念 2&#xff09;优缺点 2、PyTorch 1&#xff09;概念 2&#xff09;优缺点 3、Keras 1&#xff09;概念 2&#xff09;优缺点 4、Caffe 1&#xff09;概念 2&#xff09;优缺点 二、pytorch安装 1、安装 2、…

传输层协议 —— UDP协议

目录 0.前言 1.UDP协议格式 16位源端口和目的端口 16位UDP长度 16位校验和 2.UDP协议特点 无连接 不可靠 面向数据报 3.UDP的缓冲区 0.前言 首先&#xff0c;我们得明确一点&#xff0c;网络模型是分层的。自底向上分别是物理层、数据链路层、网络层、传输层、应用层…

Nginx反向代理出现502 Bad Gateway问题的解决方案

&#x1f389; 前言 前一阵子写了一篇“关于解决调用百度翻译API问题”的博客&#xff0c;近日在调用其他API时又遇到一些棘手的问题&#xff0c;于是写下这篇博客作为记录。 &#x1f389; 问题描述 在代理的遇到过很多错误码&#xff0c;其中出现频率最高的就是502&#x…

JavaEE:网络编程(套接字)

文章目录 Socket套接字TCP和UDP的区别有连接/无连接可靠传输/不可靠传输面向字节流/面向数据报全双工/半双工 UDP/TCP api的使用UDPDatagramSocketDatagramPacketInetSocketAddress练习 TCPServerSocketSocket练习 Socket套接字 Socket是计算机网络中的一种通信机制&#xff0…

驱动开发知识点

裸机开发 ——————————————linux驱动 SOC&#xff1a; 定义&#xff1a;SOC&#xff0c;全称System on Chip&#xff0c;是一种集成了多个功能模块的芯片&#xff0c;包括处理器、内存、外设、接口等。它将原本分散在多个芯片上的功能集成到一个芯片上&#xff0…

一个基于 laravel 和 amis 开发的后台框架, 友好的组件使用体验,可轻松实现复杂页面(附源码)

前言 随着互联网应用的发展&#xff0c;后台管理系统的复杂度不断增加&#xff0c;对于开发者而言&#xff0c;既要系统的功能完备&#xff0c;又要追求开发效率的提升。然而&#xff0c;传统的开发方式往往会导致大量的重复劳动&#xff0c;尤其是在构建复杂的管理页面时。有…

不限学历!这个证书在上海太香了!利于积分、落户、抵扣个税...

一、软考是什么&#xff1f; “软考”全称&#xff1a;计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff0c;关于它你需要知道&#xff1a; 1、软考是全国性考试&#xff1a;软考实行全国统一规划&#xff0c;实行统一大纲&#xff0c;统一试题&#xff…