【算法介紹】

基於YOLOv11的齒輪缺陷檢測系統,是針對齒輪製造與維護領域開發的高效自動化檢測工具。該系統依託YOLOv11目標檢測算法,利用其增強的特徵提取能力(如C3k2塊與C2PSA模塊)和優化的檢測頭設計,實現對齒輪表面缺陷的高精度識別,可精準定位“break(斷裂),lack(斷齒)與scratch(劃痕)等典型缺陷類型。

系統支持單張圖像、視頻流及實時攝像頭畫面檢測,滿足不同場景的檢測需求。數據集採用Pascal VOC與YOLO雙格式標註,涵蓋7000+張齒輪圖像,標註框總數超1.6w個,確保模型泛化能力。

系統界面基於PyQt5開發,提供直觀的操作體驗。該技術方案顯著提升了齒輪缺陷檢測效率,為製造業質量管控提供了可靠支持。

【效果展示】

[C#][winform]基於yolov11的齒輪缺陷檢測系統C#源碼+onnx模型+評估指標曲線+精美GUI界面_Text

[C#][winform]基於yolov11的齒輪缺陷檢測系統C#源碼+onnx模型+評估指標曲線+精美GUI界面_ide_02

【訓練數據集介紹】

數據集格式:Pascal VOC格式+YOLO格式(不包含分割路徑的txt文件,僅僅包含jpg圖片以及對應的VOC格式xml文件和yolo格式txt文件)

圖片數量(jpg文件個數):7742

標註數量(xml文件個數):7742

標註數量(txt文件個數):7742

標註類別數:3

標註類別名稱(注意yolo格式類別順序不和這個對應,而以labels文件夾classes.txt為準):["break","lack","scratch"]

每個類別標註的框數:

break 框數 = 2620

lack 框數 = 2568

scratch 框數 = 11045

總框數:16233

使用標註工具:labelImg

標註規則:對類別進行畫矩形框

重要説明:暫無

特別聲明:本數據集不對訓練的模型或者權重文件精度作任何保證,數據集只提供準確且合理標注

圖片預覽:

[C#][winform]基於yolov11的齒輪缺陷檢測系統C#源碼+onnx模型+評估指標曲線+精美GUI界面_Text_03

標註例子:

[C#][winform]基於yolov11的齒輪缺陷檢測系統C#源碼+onnx模型+評估指標曲線+精美GUI界面_System_04

【訓練信息】

參數


訓練集圖片數

7146

驗證集圖片數

596

訓練map

98.5%

訓練精度(Precision)

96.9%

訓練召回率(Recall)

98.4%

【驗證集精度統計】

Class

Images

Instances

P

R

mAP50

mAP50-95

all

596

1329

0.969

0.984

0.985

0.702

break

190

190

0.997

1

0.995

0.689

lack

186

186

0.997

1

0.995

0.747

scratch

220

953

0.913

0.951

0.966

0.67

【測試環境】

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

注意使用CPU推理,沒有使用cuda推理因此不需要電腦具有nvidia顯卡,無需安裝安裝cuda+dunn

【界面設計】

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 = "模型加載已完成!";
        }
    }
}

【常用評估參數介紹】

在目標檢測任務中,評估模型的性能是至關重要的。你提到的幾個術語是評估模型性能的常用指標。下面是對這些術語的詳細解釋:

  1. Class
  • 這通常指的是模型被設計用來檢測的目標類別。例如,一個模型可能被訓練來檢測車輛、行人或動物等不同類別的對象。
  1. Images
  • 表示驗證集中的圖片數量。驗證集是用來評估模型性能的數據集,與訓練集分開,以確保評估結果的公正性。
  1. Instances
  • 在所有圖片中目標對象的總數。這包括了所有類別對象的總和,例如,如果驗證集包含100張圖片,每張圖片平均有5個目標對象,則Instances為500。
  1. P(精確度Precision)
  • 精確度是模型預測為正樣本的實例中,真正為正樣本的比例。計算公式為:Precision = TP / (TP + FP),其中TP表示真正例(True Positives),FP表示假正例(False Positives)。
  1. R(召回率Recall)
  • 召回率是所有真正的正樣本中被模型正確預測為正樣本的比例。計算公式為:Recall = TP / (TP + FN),其中FN表示假負例(False Negatives)。
  1. mAP50
  • 表示在IoU(交併比)閾值為0.5時的平均精度(mean Average Precision)。IoU是衡量預測框和真實框重疊程度的指標。mAP是一個綜合指標,考慮了精確度和召回率,用於評估模型在不同召回率水平上的性能。在IoU=0.5時,如果預測框與真實框的重疊程度達到或超過50%,則認為該預測是正確的。
  1. mAP50-95
  • 表示在IoU從0.5到0.95(間隔0.05)的範圍內,模型的平均精度。這是一個更嚴格的評估標準,要求預測框與真實框的重疊程度更高。在目標檢測任務中,更高的IoU閾值意味着模型需要更準確地定位目標對象。mAP50-95的計算考慮了從寬鬆到嚴格的多個IoU閾值,因此能夠更全面地評估模型的性能。

這些指標共同構成了評估目標檢測模型性能的重要框架。通過比較不同模型在這些指標上的表現,可以判斷哪個模型在實際應用中可能更有效。

【使用步驟】

使用步驟: (1)首先根據官方框架ultralytics安裝教程安裝好yolov11環境,並根據官方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#源碼

yolo11n.onnx模型(提供pytorch模型)

訓練的map,P,R曲線圖(在weights\results.png)

測試圖片(在test_img文件夾下面)

特別注意這裏提供訓練數據集