YOLOv5鸡蛋目标检测实战:数据集+PyQt界面+推理避坑全解析 简介面向计算机视觉初学者、目标检测方向毕设学生及需要快速落地鸡蛋检测方案的项目开发者这份资源围绕YOLOv5鸡蛋目标检测任务提供从数据集、训练权重到PyQt可视化界面的完整闭环。包内包含训练好的模型权重可直接对鸡蛋图像进行推理附带已划分train、val、test的鸡蛋数据集配套data.yaml配置文件将目录指向对应文件夹后YOLOv5、YOLOv7、YOLOv8等算法均可直接启动训练省去自行采集与标注数据的时间。资源总计643个文件以jpg图像、xml与txt标注文件为主体同时包含py源码、pyc编译文件、pt模型、ui界面文件以及shell脚本、说明文档、演示视频等类型压缩包大小116.87MB结构清晰便于按需取用。目前已有140人学习下载适合希望借助现成数据与可视化工具快速复现目标检测流程、或在此基础上扩展项目功能的读者。1. 拿到一套 YOLOv5 鸡蛋检测资源先确认它是不是半成品做养殖场巡检、鸡蛋分拣计数这类活最怕的事情是教程翻了一堆到最后手里只有一个.pt权重文件数据没有、界面没有想跑个 demo 还得从零写起。这套「yolov5鸡蛋目标检测」资源解决的就是这个「最后一公里」训练好的模型权重、鸡蛋目标检测数据集、PyQt 可视化界面三件套齐全解压之后不碰训练也能先看到检测效果。适合有 Python 基础、想快速在鸡蛋这类小目标检测场景做出可演示成果的开发者也适合正在给养殖或农产品项目做技术选型的人。先花半小时把资源和环境对齐后面换数据、调参数、接业务才有得玩。2. 检测链路拆解模型推理、输出解析与单张图片跑通2.1 下载包里到底有什么模型、数据集与界面的分工拿到压缩包先别急着双击python main.py第一件事是把目录结构看明白。这套资源的典型组织方式如下目录/文件内容在链路中的作用weights/best.pt训练好的 YOLOv5 权重整个检测链路的入口也是资源里的「黑匣子」dataset/鸡蛋数据集images 与 labels 按 train/val 划分二次训练与精度验证的数据基础gui/PyQt 界面主程序把检测包装成人能直接操作的窗口程序detect.py命令行推理脚本最快跑通链路的方式先于 GUI 验证模型requirements.txttorch、PyQt5、opencv 等依赖清单环境一键安装我拿到这类资源后的固定顺序是先看目录再装依赖然后跑一次命令行推理最后才开 GUI。原因很简单——GUI 涉及界面线程、信号槽、显示控件任何一个环节出错都会干扰你对模型本身的判断。先用detect.py验证权重能加载、能出框、坐标是对的后面所有问题都好定位。依赖安装用虚拟环境是比较稳的做法避免污染系统 Python。requirements.txt里的 torch 版本建议按资源作者锁定的版本来YOLOv5 对 torch 版本并不挑但你要是已经装了 PyTorch 2.x有些旧版torch.hub接口的行为会略有差异遇到再说没遇到不用管。2.2 为什么是 YOLOv5单类小目标检测的选型逻辑鸡蛋检测本质上是一个单类目标检测任务模型只需要区分「蛋」和「背景」。YOLOv5 虽然是 anchor-based 时代的代表性框架但对蛋这种形态相对规则、大小相对一致的物体速度和精度的平衡依然很好。它内置的自适应锚框计算会自动根据数据集重新聚类 anchor这一点在训练小目标时非常省心。YOLOv5s 的模型结构是 CSPDarknet 骨干加 PANet 颈部配合三个尺度的输出头。鸡蛋这类目标在 640 分辨率下通常占几十到上百像素属于中小目标主要落在中尺度和大尺度输出头上。实际跑下来v5 对这个场景的召回率是够用的。你不需要理解每个模块的细节但要清楚一个边界这套资源从权重到数据到界面代码都是围绕 YOLOv5 自洽的。如果你已经在用 ultralytics 的 v8 或 v11 环境这套 v5 的.pt权重不能直接复用需要先做权重转换、再对齐推理接口那是另一套工作量。生态成熟度也是选型的重要理由。YOLOv5 的部署资料是目前检测框架里最多的rk3568 量化、树莓派部署这类边缘场景网上案例一抓一把资源作者把模型和数据都给全了后续你要做嵌入式迁移参考资料不会缺。2.3 跑通第一条推理命令torch.hub 加载、输出解析与画框保存命令行推理是验证资源完整性的最快路径新建一个test_infer.py内容如下import torch import cv2 # force_reloadFalse 时走本地缓存换过权重文件就改成 True 强制重新下载模型结构 model torch.hub.load(ultralytics/yolov5, custom, pathweights/best.pt, force_reloadFalse) model.conf 0.35 # 置信度阈值低于它的框一律丢弃 model.iou 0.45 # NMS 的 IoU 阈值两个重叠框高于它则合并 img cv2.imread(dataset/images/val/001.jpg) results model(img, size640) # size640 输入尺寸小目标多可试 960 results.save(runs/detect/) # 保存画框后的图YOLOv5 自动创建 exp/exp2 子目录 df results.pandas().xyxy[0] # 转为 DataFramex1,y1,x2,y2,confidence,class print(df[[x1, y1, x2, y2, confidence]]) print(目标数量:, len(df))代码逻辑不复杂但有几个参数值得说清楚。torch.hub.load的第一个参数ultralytics/yolov5指定从 GitHub 拉取模型结构代码custom表示加载自定义权重path指向你下载好的best.pt。force_reload这个参数是个常见陷阱默认False时走本地缓存如果你后来换了一个新的best.pt但文件名没变加载的很可能还是旧权重遇到模型行为不对时优先检查这里。model.conf和model.iou是推理时最常调的两个参数后面 PyQt 界面里的滑块本质上就是改这两个属性。results.pandas().xyxy[0]返回的表格里x1 y1 x2 y2是检测框的像素坐标confidence是该框的置信度class是类别编号单类场景下恒为 0。批量检测可以套一个循环import glob for p in sorted(glob.glob(dataset/images/val/*.jpg)): r model(cv2.imread(p), size640) r.save(runs/detect/) print(p, 检测到, len(r.xyxy[0]), 个鸡蛋)注意这里有两个习惯一是glob排序保证输出顺序稳定二是建议在脚本开头用os.chdir(os.path.dirname(os.path.abspath(__file__)))把工作目录固定到脚本所在位置否则相对路径weights/best.pt会因为你在别的目录下运行而报找不到文件。这个坑几乎每个用 YOLOv5 的人都踩过。3. PyQt 可视化界面把模型包装进 GUI 的正确姿势3.1 界面功能拆解图片、视频、摄像头三条检测通道PyQt 界面在这个资源里的角色是「让不懂命令行的人也能用检测模型」。常见的界面结构是三个检测通道加一个参数区界面模块控件形式背后调用的检测入口图片检测文件选择按钮 图片显示区单帧model(img)视频检测视频文件路径 播放/暂停逐帧读取循环摄像头检测打开/关闭按钮cv2.VideoCapture(0)参数区置信度 QSlider、IoU QSlider实时写model.conf/model.iou结果区QLabel 显示画框帧QThread 信号槽更新三条检测通道的底层逻辑是一样的都是把一帧图像喂给同一个model对象然后取出画框结果。所以不要复制三份推理代码抽一个公共函数更合理def detect_frame(model, frame, size640): results model(frame, sizesize) boxed results.render()[0] # 返回画好框的 BGR ndarray count len(results.xyxy[0]) return boxed, countrender()[0]是 YOLOv5 内置的画框方法直接在原图上绘制检测框和标签返回 numpy 数组。后面无论图片、视频还是摄像头通道都调用这个函数界面代码会干净很多。3.2 关键代码用 QThread 把推理和界面分离PyQt 界面最容易翻车的点不是检测本身而是把推理写在了按钮的槽函数里。Qt 的界面事件循环跑在主线程上推理一个 640 分辨率的帧大约要几十毫秒视频流就是逐帧推理主线程被阻塞后窗口直接表现为「未响应」。业界通行解法是开一个QThread子线程跑推理通过信号把结果传回主线程更新界面。from PyQt5.QtCore import QThread, pyqtSignal import cv2 import numpy as np class DetectThread(QThread): frame_out pyqtSignal(np.ndarray) # 画框后的帧 count_out pyqtSignal(int) # 每帧检测到的鸡蛋数量 def __init__(self, model, source0): # source0 表示默认摄像头 super().__init__() self.model model self.source source self._running True def run(self): cap cv2.VideoCapture(self.source) while self._running and cap.isOpened(): ok, frame cap.read() if not ok: break results self.model(frame, size640) boxed results.render()[0] self.frame_out.emit(boxed) self.count_out.emit(len(results.xyxy[0])) cap.release() def stop(self): self._running False self.wait() # 等 run 退出再返回防止线程泄漏这段代码是视频和摄像头通道共用的骨架。frame_out和count_out是两个信号子线程里emit后主线程里connect的槽函数会收到数据。stop()方法里_running置False后必须wait()否则线程还在跑就被销毁程序退出时会崩。主窗口侧接收信号的写法class MainWindow(QMainWindow): def __init__(self, model): super().__init__() self.model model self.thread None def start_camera(self): if self.thread is not None: return # 防止重复启动 self.thread DetectThread(self.model, source0) self.thread.frame_out.connect(self.show_frame) self.thread.count_out.connect(self.show_count) self.thread.start() def show_frame(self, frame): h, w, _ frame.shape qimg QImage(frame.data, w, h, 3 * w, QImage.Format_BGR888) self.video_label.setPixmap(QPixmap.fromImage(qimg)) def stop_camera(self): if self.thread: self.thread.stop() self.thread Noneshow_frame里的QImage构造是 PyQt 显示 numpy 图像的标准姿势注意3 * w这个字节跨度参数不能写错否则图像显示出来是花的。start_camera里的空判断也值得保留Qt 里重复启动一个 QThread 会直接崩溃。3.3 界面上的可调参数置信度和 IoU 阈值怎么映射到推理界面上放滑块不是摆设这两个参数直接决定检测效果。参数映射关系如下界面参数滑块范围推荐值调高/调低的影响置信度 conf0.10 ~ 0.900.35调高漏检增多调低背景误检增多IoU 阈值0.30 ~ 0.700.45调高保留更多重复框调低合并掉挨得近的蛋鸡蛋场景比较特殊的地方在于蛋与蛋经常紧挨着尤其是蛋托里的蛋边界几乎是贴着的。IoU 阈值调到 0.5 以上时相邻蛋的框可能被 NMS 误合并导致漏检调到 0.35 以下则一个蛋上容易出现两个重复框。我自己常用的组合是conf0.35, iou0.45在这个场景下误检和漏检相对均衡。滑块绑定的实现就是model.conf slider.value() / 100这种写法滑块变化时实时更新模型属性下次推理自动生效不需要重启程序。4. 鸡蛋数据集与二次训练换场景、提精度都要落在这里4.1 数据集目录与 YOLO 标注格式每一行 txt 的含义这套资源自带的数据集是「能用」和「能继续训练」的分界线。目录结构通常是dataset/ ├── egg.yaml ├── images/ │ ├── train/ # 训练图片 │ └── val/ # 验证图片 └── labels/ ├── train/ # 训练图片对应的标注 txt └── val/egg.yaml是数据配置YOLOv5 训练时直接读它train: dataset/images/train val: dataset/images/val nc: 1 names: [egg]train和val的路径可以是相对train.py的路径也可以是绝对路径。nc是类别数单类鸡蛋就是 1names列表里第一个名字是egg。每张图片对应的 txt 标注文件每行表示一个目标0 0.5219 0.4367 0.1284 0.0961这 5 个数字依次是class_id从 0 开始、归一化中心 x、归一化中心 y、归一化宽、归一化高。所谓归一化就是像素坐标除以图片宽高所以值必然在 0~1 之间。举个例子0.5219 0.4367表示该蛋的中心点在图片约 52% 宽度、44% 高度处0.1284 0.0961表示该蛋的宽占图片宽度 12.8%、高占图片高度 9.6%。这个格式是整个资源能否无缝共用的关键——训练、验证、CLI 推理、GUI 界面全部读同一套标注。你换自己的数据集时也必须转成这个格式否则训练直接报错。4.2 训练自己的鸡蛋数据数据配置、训练命令与超参数取值数据集看明白之后二次训练其实就是一条命令的事python train.py \ --data dataset/egg.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --imgsz 640 \ --device 0几个参数按实际机器调整--weights yolov5s.pt是官方预训练权重不是资源里自带的best.pt。很多人误用下载的best.pt来继续训练但best.pt是已经收敛到鸡蛋域的模型你再拿它训自己的数据相当于在错位的特征层上微调loss 会表现得非常诡异。二次训练的统一入口是官方 80 类的yolov5s.pt让模型先有通用视觉特征再迁移到鸡蛋域。--epochs先跑 100然后看runs/train/exp下的val/obj_loss曲线如果还在降就加到 150~200。--batch-size 16需要约 8GB 显存显存不够就减半到 8。--imgsz 640是速度和精度的平衡点鸡蛋是小目标升到 960 通常能提升召回率但训练时间和显存占用接近翻倍先 640 跑通再调。YOLOv5 的超参数文件hyp.scratch-low.yaml和hyp.scratch.yaml也值得知道。数据集规模在几百张量级时用--hyp hyp.scratch-low.yaml更稳它的学习率更低不容易在少量数据上过拟合。如果训练时 loss 震荡得厉害最常见的调法是直接把--hyp里的lr0从 0.01 改成 0.001其他超参数基本不用动。训练完成后验证一下python val.py --weights runs/train/exp/weights/best.pt --data dataset/egg.yaml重点看mAP0.5、mAP0.5:0.95、precision、recall四个指标。这套资源自带模型的精度以压缩包内 README 或训练日志为准你自己训出来的模型以这次val.py的结果为准。4.3 标注环节的常见坑遮挡、反光与大小不一鸡蛋数据集的标注比想象中容易出错。第一个坑是遮挡——蛋托里的蛋互相挨着前一个蛋的边缘被后一个挡住标注时框不能强行把两个蛋包在一起宁可切掉被挡住的边缘让框只包围可见部分。YOLO 允许框局部包含背景模型自己会学。第二个坑是反光。养殖场灯光下鸡蛋表面会出现高光看起来像一块白斑标注时不能按高光轮廓画要按蛋的实际边缘画。这个只能靠标注时的耐心一套数据集的精度上限在标注阶段就决定了。第三个坑是大小不一。远处的小蛋和近处的大蛋在图像里尺寸差很多小目标样本如果太少模型容易漏检。YOLOv5 默认开的 mosaic 增强能缓解一部分但标注时不能因为蛋小、模糊就跳过去不标漏掉的框会被模型当成背景负样本学这是召回率上不去的隐藏原因。标注工具用 LabelImg 就行导出格式选 YOLO注意 class 编号从 0 开始。标注完跑一个几行代码的检查脚本能拦住九成格式错误import os for f in os.listdir(dataset/labels/train): with open(os.path.join(dataset/labels/train, f)) as fp: for line in fp: c, x, y, w, h map(float, line.strip().split()) assert 0 x 1 and 0 y 1, f{f} 中心点越界 assert w 0 and h 0, f{f} 宽高异常 assert 0 c 1, f{f} class_id 应为 0 print(标注检查通过)这个脚本能抓出坐标越界、宽高为负、类别编号错位这三类高频问题每次标注完先跑一遍再进训练流程。5. 避坑排查这套资源复现过程中的五个真问题5.1 模型加载翻车现场反复下载、权重路径错、显存不足现象 1torch.hub.load每次运行都提示 Downloading而且换过best.pt后加载的却还是旧权重。 原因torch hub 对模型结构代码和权重文件的缓存策略不一样当缓存目录里已有同名权重文件时force_reloadFalse不会重新下载。你换了新权重但文件名没变缓存命中的就是旧文件。 解决换权重时把force_reload改成True或者删掉~/.cache/torch/hub下对应目录再运行。路径参数建议用绝对路径省掉后面所有相对路径的心智负担。现象 2报错No such file or directory: weights/best.pt。 原因当前工作目录不在项目根目录相对路径解析失败。终端里在哪个目录运行脚本weights/best.pt就相对于哪个目录去解析。 解决在脚本开头加两行import os os.chdir(os.path.dirname(os.path.abspath(__file__)))强制以脚本文件所在目录为基准之后所有相对路径都稳了。现象 3显存溢出CUDA out of memory。 原因批量检测时没有用torch.no_grad()包裹推理过程仍在构建计算图张量累积导致显存被吃满。 解决推理逻辑外面套with torch.no_grad():或者每处理一批后调用torch.cuda.empty_cache()。实在不行把size从 640 降到 480显存占用是平方关系下降。5.2 界面与性能的坑卡死、低帧率、检测框抖动现象 1点「开始检测」按钮后窗口转圈系统提示「未响应」。 原因推理在按钮的槽函数里直接执行阻塞了 Qt 主线程的事件循环。Qt 界面的一切刷新、点击、绘制都依赖事件循环主线程卡住整个窗口就死了。 解决第 3 章的DetectThread方案。把推理放到 QThread 的run()里跑通过信号把帧传回主线程。这是 PyQt 加 YOLO 的通用解法不光是这套资源任何检测类 GUI 都应该这么写。现象 2视频和摄像头检测 FPS 只有 3~5画面一卡一卡。 原因每帧都跑 640 推理加render()画框CPU 机器根本扛不住。 解决跳帧策略——每 2~3 帧推理一次中间帧直接复用上一帧的检测结果人眼几乎感知不到延迟差异。或者把size降到 480速度提升明显代价是小目标召回率稍微下降。现象 3检测框在前后帧之间乱跳鸡蛋计数忽多忽少。 原因单帧检测是独立的置信度在阈值边缘的帧同一颗蛋时而检出时而漏掉框的位置也因为轻微抖动在变化。 解决做一个轻量级的 EMA 平滑。对连续帧的检测结果做 IoU 匹配匹配上的框用0.7 * 旧坐标 0.3 * 新坐标更新置信度同理。几十行代码的事但画面稳定感提升非常明显是界面演示效果的关键。5.3 训练与数据的坑标注漏检、类别号错位、预训练权重不匹配现象 1训练一切正常但验证时 precision 很高、recall 极低。 原因标注时漏标了大量蛋。漏标的框在训练数据里相当于把目标区域标成了背景模型学到的是「这些看起来像蛋的区域其实是背景」于是它越来越保守。 解决抽查 labels 目录和 images 目录的数量比例肉眼过一遍标注覆盖率。宁可多标不要漏标这个原则在数据量小的时候尤其重要。现象 2训练开始时直接报类别数不匹配。 原因egg.yaml里nc: 1但某个 txt 标注文件里出现了class_id1或更大值。坐标和类别解析失败后 YOLOv5 会直接跳过或报错。 解决跑一遍 4.3 小节的标注检查脚本class_id 强制从 0 开始并且核验 yaml 里的nc与数据集实际类别数一致。现象 3用下载的best.pt作为--weights继续训练loss 异常震荡。 原因best.pt是在这个鸡蛋数据集上收敛过的模型类别数、数据分布都和你的训练配置绑定继续训练等于在一个已经收敛的解上做微调梯度方向混乱。 解决二次训练统一用官方预训练权重yolov5s.pt起步。如果真的想做增量训练--weights改用runs/train/exp/weights/last.pt并且确保nc一致。6. 把检测结果接到业务流程导出 CSV、验证基线、最后一道自检界面能跑通、模型能出框之后最后一步是把检测结果从「屏幕上的框」变成「业务系统能消费的数据」。最常见的出口是 CSV。import csv import time df results.pandas().xyxy[0] df[ts] time.time() # 打上时间戳后面按时间段统计个数 df.to_csv(detect_result.csv, indexFalse, encodingutf-8-sig)utf-8-sig这个编码值得注意不写它的话 CSV 用 Excel 打开会乱码这是 Windows 生态下最隐蔽的小坑。然后做一个验证基线。拿dataset/images/val里的验证图批量跑一遍推理统计三个数字平均每张图检测出几个蛋、平均置信度是多少、单帧推理耗时多少毫秒。这三个数字记录下来作为基线。以后你改任何配置——置信度阈值、IoU 阈值、输入尺寸、平滑策略——都拿新的数字和基线对比好与坏一目了然。指标工具参考mAP0.5val.py以资源 README 为准单帧耗时timeit统计低于 50ms 算流畅平均每图检出数CSV 统计与人工清点对照最后一道自检按这个顺序过一遍CLI 推理能出框 → GUI 界面能显示 → 所有路径改成绝对路径 → 视频和摄像头通道各测一遍 → 备份好best.pt。这套顺序是我踩坑踩出来的——早期做检测项目时习惯跳过 CLI 直接开界面结果花了一整天排查才发现是路径问题。从那以后我每次拿到这类检测资源都强制走一遍固定流程先看目录、再跑命令行、最后才开 GUI界面一律用线程跑推理权重路径写绝对路径。这套流程帮我少踩了至少一半的坑。YOLOv5 鸡蛋检测这套资源如果符合你的场景下载后照着第 2 章的链路跑一遍两小时内看到效果问题不大。希望帮到你。本文还有配套的精品资源点击获取