简介:本资源面向煤矿智能化巡检与工业视觉检测方向的开发者、研究生及算法工程师,提供一套基于YOLOv8的煤矿传送带矸石与锚杆异物检测完整方案,可直接用于推理部署,也可基于数据集重新训练。包内包含3000多张标注图像,标签为txt格式,已按train、val、test划分并配置好data.yaml,类别涵盖bolt_object与bulk_object两类,yolov5、yolov7、yolov8、yolov9等主流框架均可直接接入训练。资源共2000个文件,以1991个xml标注文件为主,另含md说明、pdf环境配置教程与py脚本,压缩包约323.4MB,目录结构清晰,便于按模块检索与复现。配套PyQt可视化界面,可加载训练权重实现检测结果展示,适合快速验证与二次开发。目前已有233人学习下载,适合需要煤矿异物检测实战数据与可运行代码的中高级读者参考。
1. 煤矿传送带异物检测:这套 YOLOv8 方案到底能不能直接落地
煤矿传送带上的矸石和锚杆,是两类性质完全不同的异物。矸石是煤矸混杂的产物,形状不规则、灰度与煤块接近;锚杆则是金属杆状物,细长、反光、容易和传送带边缘的金属支架混淆。这两类目标混在同一条皮带上,传统阈值分割或者简单形态学方法基本没法同时兼顾。这套资源给的是一个 YOLOv8 目标检测模型,配了 3000 多张标注好的煤矿传送带场景数据集,外加一个 PyQt 可视化界面,打开就能跑推理、看检测框、切换图片和视频源。
适合谁用?如果你在做矿山智能化、皮带异物监测、工业视觉巡检这类项目,或者毕业设计选题落在“基于深度学习的传送带异物检测”,这套东西能帮你省掉最耗时的数据采集和标注环节。3000 张的量级不算大,但对于矸石和锚杆这两个类别,如果标注质量过关,够训出一个能用的基线模型。PyQt 界面不是玩具,它把模型推理、结果渲染、文件加载串起来了,你可以直接拿来做演示或者二次开发。下面我从数据、训练、界面、部署几个环节拆开讲,重点说清楚哪些地方容易翻车。
2. 数据集拆解与 YOLOv8 训练配置:从 3000 张标注到可收敛模型
2.1 矸石与锚杆的标注特点
矸石在图像里通常表现为块状、边缘粗糙、颜色偏暗灰或黑褐,和煤块的区别在于纹理更杂乱、反光更弱。锚杆则是细长条状,长度可能横跨半个画面,直径只有几个像素到十几个像素。这两类目标放在同一个数据集里,标注策略要分开考虑。
矸石的标注框一般比较规整,外接矩形就能框住,但要注意别把相邻的煤块误标进去。锚杆的标注难点在于细长目标,YOLOv8 的 anchor-free 机制对长宽比大的目标本身有一定适应能力,但如果标注框只框了锚杆中间一段、两端没包住,训练出来的模型会倾向于只检测锚杆的“主体部分”,边缘漏检。我一般会要求标注时锚杆两端各留 2 到 3 个像素的余量,宁可框大一点,也别框小。
数据集目录结构按 YOLOv8 的标准来:
dataset/ ├── images/ │ ├── train/ # 训练集图片,约 2400 张 │ ├── val/ # 验证集图片,约 600 张 ├── labels/ │ ├── train/ # 对应标注 txt │ ├── val/ └── data.yaml # 数据集配置文件data.yaml的内容大致如下:
path: ./dataset train: images/train val: images/val nc: 2 names: 0: gangue # 矸石 1: anchor # 锚杆这里nc: 2表示两个类别,names的顺序必须和标注文件里类别索引一致。常见翻车点是标注时把矸石标成 0、锚杆标成 1,但data.yaml里写反了,训练 loss 能降但推理时类别全乱。
2.2 YOLOv8 训练参数怎么设
这套资源用的是 YOLOv8,具体是 n/s/m/l/x 哪个版本,项目正文没写,但 3000 张数据量下我建议从yolov8s或yolov8m起步。n 太小容易欠拟合,l 以上在 3000 张上容易过拟合,除非你做大量增强。
训练命令用 Ultralytics 的 CLI:
yolo detect train \ data=dataset/data.yaml \ model=yolov8s.pt \ epochs=150 \ imgsz=640 \ batch=16 \ lr0=0.01 \ lrf=0.01 \ patience=30 \ device=0 \ project=runs/train \ name=gangue_anchor_v8s逐项说:epochs=150是上限,patience=30表示 30 轮验证指标不提升就早停,实际可能 80 到 120 轮就收敛。imgsz=640是 YOLOv8 的默认输入尺寸,如果你的锚杆在原始图像里特别细,可以试imgsz=960,但显存占用会明显上升。batch=16在 8GB 显存卡上跑yolov8s加 640 尺寸基本稳,12GB 以上可以上 32。lr0=0.01是初始学习率,lrf=0.01是最终学习率系数,余弦退火到lr0 * lrf。
如果你用 Python 脚本训练,等价写法:
from ultralytics import YOLO model = YOLO("yolov8s.pt") model.train( data="dataset/data.yaml", epochs=150, imgsz=640, batch=16, lr0=0.01, lrf=0.01, patience=30, device=0, project="runs/train", name="gangue_anchor_v8s" )训练过程中重点看三个指标:box_loss是否稳定下降、mAP50是否在验证集上持续爬升、cls_loss有没有异常波动。如果box_loss降但mAP50不涨,大概率是标注框质量问题;如果cls_loss震荡厉害,检查两类样本是否严重不均衡。
2.3 数据增强的边界
YOLOv8 默认开启 mosaic、HSV 抖动、随机翻转等增强。煤矿传送带场景下,HSV 抖动对矸石检测有帮助,因为井下光照变化大;但随机翻转要小心,锚杆在真实场景里通常有固定走向,垂直翻转可能产生不合理的样本。我一般会关掉垂直翻转:
model.train( ..., fliplr=0.5, # 水平翻转保留 flipud=0.0, # 关闭垂直翻转 mosaic=1.0, # mosaic 保留 hsv_h=0.015, hsv_s=0.7, hsv_v=0.4 )mosaic=1.0表示始终用 mosaic 增强,它对小目标检测有好处,但如果你发现锚杆被拼接到奇怪位置导致误检,可以降到 0.5。hsv_s=0.7是饱和度抖动幅度,煤矿图像本身饱和度低,这个值可以适当调小到 0.5,避免颜色失真。
3. PyQt 可视化界面:推理管线与交互逻辑怎么串
3.1 界面结构拆解
这套资源的 PyQt 界面,从功能上看至少包含几个模块:图片/视频加载、模型推理、检测结果渲染、类别统计显示。PyQt 本身只是 GUI 框架,真正干活的是背后调用的 YOLOv8 推理接口。常见的实现方式是主线程负责界面刷新,子线程跑推理,避免界面卡死。
一个典型的推理线程类:
from PyQt5.QtCore import QThread, pyqtSignal from ultralytics import YOLO import cv2 class InferenceThread(QThread): frame_ready = pyqtSignal(object) # 发送带检测框的图像 stats_ready = pyqtSignal(dict) # 发送类别统计 def __init__(self, model_path, source): super().__init__() self.model = YOLO(model_path) self.source = source self.running = True def run(self): cap = cv2.VideoCapture(self.source) while self.running and cap.isOpened(): ret, frame = cap.read() if not ret: break results = self.model(frame, imgsz=640, conf=0.25, iou=0.45) annotated = results[0].plot() # 绘制检测框 self.frame_ready.emit(annotated) # 统计各类别数量 boxes = results[0].boxes stats = {} if boxes is not None: for cls_id in boxes.cls.tolist(): name = self.model.names[int(cls_id)] stats[name] = stats.get(name, 0) + 1 self.stats_ready.emit(stats) cap.release()conf=0.25是置信度阈值,iou=0.45是 NMS 的 IoU 阈值。这两个参数在界面里最好做成可调的,因为煤矿场景下矸石和煤块颜色接近,置信度阈值太低会误检,太高会漏检。我一般会把conf的调节范围放在 0.1 到 0.6 之间。
3.2 界面与模型解耦
PyQt 界面代码和模型推理代码不要写在一个文件里。常见做法是拆成三个文件:ui_main.py负责界面布局,inference.py封装推理逻辑,main.py做入口和信号连接。这样你换模型、改推理参数时不用动界面代码。
信号连接部分:
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.thread = None def start_detection(self): source = self.ui.lineEdit_source.text() self.thread = InferenceThread("best.pt", source) self.thread.frame_ready.connect(self.update_frame) self.thread.stats_ready.connect(self.update_stats) self.thread.start() def update_frame(self, frame): rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = rgb.shape qimg = QImage(rgb.data, w, h, ch * w, QImage.Format_RGB888) self.ui.label_display.setPixmap(QPixmap.fromImage(qimg)) def update_stats(self, stats): text = " | ".join([f"{k}: {v}" for k, v in stats.items()]) self.ui.label_stats.setText(text)update_frame里做了 BGR 到 RGB 的转换,因为 OpenCV 读进来是 BGR,Qt 显示需要 RGB。QImage构造时ch * w是每行字节数,这个参数写错会导致图像花屏。update_stats把类别统计拼成字符串显示,方便现场人员一眼看到当前画面里有几块矸石、几根锚杆。
3.3 视频源与帧率控制
如果输入是视频文件,推理速度取决于模型大小和硬件。yolov8s在 GTX 1660 Ti 上跑 640 尺寸,单帧大概 15 到 25 毫秒,理论上能到 40 FPS 以上,但 PyQt 界面刷新和视频解码会吃掉一部分性能。实际体验下来,30 FPS 的视频源能流畅处理。如果卡顿,可以在推理线程里跳帧:
frame_count = 0 while self.running and cap.isOpened(): ret, frame = cap.read() if not ret: break frame_count += 1 if frame_count % 2 != 0: # 每两帧处理一帧 continue results = self.model(frame, ...)跳帧会降低检测的时序连续性,但对于传送带异物监测,只要异物在画面里停留超过 0.5 秒,跳一帧不影响报警。如果输入是 RTSP 流,cv2.VideoCapture的缓冲会导致延迟累积,常见做法是设置cap.set(cv2.CAP_PROP_BUFFERSIZE, 1),但 OpenCV 对 RTSP 缓冲的控制有限,更稳的方案是用ffmpeg拉流后推给推理线程。
4. 避坑与排查:训练和推理阶段最容易翻车的五个点
4.1 现象:训练 loss 正常下降,但验证集 mAP 始终在 0.1 以下
原因:标注文件里的类别索引和data.yaml的names顺序不一致,或者标注格式不是 YOLO 的class x_center y_center width height归一化格式。有些标注工具导出的是 VOC 的xmin ymin xmax ymax绝对坐标,直接拿来用会出问题。
解决:写个脚本检查标注文件,确认每行第一个数字是 0 或 1,后面四个数都在 0 到 1 之间。如果是 VOC 格式,先转换:
import os from PIL import Image def voc_to_yolo(img_path, xml_boxes, class_map, output_path): img = Image.open(img_path) w, h = img.size with open(output_path, "w") as f: for cls_name, xmin, ymin, xmax, ymax in xml_boxes: cls_id = class_map[cls_name] x_center = (xmin + xmax) / 2.0 / w y_center = (ymin + ymax) / 2.0 / h bw = (xmax - xmin) / w bh = (ymax - ymin) / h f.write(f"{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}\n")4.2 现象:模型对矸石检测还行,但锚杆几乎全漏
原因:锚杆细长,在 640 尺寸下可能只占几个像素宽,YOLOv8 的 P3 特征图下采样 8 倍后,细杆特征被稀释。另外如果标注时锚杆框太紧,训练时正样本匹配数量不足。
解决:把输入尺寸提到 960 或 1280,同时检查标注框是否包住了锚杆两端。如果数据量够,可以在data.yaml里给锚杆类别加权重,但 YOLOv8 原生不支持类别权重,需要改 loss 或者用过采样。更简单的做法是复制锚杆样本,让两类样本比例接近 1:1。
4.3 现象:PyQt 界面点“开始检测”后直接卡死
原因:推理代码写在了主线程里,model()调用是阻塞的,界面事件循环被堵住。
解决:把推理放到QThread子类里,通过信号槽更新界面。注意不要在子线程里直接操作 UI 控件,所有 UI 更新必须通过信号发回主线程。另外QThread的run方法里不要创建QWidget对象。
4.4 现象:视频检测结果框闪烁严重,同一目标时有时无
原因:置信度阈值设得太高,或者 NMS 的 IoU 阈值太低导致相邻帧检测框被抑制。另外如果视频压缩率高,锚杆边缘模糊,模型置信度会在阈值附近波动。
解决:把conf降到 0.2 左右,iou提到 0.5 到 0.6。如果还闪,可以在后处理里加简单的跟踪逻辑,比如用 IOU 匹配相邻帧的检测框,连续 3 帧命中才输出报警。
4.5 现象:换一台机器推理,报CUDA out of memory或no kernel image is available
原因:训练和推理的 CUDA 版本、显卡架构不一致。比如训练用 RTX 30 系,推理用 GTX 10 系,PyTorch 版本没对应好。
解决:确认推理环境的 PyTorch 和 CUDA 版本匹配。如果目标机器没有 NVIDIA 显卡,导出 ONNX 用 CPU 推理:
model = YOLO("best.pt") model.export(format="onnx", imgsz=640, simplify=True)然后 PyQt 里用onnxruntime加载 ONNX 模型推理。CPU 推理速度会慢不少,yolov8s在 i7 上单帧大概 80 到 150 毫秒,适合对实时性要求不高的场景。
5. 模型导出与 PyQt 界面打包:从开发环境到现场部署的最后一公里
训练完拿到best.pt只是第一步,真正要拿到现场用,还得解决模型导出和界面打包两个问题。先说导出。YOLOv8 支持多种导出格式,煤矿现场常见的目标机器可能是工控机、Jetson 或者 RK3588 这类边缘设备。如果工控机有 NVIDIA 显卡,直接best.pt加 PyTorch 环境最省事;如果没有,导出 ONNX 用 CPU 跑;如果是 RK3588,需要导出 RKNN 格式,但 Ultralytics 原生不支持直接导 RKNN,得先转 ONNX 再用 RKNN Toolkit 转换。
ONNX 导出时有个细节:simplify=True会调用 onnx-simplifier 优化计算图,但某些自定义算子可能被简化掉导致推理结果异常。我一般会先导一版不简化的,对比推理结果一致后再用简化版。导出命令:
from ultralytics import YOLO model = YOLO("runs/train/gangue_anchor_v8s/weights/best.pt") model.export( format="onnx", imgsz=640, opset=12, simplify=False, dynamic=False )opset=12是 ONNX 算子集版本,RKNN 和 TensorRT 对 opset 的支持范围不同,12 是比较稳的选择。dynamic=False表示固定输入尺寸,边缘设备上固定尺寸推理效率更高。
PyQt 界面打包用 PyInstaller,但 YOLOv8 依赖的ultralytics包里有动态导入和资源文件,直接打包容易漏东西。我一般会写一个.spec文件,把ultralytics的路径显式加进去:
# main.spec from PyInstaller.utils.hooks import collect_data_files datas = collect_data_files("ultralytics") a = Analysis( ["main.py"], datas=datas, hiddenimports=["ultralytics", "torch", "cv2"], ... )打包命令pyinstaller main.spec。打出来的 exe 在没装 Python 的 Windows 机器上跑,第一次启动会解压资源,慢一点正常。如果报ModuleNotFoundError,检查hiddenimports里有没有漏掉ultralytics.models或ultralytics.nn这类子模块。
最后说一个我踩过的坑:PyQt 界面里加载模型路径不要写死绝对路径,现场机器盘符可能不一样。我习惯把best.pt和data.yaml放在 exe 同级的models/目录下,代码里用os.path.dirname(sys.argv[0])拼相对路径。从那以后我每次打包完都会在一台干净机器上跑一遍完整流程:打开界面、加载图片、切换视频、调置信度、看统计输出。希望帮到你。
本文还有配套的精品资源,点击获取