第一部分:环境配置
1.1 创建虚拟环境
推荐使用 Anaconda 管理 Python 环境
conda create -n yolov5 python=3.8 conda activate yolov5注意:Python 版本要求 3.8 或更高。
1.2 安装 PyTorch
根据是否有 NVIDIA GPU 及 CUDA 版本选择对应命令
# CPU 版本 pip install torch torchvision torchaudio # GPU 版本(示例:CUDA 11.3) pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu113PyTorch 版本要求 >=1.8。
1.3 克隆 YOLOv5 仓库并安装依赖
git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt同时安装常用工具库:
pip install opencv-python matplotlib tqdm1.4 验证安装
python detect.py --weights yolov5s.pt --source data/images/zidane.jpg若能正常输出检测结果,则环境配置成功-
第二部分:数据集准备
2.1 数据集目录结构
YOLOv5 要求遵循以下标准目录结构
custom_dataset/ ├── images/ │ ├── train/ # 训练集图片 │ └── val/ # 验证集图片 └── labels/ ├── train/ # 训练集标注(.txt) └── val/ # 验证集标注(.txt)图片与标签文件需同名(如 img1.jpg 对应 img1.txt)
2.2 标注文件格式
每个.txt标注文件每行代表一个检测框,格式为
<class_id> <x_center> <y_center> <width> <height>所有坐标需归一化到 [0, 1] 区间。示例:
0 0.542 0.678 0.215 0.3322.3 标注工具推荐
• LabelImg:基础矩形框标注,适合简单场景-
• CVAT:支持多边形、关键点标注,适合复杂场景-
• Roboflow:自动标注 + 数据增强-
2.4 创建数据集配置文件
在 data/ 目录下创建 custom.yaml
train: ../custom_dataset/images/train val: ../custom_dataset/images/val nc: 3 # 类别数量 names: ['defect1', 'defect2', 'defect3'] # 类别名称第三部分:模型训练
3.1 选择模型规模
YOLOv5 提供五种规模模型:
| 模型 | 速度 | 特点 |
|---|---|---|
| YOLOv5n | 最快(1.4ms/img) | 纳米版,适合边缘设备 |
| YOLOv5s | 快(3.7ms/img) | 适合嵌入式设备 |
| YOLOv5m | 平衡(5.6ms/img) | 平衡型 |
| YOLOv5l | 高精度(7.8ms/img) | 高精度 |
| YOLOv5x | 最高精度(11.7ms/img) | 最高精度 |
3.2 启动训练
python train.py --img 640 --batch 16 --epochs 300 \ --data custom.yaml --weights yolov5s.pt \ --cfg models/yolov5s.yaml --name custom_model关键参数说明
显存不足时可减小 --batch-size
3.3 训练过程监控
使用 TensorBoard 可视化训练过程
tensorboard --logdir runs/train/exp
重点关注指标-
• box_loss:边界框回归损失
• obj_loss:目标存在性损失
• cls_loss:分类损失
• mAP@0.5:IoU=0.5 时的平均精度
训练完成后,模型权重保存在 runs/train/custom_model/weights/best.pt。
第四部分:模型导出(ONNX)
为了在 Qt 中部署,需要将 PyTorch 模型(.pt)转换为 ONNX 格式-
4.1 使用官方导出脚本
python models/export.py --weights runs/train/custom_model/weights/best.pt \ --include onnx --img 640 --batch 14.2 手动导出(备选方案)
import torch from models.experimental import attempt_load def convert_to_onnx(model_path, output_path, img_size=(640, 640), opset_version=12): model = attempt_load(model_path, map_location='cpu') model.eval() # 创建示例输入 img = torch.zeros(1, 3, *img_size) # 导出 ONNX torch.onnx.export( model, img, output_path, opset_version=opset_version, input_names=['images'], output_names=['output'] ) print(f"Model exported to {output_path}") convert_to_onnx('best.pt', 'best.onnx')ONNX opset 版本建议 ≥11
第五部分:集成到 Qt 缺陷检测程序
集成方式主要有两种:Python(PyQt5)方案 和 C++(Qt + ONNX Runtime)方案。
方案一:Python + PyQt5(推荐快速开发)
这是最直接的方式,适合快速构建原型-
5.1 环境准备
pip install PyQt5 onnxruntime opencv-python5.2 核心推理代码
import cv2 import onnxruntime as ort import numpy as np from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QFileDialog from PyQt5.QtGui import QPixmap, QImage from PyQt5.QtCore import Qt class YOLOv5Detector: def __init__(self, model_path): self.session = ort.InferenceSession(model_path) self.input_name = self.session.get_inputs()[0].name self.output_name = self.session.get_outputs()[0].name self.img_size = 640 def preprocess(self, img): # 调整大小并归一化 img = cv2.resize(img, (self.img_size, self.img_size)) img = img.transpose(2, 0, 1) # HWC -> CHW img = img.astype(np.float32) / 255.0 return np.expand_dims(img, axis=0) def detect(self, img): input_tensor = self.preprocess(img) outputs = self.session.run([self.output_name], {self.input_name: input_tensor}) # 后处理 NMS,提取检测框 return self.postprocess(outputs[0]) def postprocess(self, output): # 根据实际输出格式解析检测结果 # 返回: [(x1, y1, x2, y2, class_id, confidence), ...] pass5.3 PyQt5 界面集成
class DefectDetectionWindow(QMainWindow): def __init__(self): super().__init__() self.detector = YOLOv5Detector('best.onnx') self.initUI() def initUI(self): self.setWindowTitle('缺陷检测系统') self.setGeometry(100, 100, 800, 600) # 图像显示标签 self.image_label = QLabel(self) self.image_label.setAlignment(Qt.AlignCenter) self.image_label.setStyleSheet("border: 1px solid gray;") # 按钮 self.btn_open = QPushButton('打开图片', self) self.btn_open.clicked.connect(self.open_image) self.btn_detect = QPushButton('开始检测', self) self.btn_detect.clicked.connect(self.detect_image) # 布局(略) def open_image(self): file_path, _ = QFileDialog.getOpenFileName( self, '选择图片', '', 'Images (*.png *.jpg *.jpeg)') if file_path: self.current_image = cv2.imread(file_path) self.display_image(self.current_image) def detect_image(self): if hasattr(self, 'current_image'): results = self.detector.detect(self.current_image) # 在图像上绘制检测框 annotated = self.draw_boxes(self.current_image.copy(), results) self.display_image(annotated) def display_image(self, img): # cv2 图像转 QPixmap rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) h, w, ch = rgb.shape bytes_per_line = ch * w qt_img = QImage(rgb.data, w, h, bytes_per_line, QImage.Format_RGB888) pixmap = QPixmap.fromImage(qt_img).scaled( self.image_label.width(), self.image_label.height(), Qt.KeepAspectRatio, Qt.SmoothTransformation) self.image_label.setPixmap(pixmap)5.4 打包为独立可执行文件
pip install pyinstaller pyinstaller --onefile --windowed --add-data "best.onnx;." main.py参考项目:yolov5-onnx-pyqt-exe
https://github.com/hhx518/yolov5-onnx-pyqt-exe
方案二:C++ + Qt + ONNX Runtime(高性能生产级)
适合对性能要求较高的工业场景
5.5 C++ 环境搭建
安装 Qt:
• 推荐 Qt 5.15.2 LTS
• 勾选 MinGW 64-bit 或 MSVC 编译器
安装 ONNX Runtime:
• 从 GitHub releases 下载预编译包
• 或自行编译-
安装 OpenCV:
# Ubuntu sudo apt install libopencv-dev # Windows: 从官网下载预编译二进制文件5.6 Qt 项目配置(.pro 文件)
QT += core widgets gui CONFIG += c++17 INCLUDEPATH += /path/to/opencv/include \ /path/to/onnxruntime/include LIBS += -L/path/to/opencv/lib -lopencv_world450 \ -L/path/to/onnxruntime/lib -lonnxruntime SOURCES += main.cpp mainwindow.cpp detector.cpp HEADERS += mainwindow.h detector.h5.7 ONNX Runtime 推理代码(detector.h)
#ifndef DETECTOR_H #define DETECTOR_H #include <opencv2/opencv.hpp> #include <onnxruntime/core/session/onnxruntime_cxx_api.h> #include <vector> struct Detection { cv::Rect box; int class_id; float confidence; }; class YOLOv5Detector { public: YOLOv5Detector(const std::string& model_path); std::vector<Detection> detect(const cv::Mat& image); private: Ort::Session session; Ort::MemoryInfo memory_info; std::vector<int64_t> input_shape; int img_size = 640; cv::Mat preprocess(const cv::Mat& image); std::vector<Detection> postprocess(const std::vector<float>& output, float conf_threshold = 0.5, float nms_threshold = 0.4); }; #endif5.8 ONNX Runtime 推理代码(detector.cpp)
#include "detector.h" #include <onnxruntime/core/providers/cpu/cpu_provider_factory.h> YOLOv5Detector::YOLOv5Detector(const std::string& model_path) : memory_info(Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault)) { Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "YOLOv5"); Ort::SessionOptions session_options; session_options.SetIntraOpNumThreads(1); // 使用 CPU 推理(可改为 CUDA) session_options.AppendExecutionProvider_CPU(0); session = Ort::Session(env, model_path.c_str(), session_options); // 获取输入形状 auto input_info = session.GetInputTypeInfo(0); auto input_tensor_info = input_info.GetTensorTypeAndShapeInfo(); input_shape = input_tensor_info.GetShape(); } cv::Mat YOLOv5Detector::preprocess(const cv::Mat& image) { cv::Mat resized; cv::resize(image, resized, cv::Size(img_size, img_size)); resized.convertTo(resized, CV_32FC3, 1.0 / 255.0); // HWC -> CHW cv::Mat channels[3]; cv::split(resized, channels); cv::Mat chw; cv::vconcat(channels[0], channels[1], chw); cv::vconcat(chw, channels[2], chw); return chw; } std::vector<Detection> YOLOv5Detector::detect(const cv::Mat& image) { cv::Mat input_tensor = preprocess(image); // 准备输入 std::vector<int64_t> input_shape = {1, 3, img_size, img_size}; Ort::Value input_tensor_ort = Ort::Value::CreateTensor<float>( memory_info, (float*)input_tensor.data, input_tensor.total() * input_tensor.elemSize(), input_shape.data(), input_shape.size() ); // 推理 auto output_tensors = session.Run( Ort::RunOptions{nullptr}, {"images"}, &input_tensor_ort, 1, {"output"}, 1 ); // 获取输出 float* output_data = output_tensors[0].GetTensorMutableData<float>(); auto output_shape = output_tensors[0].GetTensorTypeAndShapeInfo().GetShape(); size_t output_size = output_shape[1] * output_shape[2]; std::vector<float> output(output_data, output_data + output_size); // 后处理(NMS) return postprocess(output); }5.9 Qt 主窗口集成
// mainwindow.h class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void onOpenImage(); void onDetect(); private: Ui::MainWindow *ui; YOLOv5Detector* detector; cv::Mat current_image; QImage cvMatToQImage(const cv::Mat& mat); void displayImage(const cv::Mat& image); }; // mainwindow.cpp void MainWindow::onDetect() { if (current_image.empty()) return; auto detections = detector->detect(current_image); cv::Mat result = current_image.clone(); for (const auto& det : detections) { cv::rectangle(result, det.box, cv::Scalar(0, 255, 0), 2); std::string label = "Defect: " + std::to_string(det.class_id) + " " + std::to_string(det.confidence); cv::putText(result, label, cv::Point(det.box.x, det.box.y - 5), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0), 2); } displayImage(result); } QImage MainWindow::cvMatToQImage(const cv::Mat& mat) { cv::Mat rgb; cv::cvtColor(mat, rgb, cv::COLOR_BGR2RGB); return QImage(rgb.data, rgb.cols, rgb.rows, rgb.step, QImage::Format_RGB888); } void MainWindow::displayImage(const cv::Mat& image) { QImage qimg = cvMatToQImage(image); QPixmap pixmap = QPixmap::fromImage(qimg); ui->imageLabel->setPixmap(pixmap.scaled(ui->imageLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); }第六部分:性能优化建议
GPU 推理:若硬件支持,将模型加载到 GPU 上推理
多线程处理:使用 QThread 将检测放在子线程,避免界面卡顿
图像预处理优化:减少不必要的图像处理步骤
批量推理:多张图片同时处理时使用 batch 推理
总结流程图
环境配置(Python 3.8 + PyTorch + YOLOv5) ↓ 准备数据集(images/ + labels/ + custom.yaml) ↓ 模型训练(python train.py ...) ↓ 模型导出(.pt → .onnx) ↓ ┌────┴────┐ ↓ ↓ PyQt5方案 C++方案 (Python) (Qt+ONNXRuntime) ↓ ↓ 打包部署 编译部署以上步骤涵盖了从环境搭建、数据集准备、模型训练到 Qt 集成的完整流程。根据实际需求选择 Python(PyQt5)或 C++(Qt + ONNX Runtime)方案即可。