当前位置: 首页 > news >正文

[C#][winform]基于yolov8的舌苔舌象疾病诊断检测系统C#源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】

基于YOLOv8的舌苔识别检测系统是一项融合了先进计算机视觉技术的创新应用。YOLOv8作为YOLO系列目标检测模型的最新版本,以其卓越的检测速度和精确度著称,能够实时、准确地识别和定位图像中的多个对象。在舌苔识别领域,YOLOv8的应用极大地提升了检测效率和准确性。

该系统通过训练YOLOv8模型,使其能够识别舌苔中的关键特征,如苔色、舌色、齿痕及裂纹等。这些特征对于中医体质辨识至关重要。用户只需上传舌苔图片,系统即可快速分析并展示识别结果,同时结合中医理论,给出相应的体质信息判断。

相比传统检测方法,基于YOLOv8的舌苔识别检测系统具有高速、高精度、多平台兼容及多任务支持等显著优势。它不仅能够简化检测流程,降低检测成本,还能提高检测结果的客观性和准确性,为中医体质辨识提供有力支持。此外,该系统还可广泛应用于医疗、健康管理等领域,为公众提供更加便捷、高效的健康服务。

【效果展示】

【测试环境】

windows10 x64系统
VS2019
netframework4.7.2
opencvsharp4.9.0
onnxruntime1.22.0

【模型可以检测出类别】

houbai(厚白)
huihei(灰黑)
houhuang(厚黄)
fenhong(粉红)
bobai(薄白)

【训练信息】

参数
训练集图片数720
验证集图片数80
训练map98.9%
训练精度(Precision)96.0%
训练召回率(Recall)96.8%

验证集测试精度信息

Class

Images

Instances

P

R

mAP50

mAP50-95

all

80

80

0.96

0.968

0.989

0.847

houbai

19

19

0.994

0.947

0.993

0.865

huihei

10

10

0.995

1

0.995

0.782

houhuang

15

15

0.933

1

0.987

0.881

fenhong

20

20

0.95

0.954

0.983

0.855

bobai

16

16

0.929

0.938

0.988

0.854

【界面设计】

using DeploySharp.Data; using OpenCvSharp; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace FIRC { public partial class Form1 : Form { public bool videoStart = false;//视频停止标志 string weightsPath = Application.StartupPath + "\\weights";//模型目录 YoloDetector detetor = new YoloDetector();//推理引擎 public Form1() { InitializeComponent(); CheckForIllegalCrossThreadCalls = false;//线程更新控件不报错 } private void LoadWeightsFromDir() { var di = new DirectoryInfo(weightsPath); foreach(var fi in di.GetFiles("*.onnx")) { comboBox1.Items.Add(fi.Name); } if(comboBox1.Items.Count>0) { comboBox1.SelectedIndex = 0; } else { tssl_show.Text = "未找到模型,请关闭程序,放入模型到weights文件夹!"; tsb_pic.Enabled = false; tsb_video.Enabled = false; tsb_camera.Enabled = false; } } private void Form1_Load(object sender, EventArgs e) { LoadWeightsFromDir();//从目录加载模型 } public string GetResultString(DetResult[] result) { Dictionary<string, int> resultDict = new Dictionary<string, int>(); for (int i = 0; i < result.Length; i++) { if(resultDict.ContainsKey( result[i].Category) ) { resultDict[result[i].Category]++; } else { resultDict[result[i].Category] =1; } } var resultStr = ""; foreach(var item in resultDict) { resultStr += string.Format("{0}:{1}\r\n",item.Key,item.Value); } return resultStr; } private void tsb_pic_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png"; if (ofd.ShowDialog() != DialogResult.OK) return; tssl_show.Text = "正在检测中..."; Task.Run(() => { var sw = new Stopwatch(); sw.Start(); Mat image = Cv2.ImRead(ofd.FileName); detetor.SetParams(Convert.ToSingle(numericUpDown1.Value), Convert.ToSingle(numericUpDown2.Value)); var results=detetor.Inference(image); var resultImage = detetor.DrawImage(image, results); sw.Stop(); pb_show.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(resultImage); tb_res.Text = GetResultString(results); tssl_show.Text = "检测已完成!总计耗时"+sw.Elapsed.TotalSeconds+"秒"; }); } public void VideoProcess(string videoPath) { Task.Run(() => { detetor.SetParams(Convert.ToSingle(numericUpDown1.Value), Convert.ToSingle(numericUpDown2.Value)); VideoCapture capture = new VideoCapture(videoPath); if (!capture.IsOpened()) { tssl_show.Text="视频打开失败!"; return; } Mat frame = new Mat(); var sw = new Stopwatch(); int fps = 0; while (videoStart) { capture.Read(frame); if (frame.Empty()) { Console.WriteLine("data is empty!"); break; } sw.Start(); var results = detetor.Inference(frame); var resultImg = detetor.DrawImage(frame,results); sw.Stop(); fps = Convert.ToInt32(1 / sw.Elapsed.TotalSeconds); sw.Reset(); Cv2.PutText(resultImg, "FPS=" + fps, new OpenCvSharp.Point(30, 30), HersheyFonts.HersheyComplex, 1.0, new Scalar(255, 0, 0), 3); //显示结果 pb_show.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(resultImg); tb_res.Text = GetResultString(results); Thread.Sleep(5); } capture.Release(); pb_show.Image = null; tssl_show.Text = "视频已停止!"; tsb_video.Text = "选择视频"; }); } public void CameraProcess(int cameraIndex=0) { Task.Run(() => { detetor.SetParams(Convert.ToSingle(numericUpDown1.Value), Convert.ToSingle(numericUpDown2.Value)); VideoCapture capture = new VideoCapture(cameraIndex); if (!capture.IsOpened()) { tssl_show.Text = "摄像头打开失败!"; return; } Mat frame = new Mat(); var sw = new Stopwatch(); int fps = 0; while (videoStart) { capture.Read(frame); if (frame.Empty()) { Console.WriteLine("data is empty!"); break; } sw.Start(); var results = detetor.Inference(frame); var resultImg = detetor.DrawImage(frame, results); sw.Stop(); fps = Convert.ToInt32(1 / sw.Elapsed.TotalSeconds); sw.Reset(); Cv2.PutText(resultImg, "FPS=" + fps, new OpenCvSharp.Point(30, 30), HersheyFonts.HersheyComplex, 1.0, new Scalar(255, 0, 0), 3); //显示结果 pb_show.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(resultImg); tb_res.Text = GetResultString(results); Thread.Sleep(5); } capture.Release(); pb_show.Image = null; tssl_show.Text = "摄像头已停止!"; tsb_camera.Text = "打开摄像头"; }); } private void tsb_video_Click(object sender, EventArgs e) { if(tsb_video.Text=="选择视频") { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "视频文件(*.*)|*.mp4;*.avi"; if (ofd.ShowDialog() != DialogResult.OK) return; videoStart = true; VideoProcess(ofd.FileName); tsb_video.Text = "停止"; tssl_show.Text = "视频正在检测中..."; } else { videoStart = false; } } private void tsb_camera_Click(object sender, EventArgs e) { if (tsb_camera.Text == "打开摄像头") { videoStart = true; CameraProcess(0); tsb_camera.Text = "停止"; tssl_show.Text = "摄像头正在检测中..."; } else { videoStart = false; } } private void tsb_exit_Click(object sender, EventArgs e) { videoStart = false; this.Close(); } private void trackBar1_Scroll(object sender, EventArgs e) { numericUpDown1.Value = Convert.ToDecimal(trackBar1.Value / 100.0f); } private void trackBar2_Scroll(object sender, EventArgs e) { numericUpDown2.Value = Convert.ToDecimal(trackBar2.Value / 100.0f); } private void numericUpDown1_ValueChanged(object sender, EventArgs e) { trackBar1.Value = (int)(Convert.ToSingle(numericUpDown1.Value) * 100); } private void numericUpDown2_ValueChanged(object sender, EventArgs e) { trackBar2.Value = (int)(Convert.ToSingle(numericUpDown2.Value) * 100); } private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { tssl_show.Text="加载模型:"+comboBox1.Text; detetor.LoadWeights(weightsPath+"\\"+comboBox1.Text); tssl_show.Text = "模型加载已完成!"; } } }

【常用评估参数介绍】

在目标检测任务中,评估模型的性能是至关重要的。你提到的几个术语是评估模型性能的常用指标。下面是对这些术语的详细解释:

Class:
这通常指的是模型被设计用来检测的目标类别。例如,一个模型可能被训练来检测车辆、行人或动物等不同类别的对象。
Images:
表示验证集中的图片数量。验证集是用来评估模型性能的数据集,与训练集分开,以确保评估结果的公正性。
Instances:
在所有图片中目标对象的总数。这包括了所有类别对象的总和,例如,如果验证集包含100张图片,每张图片平均有5个目标对象,则Instances为500。
P(精确度Precision):
精确度是模型预测为正样本的实例中,真正为正样本的比例。计算公式为:Precision = TP / (TP + FP),其中TP表示真正例(True Positives),FP表示假正例(False Positives)。
R(召回率Recall):
召回率是所有真正的正样本中被模型正确预测为正样本的比例。计算公式为:Recall = TP / (TP + FN),其中FN表示假负例(False Negatives)。
mAP50:
表示在IoU(交并比)阈值为0.5时的平均精度(mean Average Precision)。IoU是衡量预测框和真实框重叠程度的指标。mAP是一个综合指标,考虑了精确度和召回率,用于评估模型在不同召回率水平上的性能。在IoU=0.5时,如果预测框与真实框的重叠程度达到或超过50%,则认为该预测是正确的。
mAP50-95:
表示在IoU从0.5到0.95(间隔0.05)的范围内,模型的平均精度。这是一个更严格的评估标准,要求预测框与真实框的重叠程度更高。在目标检测任务中,更高的IoU阈值意味着模型需要更准确地定位目标对象。mAP50-95的计算考虑了从宽松到严格的多个IoU阈值,因此能够更全面地评估模型的性能。
这些指标共同构成了评估目标检测模型性能的重要框架。通过比较不同模型在这些指标上的表现,可以判断哪个模型在实际应用中可能更有效。

【使用步骤】

使用步骤:
(1)首先根据官方框架ultralytics安装教程安装好yolov8环境,并根据官方export命令将自己pt模型转成onnx模型,然后去github仓库futureflsl/firc-csharp-projects找到源码
(2)使用vs2019打开sln项目,选择x64 release并且修改一些必要的参数,比如输入shape等,点击运行即可查看最后效果

特别注意如果运行报错了,请参考我的博文进行重新引用我源码的DLL:[C#]opencvsharp报错System.Memory,Version=4.0.1.2,Culture=neutral,PublicKeyToken=cc7b13fcd2ddd51“版本高于所引_未能加载文件或程序集“system.memory, version=4.0.1.2, culture-CSDN博客

【提供文件】

C#源码
yolov8n.onnx模型(不提供pytorch模型)
训练的map,P,R曲线图(在weights\results.png)
测试图片(在test_img文件夹下面)

特别注意这里提供训练数据集

http://www.cnnetsun.cn/news/60724.html

相关文章:

  • HTTP报错踩坑实录:4xx/5xx核心原因+Java项目解决方案(Javaer必藏)
  • 5个实战技巧让AI秒懂你的需求:思维链提示工程深度解析
  • 如何高效下载M3U8视频文件:完整指南与实用技巧
  • AI如何帮你高效拆分Python字符串?
  • GLM-4.5智能体大模型:重新定义AI生产力边界
  • 金融软件测试:严苛标准下的安全与性能挑战
  • 软件架构师的成长之路
  • 90亿参数逆袭:GLM-Z1-9B重新定义轻量级大模型性能边界
  • Rust GUI终极性能优化指南:编译时间缩短40%的完整配置方案
  • 3步搞定llama.cpp SYCL后端:让Intel GPU火力全开运行大模型
  • SGMICRO圣邦微 74LVC1G32XN5G/TR NA 逻辑门
  • Maxun元数据过滤终极指南:从入门到精通的全流程解析
  • Higress云原生网关Helm部署实战:企业级高效配置指南
  • DTIIA 5.0 输送机系统设计说明
  • JavaEE进阶——SpringBoot统一功能处理实战指南
  • leetcode 2110. 股票平滑下跌阶段的数目 中等
  • 15、智能平台管理接口驱动与直接内存访问技术解析
  • Ability Kit(程序框架服务)Stage模型
  • JVM内存结构与Java内存模型的区别
  • 认证加密算法选择困境:AES-GCM与ChaCha20-Poly1305的深度决策指南
  • 5分钟搞定NAS媒体库!nas-tools终极使用指南让你效率翻倍
  • GLM-4.5:重新定义智能体时代的成本效益比与工程化实践
  • yarn的容量调度器多队列
  • Spark的容错机制
  • M3u8下载终极指南:5分钟快速上手完整教程
  • Slint UI开发终极指南:2025从入门到精通的完整路径
  • 字节跳动UI-TARS重构GUI自动化:单模型架构超越GPT-4o,企业级应用提速300%
  • Qwen3-235B-A22B:双模式推理重塑2025企业AI效率标准
  • 万亿级MoE架构技术突破:Kimi-K2-Base如何重塑AI产业价值链
  • 30亿参数挑战720亿:CapRL-3B如何改写多模态模型游戏规则