资讯详情

舰船检测全链路实战:YOLOv5训练与PyQt界面部署

📅 2026/9/27 3:12:42 | 华诺云谱 👁 阅读
舰船检测全链路实战:YOLOv5训练与PyQt界面部署
简介本资源面向计算机视觉学习者与舰船检测应用开发者提供一套基于YOLOv5的完整舰船检测方案涵盖训练好的多类别检测权重、PR曲线与loss曲线等训练过程记录mAP可达90%以上并附带数千张标注好的船只检测数据集标签同时提供txt与xml两种格式覆盖舰艇、游轮、帆船、军舰等多个类别。资源包共159个文件以py与pyc代码、yaml配置、jpg与png图像、pt权重、ui界面文件及xml标注为主压缩包约769.62MB采用PyTorch框架可与YOLOv5共用环境配置完成后即可加载模型直接测试。配套PyQt界面支持检测图片、视频及调用摄像头并提供相应选择项便于快速验证效果。目前已有1013人学习下载适合希望快速上手舰船检测、复用数据集与权重进行二次开发或课程实践的用户参考。1. 从几千张标注图到 PyQt 界面舰船检测这条链路到底怎么跑通舰船检测这件事真正卡住人的从来不是 YOLOv5 本身而是三件事凑不齐一份标注质量过关的船只检测数据集、一套能复现的训练配置、一个能让非算法同事直接点开就用的 PyQt 界面。标题里说的「几千张标注好的船只检测数据集 YOLOv5 各种类型舰船检测 PyQt 界面」本质是一条完整的落地链路——数据进来模型出去界面兜底。它适合两类人一类是手里已经有一批航拍或遥感舰船图、想快速验证检测可行性的人另一类是做完模型发现没人会用、需要补一个桌面端交互入口的人。我做过几轮类似的船检项目最深的体会是模型精度到 0.85 之后剩下的时间基本都花在数据清洗和界面联调上而不是调网络结构。这一章先把整条链路的边界讲清楚后面几章拆开讲数据、训练、界面和踩坑。2. 舰船数据集怎么选、怎么洗、怎么转成 YOLOv5 能吃的格式数据集是这条链路的地基。几千张标注图听起来不少但如果类别分布畸形、框贴边、小目标密集训出来的模型在真实场景里会集体翻车。舰船检测的数据来源常见有几类遥感/卫星影像切片、无人机航拍、港口监控截图。不同来源的目标尺度差异极大卫星图里一条船可能只有十几个像素航拍图里能占半张图。选数据集之前先想清楚你的部署场景是近景还是远景别拿遥感数据训一个要跑在码头摄像头上的模型。2.1 舰船类别的划分粒度别一上来就分十几类很多公开船只数据集会把船分成航母、驱逐舰、护卫舰、补给舰、渔船、货轮、油轮、游艇等一大堆细类。我的建议是第一版模型只分 2 到 4 类。原因是细类之间的视觉差异在低分辨率下几乎不可分标注一致性也差——同一条船不同标注员可能标成不同类模型学到的就是噪声。一个务实的划分方式是按尺度 场景分划分方案类别适用场景标注难度二分类ship / 背景只关心有没有船低三分类大型舰船 / 小型船只 / 背景港口监控、航道管理中四分类军舰 / 货轮 / 渔船 / 小艇需要粗粒度区分用途中高细粒度十余种舰型情报级识别高需专家标注新手直接上细粒度大概率得到一个每类 AP 都不到 0.5 的模型。先把二分类或三分类跑通再考虑加类。2.2 标注格式转换VOC / COCO 转 YOLO 的脚本与四个边界坑舰船数据集常见的标注格式是 Pascal VOC 的 XML 或 COCO 的 JSONYOLOv5 要的是每张图一个.txt每行class_id cx cy w h且坐标是归一化到 0~1 的。下面这个脚本处理 VOC 转 YOLO我把它当成标准模板用import os import xml.etree.ElementTree as ET # 类别映射按你的数据集实际类别改顺序决定 class_id CLASSES [warship, cargo, fishing, boat] def convert_voc_to_yolo(xml_dir, img_dir, out_dir): os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() # 图片尺寸从 XML 的 size 节点取别用 PIL 再读一遍省 IO size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in CLASSES: continue # 未定义类别直接丢弃避免 class_id 越界 cls_id CLASSES.index(name) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 边界裁剪标注越界是舰船数据集的高频问题 xmin max(0, min(xmin, w)) xmax max(0, min(xmax, w)) ymin max(0, min(ymin, h)) ymax max(0, min(ymax, h)) if xmax - xmin 2 or ymax - ymin 2: continue # 过滤掉宽高小于 2 像素的废框 cx (xmin xmax) / 2.0 / w cy (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) if lines: txt_name os.path.splitext(xml_file)[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines)) convert_voc_to_yolo(./annotations, ./images, ./labels)逻辑说明脚本遍历 XML按CLASSES列表把类别名映射成整数 id坐标做归一化。四个边界坑分别是——类别越界数据集里有你没定义的类必须丢弃而不是硬塞、坐标越界标注框超出图片范围不裁剪会导致归一化后出现负数或大于 1 的值训练时 loss 直接 NaN、废框宽高过小的框是标注噪声留着只会拉低精度、空标签文件一张图里所有框都被过滤后不要生成空 txt否则 YOLOv5 会把它当负样本但实际它可能只是标注漏了。参数上CLASSES的顺序必须和后面训练时data.yaml里的names完全一致错一位整个模型就废了。归一化保留 6 位小数足够YOLOv5 内部会再处理。2.3 数据集划分与 data.yaml8:1:1 不是铁律划分训练/验证/测试集时舰船数据有个特殊点同一片海域、同一时段的连续帧高度相似。如果随机划分验证集里会出现和训练集几乎一样的图指标虚高。正确做法是按场景或按航次划分让验证集来自训练时没见过的海域。data.yaml的写法path: /home/user/ship_dataset train: images/train val: images/val test: images/test nc: 4 names: [warship, cargo, fishing, boat]nc是类别数必须和names长度一致。path用绝对路径最稳相对路径在不同工作目录下启动训练时经常找不到文件这是新手最常见的翻车点之一。3. YOLOv5 训练舰船检测模型从环境配置到超参数怎么调环境配置这一步conda 建虚拟环境是主流做法能避开系统 Python 的依赖冲突。YOLOv5 对 PyTorch 和 CUDA 版本比较敏感版本对不上会报一堆看不懂的错。我一般先确认显卡驱动支持的 CUDA 上限再选对应的 PyTorch。3.1 环境配置与最小可跑命令# 建环境Python 版本选 3.8 或 3.9兼容性最好 conda create -n ship_yolo python3.9 -y conda activate ship_yolo # 装 PyTorchCUDA 11.8 是当前比较通用的版本按自己驱动改 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 拉 YOLOv5 源码并装依赖 git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt装完先跑一次自检确认环境和预训练权重都能用python detect.py --weights yolov5s.pt --source data/images --device 0这条命令会用 COCO 预训练的 yolov5s 跑一遍示例图。如果这一步就报错别急着训自己的数据先把环境问题解决掉。常见错误是torch.cuda.is_available()返回 False多半是 PyTorch 版本和驱动不匹配重装对应 CUDA 版本的 torch 即可。3.2 训练命令与关键超参数舰船检测我一般从 yolov5s 起步数据量几千张的话yolov5s 或 yolov5m 足够上 l/x 容易过拟合且推理慢。python train.py \ --data data/ship.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 150 \ --hyp data/hyps/hyp.scratch-low.yaml \ --device 0 \ --project runs/train \ --name ship_v1参数逐个说--img 640是输入分辨率舰船小目标多的话可以提到 1024但显存占用翻倍batch 要相应降到 4 或 8。--batch 16在 8G 显存上跑 640 分辨率比较稳。--epochs 150是经验值配合早停YOLOv5 默认 patience100不会白跑。--hyp选hyp.scratch-low.yaml是因为舰船数据集通常不大低增强配置能减少过拟合如果数据量上万可以换hyp.scratch-high.yaml加强增强。训练过程中重点看三个指标mAP0.5、mAP0.5:0.95和box_loss。如果 box_loss 一直不降检查标签格式如果 mAP 在验证集上远低于训练集说明过拟合或验证集分布不一致。3.3 舰船小目标的针对性调整舰船检测最头疼的是小目标。640 分辨率下一条 20 像素的船经过下采样后特征几乎消失。三个可操作的调整第一提高输入分辨率到 1024 或 1280代价是显存和推理时间。第二调整 anchor用python utils/autanchor.py在你的数据集上重新聚类 anchor让先验框更贴合舰船的长宽比——舰船普遍是细长型COCO 的默认 anchor 偏方正匹配度差。第三开启--multi-scale多尺度训练让模型适应不同尺度的目标。anchor 重聚类的命令python utils/autoanchor.py --data data/ship.yaml --weights yolov5s.pt它会输出当前 anchor 和数据集的最佳匹配度如果 best possible recall 低于 0.98就值得重新生成 anchor 并写回模型配置。4. PyQt 界面怎么做把训练好的模型包成能点的桌面工具模型训完.pt文件躺在 runs 目录里除了你自己没人会用。PyQt 界面的价值就是把这层命令行封装掉让同事双击就能选图、看结果、导出。别把界面做复杂核心就三个功能选图片/文件夹、跑推理、显示带框结果。4.1 界面结构设计与线程处理PyQt 做推理界面最大的坑是主线程卡死。推理是耗时操作如果直接在主线程里调模型界面会假死用户以为程序崩了。正确做法是把推理放到 QThread 里通过信号槽回传结果。界面布局我一般用最简单的三段式顶部一个按钮区选图、选文件夹、开始检测中间一个 QLabel 显示原图或结果图底部一个 QTextEdit 显示检测日志检测到几个目标、耗时多少。import sys import cv2 import torch from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, QLabel, QVBoxLayout, QWidget, QTextEdit, QFileDialog) from PyQt5.QtCore import QThread, pyqtSignal from PyQt5.QtGui import QImage, QPixmap class InferThread(QThread): # 信号传回带框图像和日志文本 finished pyqtSignal(object, str) def __init__(self, model, img_path): super().__init__() self.model model self.img_path img_path def run(self): # 推理在子线程执行避免阻塞界面 results self.model(self.img_path) rendered results.render()[0] # 返回带框的 numpy 数组 log f检测到 {len(results.xyxy[0])} 个目标 self.finished.emit(rendered, log) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(舰船检测系统) self.model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/ship_v1/weights/best.pt) self.model.conf 0.25 # 置信度阈值界面里可做成滑块 self.init_ui() def init_ui(self): central QWidget() layout QVBoxLayout() self.btn_open QPushButton(选择图片) self.btn_open.clicked.connect(self.open_image) self.label QLabel(等待选择图片) self.log QTextEdit() self.log.setReadOnly(True) layout.addWidget(self.btn_open) layout.addWidget(self.label) layout.addWidget(self.log) central.setLayout(layout) self.setCentralWidget(central) def open_image(self): path, _ QFileDialog.getOpenFileName(self, 选图, , Images (*.png *.jpg)) if not path: return self.thread InferThread(self.model, path) self.thread.finished.connect(self.show_result) self.thread.start() def show_result(self, img, log_text): # OpenCV 是 BGRQt 要 RGB转换顺序别搞反 h, w, c img.shape qimg QImage(img.data, w, h, w * c, QImage.Format_RGB888).rgbSwapped() self.label.setPixmap(QPixmap.fromImage(qimg)) self.log.append(log_text) if __name__ __main__: app QApplication(sys.argv) win MainWindow() win.show() sys.exit(app.exec_())逻辑说明InferThread继承 QThread把模型推理放在run()里完成后通过finished信号把图像和日志传回主线程。torch.hub.load直接加载本地训练好的best.ptconf是置信度阈值做成界面滑块能让用户自己调松紧。rgbSwapped()处理 OpenCV 的 BGR 到 Qt 的 RGB 转换这一步漏了颜色会反。参数上conf0.25是通用起点舰船检测如果误检多就提到 0.4漏检多就降到 0.15。iou阈值默认 0.45密集船只场景可以降到 0.3 减少框合并。4.2 打包成 exe 与常见依赖问题界面写完用 PyInstaller 打包成 exe 给不装 Python 的人用pyinstaller --noconfirm --windowed --name ShipDetect \ --add-data runs/train/ship_v1/weights/best.pt;weights \ main.py--windowed去掉控制台窗口--add-data把模型权重打进去。注意路径分隔符在 Windows 上是分号Linux 上是冒号。打包后最常见的翻车是模型路径找不到——代码里要用sys._MEIPASS处理打包后的临时目录不能写死相对路径。5. 避坑与排查舰船检测项目里最容易翻车的五件事这一章是我踩过的坑里挑出来最有代表性的五条每条按现象、原因、解决写。坑一训练 loss 正常但 mAP 一直是 0。现象是 box_loss 在降但验证集 mAP 死活不动。原因九成是data.yaml里的names顺序和标签文件里的 class_id 对不上或者nc写错了。解决方法是拿一张训练图手动跑detect.py看输出的类别名对不对再抽查几个 label txt 的第一列数字是否在[0, nc-1]范围内。坑二小目标全漏检。现象是近处大船检得到远处小船一个都检不出。原因是输入分辨率太低小目标下采样后特征消失。解决是把--img提到 1024同时用 autoanchor 重聚类 anchor让先验框匹配舰船的细长比例。坑三PyQt 界面点检测就卡死。现象是点按钮后窗口无响应几秒后恢复。原因是推理跑在主线程。解决是把推理逻辑放进 QThread用信号槽回传结果主线程只负责 UI 更新。坑四打包后 exe 报找不到模型。现象是源码能跑打包后启动就崩。原因是 PyInstaller 把文件解压到临时目录代码里的相对路径失效。解决是用sys._MEIPASS拼接资源路径并在打包时用--add-data把权重文件带上。坑五验证集指标虚高上线就拉胯。现象是验证集 mAP 0.9实际用起来一堆误检漏检。原因是数据集划分时同一场景的相似帧同时进了训练和验证集。解决是按海域或航次划分确保验证集来自训练时没见过的场景。6. 让舰船检测真正可用的两个进阶技巧第一个技巧是用测试时增强TTA换精度。YOLOv5 推理时加--augment参数会做多尺度翻转增强再合并结果小目标召回率通常能涨几个点代价是推理时间翻倍。对离线分析场景值得对实时视频流不划算。我一般先在验证集上对比开与不开的 mAP 差异超过 2 个点才考虑上线开。python detect.py --weights best.pt --source test_imgs --augment --conf 0.2第二个技巧是置信度阈值分场景调。港口监控场景误报代价高conf提到 0.4 以上搜救场景漏检代价高conf降到 0.1 并配合 TTA。这个阈值不该写死在代码里应该在 PyQt 界面上做成滑块让使用者按任务自己调。我在界面里加了一个 conf 滑块和一个 iou 滑块联调时发现比任何文档都管用——用户自己拖两下就知道什么值合适。最后一个习惯每次训完模型别只看 mAP 数字一定导出 20 张验证集的预测图肉眼过一遍。指标会骗人尤其是小目标和密集场景肉眼看一遍能发现一堆指标看不出的问题。这套链路我从数据清洗到界面联调走下来真正花时间的从来不是模型本身而是数据和交互。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑