尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

YOLOv8+PySide6花卉识别检测系统实战:从训练到部署

YOLOv8+PySide6花卉识别检测系统实战:从训练到部署 之前在做可视化相关的算法项目时经常遇到一个尴尬的情况模型训练好了指标也不错但交付给非技术同学演示时还是得靠命令行跑推理既不直观也很难把“检测结果”讲清楚。后来尝试了 YOLOv8/YOLOv5 与 PySide6 的组合才把“算法训练 → 模型推理 → 桌面端展示”这条链路完整打通。这篇文章就从零开始带大家实现一个基于深度学习 YOLOv8/YOLOv5 与 PySide6 的花卉识别鲜花检测系统覆盖数据集准备、模型训练、模型导出、界面开发、推理部署全流程。无论你是刚接触深度学习目标检测的初学者还是想快速搭建一个桌面工具交付给项目使用的开发者本文都能提供一套可复用的实操方案。1. 背景与核心概念为什么选择 YOLO PySide61.1 花卉识别检测系统能做什么花卉识别本质上是一个目标检测任务。目标检测不仅要回答“图片里有没有花”还要回答“花在哪里、是什么品种、有几朵”。和图像分类相比目标检测的输出多了一个边界框Bounding Box需要在图片上把每一朵花的位置框出来并打上对应的类别标签。常见的应用场景包括植物科普 App用户拍一张照片自动识别花卉品种并展示百科信息。园林养护监测利用巡检机器人或固定摄像头对园区花卉进行识别和数量统计。智慧农业统计大棚或基地内不同花卉的分布情况辅助花期管理。图文检索与内容审核对大量图片进行自动标注建立花卉图库索引。从技术角度看这些场景的核心环节是一致的训练一个目标检测模型再用一套可视化界面把模型能力交付给使用者。1.2 YOLOv8 与 YOLOv5 怎么选YOLO 系列在目标检测领域是一个绕不开的名字。从 YOLOv5 到 YOLOv8再到后来的 YOLO11整个系列一直在迭代。YOLOv5 是流传度最高、资料最全的一代。它结构稳定部署生态成熟很多旧的训练权重和教程都围绕它展开。如果你的硬件比较老或者你需要参考大量网上现成经验YOLOv5 会是一个保险的选择。YOLOv8 是目前更推荐起步的版本。它延续了 YOLO 系列的“单阶段检测”思路同时引入了 Anchor-Free无锚框检测头、C2f 模块、以及更丰富的训练策略。相比 YOLOv5YOLOv8 在相同体量下通常有更好的精度和更稳的训练表现而且官方的 ultralytics 库把训练、验证、导出、推理全部封装好了代码量非常少。实际项目中建议优先尝试 YOLOv8。如果遇到特别依赖 YOLOv5 预训练权重的场景再切回 YOLOv5 也不迟。本文的训练代码和 PySide6 推理代码主要基于 YOLOv8但核心流程同样适用于 YOLOv5切换成本主要在模型文件路径和部分 API 名称上。1.3 PySide6 在系统中的角色PySide6 是 Qt 6 的 Python 官方绑定库可以用来开发跨平台桌面应用。相比 Tkinter它的控件更现代界面更美观相比 C 版 Qt它又保持了 Python 的开发效率。在花卉识别系统中PySide6 负责接收用户选择的图片或打开摄像头视频流调用 YOLO 模型进行推理把检测结果边界框、类别、置信度绘制到画面上展示检测数量、类别统计等辅助信息提供开始、停止、保存结果等交互按钮。简单说YOLO 负责“看懂图像”PySide6 负责“让用户看得懂结果”。2. 环境准备与版本说明2.1 硬件与系统要求本文示例以 Windows 11 系统为主兼容 Windows 10 / Ubuntu 20.04 等常见环境。硬件方面模型训练阶段最好有一块 NVIDIA 显卡显存建议 6GB 以上。GTX 1660 Ti、RTX 3060 这类显卡都可以跑 YOLOv8s 或 YOLOv8n 的训练只是训练速度和 batch size 需要相应调整。如果只有 CPU也可以训练但速度会慢很多建议直接使用官方预训练权重做迁移学习并选择最小的模型版本。推理阶段对硬件要求低很多普通的办公电脑 CPU 也能运行只是帧率会受影响。如果使用摄像头实时检测建议至少拥有一块入门级独显或者降低输入分辨率来保证流畅度。2.2 Python 环境与依赖安装Python 版本建议使用 3.8 至 3.11 之间。PySide6 和最新版 ultralytics 对 Python 版本有一定要求过旧的版本容易出现依赖冲突。创建独立的虚拟环境是一个好习惯避免和系统 Python 环境互相污染。conda create -n flower_yolo python3.10 -y conda activate flower_yolo接下来安装 PyTorch。如果你的机器有 NVIDIA 显卡建议到 PyTorch 官网选择对应的 CUDA 版本安装命令。CPU 版本安装更简单pip install torch torchvision然后安装目标检测框架 ultralyticspip install ultralytics安装桌面开发框架 PySide6pip install PySide6为了方便图像处理再安装 OpenCV。注意 ultralytics 本身会依赖 opencv-python但我们可以显式安装一遍确保版本可用pip install opencv-python最后准备标注工具 labelImgpip install labelImg安装完成后可以用一段小代码验证环境import torch from ultralytics import YOLO import PySide6 print(PyTorch:, torch.__version__) print(CUDA available:, torch.cuda.is_available()) print(PySide6:, PySide6.__version__)如果输出中CUDA available为True说明 GPU 环境可正常使用。3. YOLOv8 目标检测原理速览3.1 网络结构核心组成YOLOv8 的网络结构可以拆成三部分Backbone主干网络、Neck颈部特征融合、Head检测头。Backbone 负责从输入图像中提取多尺度特征。YOLOv8 使用的 C2f 模块借鉴了跨阶段局部连接的思想把不同层的特征图进行更丰富的融合。相比 YOLOv5 的 C3 模块C2f 在保持轻量化的同时提升了梯度传递效率。Neck 部分负责特征金字塔融合把主干网络不同尺度的输出进行上采样、拼接等操作让模型同时具备检测大目标和小目标的能力。Head 是输出部分。YOLOv8 采用了 Anchor-Free 结构不再像 YOLOv5 那样需要预设若干锚框而是直接预测目标中心点和边界框尺寸。这样减少了超参数调优的麻烦也让模型在不同数据集上的迁移更顺畅。3.2 训练策略与损失函数YOLOv8 在训练时使用了多种数据增强策略包括马赛克增强Mosaic、随机仿射变换、HSV 色彩空间增强等。马赛克增强会把 4 张训练图片拼接成一张让模型在小目标检测和复杂背景下的鲁棒性更好。损失函数方面YOLOv8 分类分支使用 BCE Loss回归分支使用 Distribution Focal Loss 和 CIoU Loss 的组合。简单理解就是模型不仅要知道“目标在哪里”还要对边界框的位置偏差有更精细的惩罚最终框得更准。实际训练中我们需要关注的主要指标有box_loss边界框回归损失越小越好。cls_loss分类损失越小越好。dfl_loss分布聚焦损失越小越好。mAP50IoU 阈值为 0.5 时的平均精度。mAP50-95IoU 阈值从 0.5 到 0.95 的平均精度更加严格。3.3 增量训练与迁移学习迁移学习是深度学习落地项目中非常实用的套路。我们通常不从头随机初始化权重而是加载 YOLOv8 在 COCO 数据集上预训练好的权重在此基础上使用自己的花卉数据集继续训练。这样做的好处非常明显预训练模型已经学会了通用的边缘、纹理、形状等特征我们只需要在它的基础上微调就能用更少的样本、更短的时间达到不错的效果。这种“在已有模型基础上继续训练”的方式本质上就是一种增量训练。当后续采集到新的花卉类别时也可以基于当前权重继续训练模型会保留旧的识别能力同时学习新的类别。在 ultralytics 中只需要在训练命令中指定modelyolov8n.pt代码就会自动下载预训练权重并在此基础上训练yolo detect train dataflower.yaml modelyolov8n.pt epochs100 imgsz640 batch164. 数据集准备与标注4.1 数据从哪里来做花卉识别首先需要准备带标注的花卉图片数据。有两条常见路径使用公开数据集。网络上存在不少花卉分类和目标检测数据集比如 Oxford 102 Flower 数据集等。不过公开数据集通常面向分类任务目标检测格式的数据需要自己转换或寻找社区整理好的版本。自己采集并标注。这是最贴近实际项目需求的方式。用手机或相机拍摄不同角度、不同光照、不同背景的花卉图片数量越多、场景越多样模型泛化能力越好。本文以自建数据集为例建议每个类别准备 200 张以上图片。如果某些类别样本较少可以优先选择 YOLOv8n 这样的小模型配合迁移学习也能获得可接受的效果。4.2 数据标注的规范训练目标检测模型必须把每张图片中所有目标都标注出来。也就是说如果一张图里有 5 朵花就必须把 5 朵花全部框出来。漏标会让模型学习到错误信息对训练影响很大。使用 labelImg 工具标注时选择“PascalVOC”格式或“YOLO”格式均可。为了减少后续转换步骤建议直接保存为 YOLO 格式。YOLO 标注格式的每个 txt 文件中每行代表一个目标class_id x_center y_center width height注意这里的x_center、y_center、width、height都除以了图片宽高做了归一化。例如一个目标框中心点位于图片正中央宽高占图片的一半那么标注行就是0 0.5 0.5 0.5 0.54.3 数据集目录结构与 YAML 配置放好训练图片和标注文件后整体目录结构如下flower_data/ ├── images/ │ ├── train/ │ │ ├── flower_001.jpg │ │ └── ... │ └── val/ │ ├── flower_val_001.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── flower_001.txt │ │ └── ... │ └── val/ │ ├── flower_val_001.txt │ └── ... └── flower.yaml数据集配置flower.yaml是关键文件它告诉 YOLO 数据在哪里、有哪些类别# 数据集配置文件 flower.yaml path: D:/flower_data # 数据集根目录建议写绝对路径 train: images/train # 训练图片目录 val: images/val # 验证图片目录 # 类别名称 names: 0: rose 1: tulip 2: sunflower 3: daisy注意类别顺序要和标注文件中的 class_id 一一对应。如果标注时 class_id 是从 0 开始的这里也必须从 0 开始写。5. 模型训练与评估5.1 训练命令与关键参数环境准备妥当、数据集目录没问题之后就可以开始训练了。使用下面的命令启动训练yolo detect train dataflower.yaml modelyolov8n.pt epochs150 imgsz640 batch16 device0参数说明data指定数据集配置文件路径。model指定预训练权重。yolov8n.pt是 nano 版本速度最快精度更高可以用yolov8s.pt。epochs训练轮数。数据集较小时 100 到 200 轮足够了训练轮数过多反而可能过拟合。imgsz输入图片尺寸通常使用 640。batch批大小需要根据显存调整。如果显存不足可以调小到 8 或 4。device0表示使用第一块 GPUCPU 可以写cpu。训练开始后终端会输出每一轮的损失和精度指标。训练过程中ultralytics 会在runs/detect/train目录下保存权重和图表。5.2 训练结果图表怎么看训练结束后你会得到一个runs/detect/train目录。里面有 F1_curve.png、PR_curve.png、confusion_matrix.png 等图表。PR_curve 是 Precision-Recall 曲线。曲线下面积越大说明模型在不同置信度阈值下都能保持较好的精度和召回率。confusion_matrix 则展示了每个类别的预测情况如果出现大面积“把 A 类预测成 B 类”的情况说明两类特征太接近需要补充更多区分性样本。loss_curve 图展示了训练集和验证集的损失下降趋势。验证集损失如果先降后升说明模型过拟合了可以增加数据增强、减少训练轮数或者使用早停策略。5.3 最佳权重选择与模型导出训练完成后runs/detect/train/weights/目录下会有两个权重文件best.pt验证集上表现最好的权重。last.pt最后一轮保存的权重。后续部署使用best.pt。为了后续在 PySide6 程序中更稳定地加载和推理一般不需要额外导出为 ONNX直接使用.pt文件即可。如果需要在没有 PyTorch 的环境中部署或者要与其它引擎集成可以导出为 ONNXyolo export modelruns/detect/train/weights/best.pt formatonnx6. 基于 PySide6 的检测界面开发6.1 界面功能拆解桌面应用的核心目标是把模型推理能力包装成一个好用的工具。我们设计的界面需要具备以下功能选择本地图片点击识别后展示检测结果。打开摄像头或视频文件进行实时检测。在图像区域绘制边界框、类别标签和置信度。显示检测类别数量和统计信息。提供停止检测、清空结果等操作。界面布局采用左控制栏 右展示区的结构。左边放按钮和参数输入右边放图像显示区域。6.2 项目目录结构整个 PySide6 项目结构如下flower_detector/ ├── app.py # 程序入口 ├── main_window.py # 主窗口界面 ├── detection_thread.py # 推理线程 ├── models/ │ └── best.pt # 训练好的模型权重 └── requirements.txt6.3 编写主窗口界面首先编写主窗口。这里需要注意PySide6 的 UI 代码全部用 Python 编写不需要单独安装 Qt Designer当然如果你习惯可视化拖拽设计也可以用 Designer 生成.ui文件再转换。main_window.py的核心代码如下# 文件路径main_window.py import cv2 import numpy as np from PySide6.QtWidgets import ( QMainWindow, QWidget, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QGroupBox, QTextEdit, QFileDialog, QMessageBox ) from PySide6.QtCore import Qt, QTimer from PySide6.QtGui import QImage, QPixmap from detection_thread import DetectionThread class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(花卉识别检测系统 - YOLOv8 PySide6) self.resize(1200, 700) self.model_path models/best.pt self.detect_thread None self.video_thread None self._init_ui() def _init_ui(self): # 主控件 central_widget QWidget() self.setCentralWidget(central_widget) # 水平总布局 main_layout QHBoxLayout(central_widget) # 左侧控制面板 left_panel QWidget() left_layout QVBoxLayout(left_panel) left_layout.setContentsMargins(15, 15, 15, 15) left_layout.setSpacing(12) # 模型状态标签 self.model_status_label QLabel(模型未加载) self.model_status_label.setStyleSheet(color: #888;) left_layout.addWidget(self.model_status_label) # 图片识别按钮 self.btn_image QPushButton(选择图片) self.btn_image.clicked.connect(self.select_image) left_layout.addWidget(self.btn_image) # 摄像头识别按钮 self.btn_camera QPushButton(打开摄像头检测) self.btn_camera.clicked.connect(self.open_camera) left_layout.addWidget(self.btn_camera) # 停止按钮 self.btn_stop QPushButton(停止检测) self.btn_stop.clicked.connect(self.stop_detection) self.btn_stop.setEnabled(False) left_layout.addWidget(self.btn_stop) # 识别结果文本框 self.result_text QTextEdit() self.result_text.setPlaceholderText(识别统计信息会在这里显示...) self.result_text.setReadOnly(True) left_layout.addWidget(self.result_text) # 右侧显示区 self.image_label QLabel(请选择图片或打开摄像头) self.image_label.setAlignment(Qt.AlignCenter) self.image_label.setMinimumSize(800, 600) self.image_label.setStyleSheet(border: 1px solid #ccc; background: #f8f8f8;) main_layout.addWidget(left_panel, 1) main_layout.addWidget(self.image_label, 4)6.4 编写检测线程实时检测最怕的是界面卡死。如果在主线程中直接调用模型推理每一帧的推理过程都会阻塞界面刷新用户体验非常差。解决办法是把检测放到 QThread 子线程中通过信号把结果回传到主线程。detection_thread.py代码如下# 文件路径detection_thread.py from PySide6.QtCore import QThread, Signal import cv2 import numpy as np from ultralytics import YOLO class DetectionThread(QThread): 视频/摄像头检测线程 frame_ready Signal(object) # 传回绘制好的图像 detection_info Signal(str) # 传回识别统计信息 thread_finished Signal() def __init__(self, model_path, source0, conf_thres0.25, parentNone): super().__init__(parent) self.model_path model_path self.source source self.conf_thres conf_thres self.model None self._running True def run(self): # 在子线程中加载模型避免阻塞主界面 self.model YOLO(self.model_path) cap cv2.VideoCapture(self.source) if not cap.isOpened(): self.detection_info.emit(无法打开视频源) return while self._running: ret, frame cap.read() if not ret: break # 调用模型推理 results self.model(frame, confself.conf_thres, verboseFalse) # 绘制检测框 annotated_frame results[0].plot() # 统计类别信息 names results[0].names boxes results[0].boxes cls_list boxes.cls.cpu().numpy() if boxes is not None else [] count_map {} for cls_id in cls_list: cls_name names[int(cls_id)] count_map[cls_name] count_map.get(cls_name, 0) 1 info 识别统计\n if count_map: for name, cnt in count_map.items(): info f{name}: {cnt}\n else: info 未检测到目标\n self.frame_ready.emit(annotated_frame) self.detection_info.emit(info) cap.release() self.thread_finished.emit() def stop(self): self._running False使用results[0].plot()ultralytics 会自动在图像上绘制边界框、标签和置信度省去手动绘制的过程。6.5 图片识别与界面显示逻辑回到main_window.py补充图片识别、摄像头启停和图像显示方法。# 在 MainWindow 类中继续添加方法 def update_image(self, cv_img): 把 OpenCV 的 BGR 图像转换为 QPixmap 并显示 rgb_img cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB) h, w, ch rgb_img.shape bytes_per_line ch * w qimg QImage(rgb_img.data, w, h, bytes_per_line, QImage.Format_RGB888) pixmap QPixmap.fromImage(qimg) # 自适应缩放显示 scaled_pixmap pixmap.scaled( self.image_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.image_label.setPixmap(scaled_pixmap) def select_image(self): 选择图片并进行识别 file_path, _ QFileDialog.getOpenFileName( self, 选择图片, , 图片文件 (*.jpg *.jpeg *.png *.bmp) ) if not file_path: return self.btn_image.setEnabled(False) self.result_text.append(f正在识别图片{file_path}) # 加载模型并推理 from ultralytics import YOLO model YOLO(self.model_path) results model(file_path, conf0.25) annotated_frame results[0].plot() # 更新显示 self.update_image(annotated_frame) # 统计结果 names results[0].names boxes results[0].boxes cls_list boxes.cls.cpu().numpy() if boxes is not None else [] count_map {} for cls_id in cls_list: cls_name names[int(cls_id)] count_map[cls_name] count_map.get(cls_name, 0) 1 info 识别结果\n if count_map: for name, cnt in count_map.items(): info f{name}: {cnt}\n else: info 未检测到目标\n self.result_text.append(info) self.btn_image.setEnabled(True) def open_camera(self): 打开摄像头实时检测 if self.detect_thread is not None and self.detect_thread.isRunning(): return self.detect_thread DetectionThread( model_pathself.model_path, source0, # 0 表示默认摄像头 conf_thres0.25 ) self.detect_thread.frame_ready.connect(self.update_image) self.detect_thread.detection_info.connect(self.result_text.clear) self.detect_thread.detection_info.connect(self.result_text.append) self.detect_thread.thread_finished.connect(self.on_thread_finished) self.btn_camera.setEnabled(False) self.btn_stop.setEnabled(True) self.detect_thread.start() def stop_detection(self): 停止实时检测 if self.detect_thread is not None: self.detect_thread.stop() def on_thread_finished(self): self.btn_camera.setEnabled(True) self.btn_stop.setEnabled(False) self.result_text.append(检测线程已停止)6.6 程序入口最后写app.py启动整个应用。# 文件路径app.py import sys from PySide6.QtWidgets import QApplication from main_window import MainWindow def main(): app QApplication(sys.argv) window MainWindow() window.show() sys.exit(app.exec()) if __name__ __main__: main()在终端运行python app.py界面启动后点击“选择图片”即可测试单张图片识别点击“打开摄像头检测”则进入实时检测模式。需要注意模型初次加载需要几秒到十几秒时间加载完成后界面才会响应后续操作。7. 常见问题与排查思路7.1 训练阶段常见问题问题现象常见原因解决思路训练时显存不足 OOMbatch size 过大输入尺寸过大调小 batch例如从 16 调到 8 或 4模型不收敛损失不下降数据标注错乱、学习率不合适检查标注类别和标签箱适当降低学习率验证集 mAP 很低数据量太少、类别不平衡增加样本使用马赛克增强或尝试迁移学习训练速度极慢未使用 GPU或者 CPU 线程没吃满检查 device 设置CPU 训练时启用多线程7.2 PySide6 界面常见问题问题现象常见原因解决思路点击按钮后界面卡死推理放在主线程中执行把模型推理封装到 QThread 子线程中摄像头画面不显示摄像头被占用或权限不足关闭其它占用摄像头的软件检查系统权限识别结果没有绘制框置信度阈值设置太高调低 conf_thres例如从 0.5 降到 0.25PySide6 程序打包后运行报错缺少必要的动态链接库使用 PyInstaller 时添加隐藏依赖或改用 conda 环境打包7.3 排查路径建议遇到问题时建议按照下面的顺序排查先看数据。用yolo predict或者可视化工具随机抽几张训练图片检查标注框是否正确。再看训练日志。损失是否下降、PR 曲线是否正常。接着看推理。单独执行一段 Python 脚本调用模型排除界面层干扰。最后看界面。检查信号与槽的连接是否正确、线程是否正常退出。8. 最佳实践与工程建议8.1 数据层面花卉数据容易受到季节、光线和拍摄角度的影响。在采集数据时尽量保证每个类别在不同环境下的样本都有覆盖。如果样本数量少可以通过数据增强来扩充包括旋转、翻转、亮度调整、裁剪等。标注时务必做到“应标尽标”。如果画面中有一朵花不清晰宁可把整张图删掉也不要漏标。漏标会让模型把该目标当作背景学习严重影响检测效果。8.2 模型训练层面从最小模型开始实验。先用 YOLOv8n 或 YOLOv8s 快速跑通流程确认数据和代码都没有问题再尝试更大的模型。大模型不一定总是更好在数据量有限时小模型反而更不容易过拟合。训练轮数和精度并不是越多越好。常规做法是设置一个相对大的 epochs然后开启早停机制。ultralytics 默认开启了早停patience 参数当验证集指标连续多轮不提升时训练会自动终止这样既节省时间又避免过拟合。8.3 界面工程层面桌面应用的“不卡顿”是底线。在 PySide6 中凡是耗时的任务都应该放到子线程中包括模型加载、视频推流读取、模型推理和结果绘制。另外模型加载通常会消耗较长时间如果每次点击识别都重新加载体验会很差。更合理的做法是程序启动后异步加载模型加载完成后把模型实例保存下来后续识别复用同一个实例。摄像头的实时检测可以考虑在子线程中做帧丢弃。如果摄像头帧率较高但模型推理速度跟不上线程会不断堆积帧导致延迟越来越大。可以在循环中加入time.sleep或者在读取新帧前丢弃旧帧。8.4 安全与合规如果你要部署到生产环境注意选择正规渠道获取的数据集避免使用来源不明的图片数据。涉及商业化用途时要确认数据集的授权协议是否允许商用。模型本身没有太强的安全风险但如果在园区监控等场景使用注意不要未经许可采集人员或车辆等敏感信息。在正式项目落地前建议先在测试环境完成全流程验证保存好原始标注数据和训练配置便于后续复现和审计。9. 总结与后续学习方向目前我们已经跑通了一个完整的“YOLOv8 PySide6 花卉识别检测系统”从环境搭建、数据标注、模型训练到桌面应用开发、实时推理展示每一步都有对应的代码和说明。你现在可以把训练好的best.pt换到models/目录下然后在自己的项目里复用这套界面和推理逻辑。如果你希望继续深入有以下几个可以发力的方向模型轻量化使用 TensorRT 或 ONNX Runtime 加速推理把检测帧率再拉高。多目标跟踪在实时检测基础上加入 ByteTrack 或 BoT-SORT不仅可以检测花朵还能持续跟踪每一朵花。增量训练当需要增加新品种花时只需在原有权重上补充新数据继续训练避免从零开始。移动端部署模型导出为 NCNN 或 TFLite 格式把系统移植到 Android 或嵌入式设备上。界面扩展增加历史记录、批量识别、导出统计报表等功能把工具打磨成完整的桌面产品。深度学习模型迭代得很快但核心思路和方法是共通的数据决定上限模型逼近上限工程决定能否交付。希望这篇文章能帮你把整个链路打通在实际项目中少踩几个坑。如果本文对你有帮助可以收藏备用后续继续交流目标检测与桌面应用开发实战经验。
返回列表