养鸡场里数鸡,听起来像是个段子,但真到监控摄像头面前,你会发现这件事比想象中难得多。每只鸡进进出出、互相遮挡、羽毛颜色几乎一致,单靠传统图像处理想稳定区分个体,根本做不到。这套基于YOLOv8的鸡检测和跟踪系统,就是用深度学习把鸡从画面里准确框出来,再给每只鸡分一个稳定ID,把计数、轨迹跟踪和状态观察一起解决掉。整条链路包含YOLOv8深度学习模型、自制的鸡类数据集、Python开发环境、UI交互界面,以及最终产出的可供推理部署的模型文件,是一套可以完整落地的视觉项目,也适合想做目标检测和跟踪的初学者当成实战范本。
我最初接到这个需求时,对方只提了两个要求:一只一只地看清楚,别再人工点数。真做起来才发现,检测和跟踪之间还隔着数据标注、模型训练、算法调优、界面封装一整条链路。下面这篇内容,我会按照项目实际推进的顺序,把从数据采集到界面交付的每个环节拆开来讲,包括我踩过的坑和最后真正有效的做法。
1. 项目定位:一套鸡检测跟踪系统到底在解决什么
1.1 养殖场景里的三个真实需求
先说使用方的真实诉求。散养鸡舍和规模化笼养鸡舍,监控需求略有差异,但归纳起来绕不开三件事。
第一是自动计数。一场鸡舍盘点往往要两个人配合,一个数一个记,赶上鸡群到处跑,经常数到一半乱了套。监控画面里用检测模型实时统计画面内鸡只数量,并且通过跟踪算法避免重复计数,这件事直接省掉人力成本。
第二是异常行为观察。鸡如果生病、受惊或饲料不足,行为模式会变——吃食频率下降、活动范围缩小、长时间扎堆不动。跟踪系统能保留每只鸡的运动轨迹,再结合停留时间和移动速度,就能辅助管理者快速发现异常个体,不用靠饲养员凭经验去猜。
第三是密度监测与压堆预警。冬季鸡舍密闭,鸡群容易扎堆,挤压踩踏会造成损失。检测模型输出每帧的目标框,换算成区域密度后,超过阈值就可以自动提醒。这个功能在做鸡舍行为分析时非常重要,比人工盯监控可靠得多。
1.2 技术路线是怎么筛出来的
围绕上面的需求,我梳理过三条路线。
传统图像处理方案:背景建模、颜色阈值分割、轮廓检测。优点是不需要GPU、不需要数据集,但鸡是活物,光照一变、阴影一挡、羽毛颜色又接近背景,分割结果马上崩。只能说适合演示,不适合交付。
传统检测器方案:HOG特征加SVM、Haar级联之类的老方法,鸡的姿态多变、遮挡严重,特征表达力完全不够,同样放弃。
深度学习方案:自然落在YOLO系列上。YOLOv8在当前开源检测模型里属于实用性和易用性最平衡的选择——推理速度快、精度高、官方工程库封装得极其完善,训练一条命令就能跑起来,而且支持导出为ONNX或TensorRT格式,方便后续在不同设备上部署。
跟踪部分我在DeepSORT和ByteTrack之间犹豫过一段时间。鸡的外观特征高度相似,ReID模型很难把个体区分开,DeepSORT的核心优势在这里发挥不出来;反而是ByteTrack这种不依赖外观特征、纯靠运动和位置关联的方案,在实际鸡舍场景里更稳。关于这个取舍,后面第四章我会详细展开。
UI选择了Python生态里的PySide6。原因也很直接:开发效率高、控件生态完整、和OpenCV、YOLO工程库无缝配合,同时界面代码打包成Windows可执行程序也比较成熟。整个系统最终交付为:摄像头或视频文件输入,界面实时显示检测框、跟踪ID、数量统计和帧率信息。
2. 数据集准备:鸡数据从哪来、怎么标、怎么增强
2.1 视频抽帧、清洗与场景覆盖
模型效果上限不是算法决定的,而是数据决定的。这句话我每次做检测项目都要重复一遍——你在训练集里没见过的场景,模型泛化能力基本为零。
采集阶段我安排了两类点位。一类是正对鸡舍过道的侧面机位,视野广、能看到鸡群走动;另一类是安装在屋顶的俯视机位,用来覆盖拥挤场景和扎堆状态。两种视角下的目标尺度差异很大,侧面看到的鸡比较大,俯视看到的鸡比较小,这就要求训练数据里两类样本都要充足。
视频素材拿到之后做抽帧。我采用的策略是每秒钟抽1帧,避免连续帧高度相似导致数据冗余;如果画面里鸡群快速移动,也可以适当提高到每秒2帧。抽出来的图片要逐张人工过一遍,剔除严重模糊、超过一半目标被遮挡、或者光线过暗什么都没有的废图。
这里有一个很多人会忽略的点:场景覆盖一定要看全时段。白天自然光、傍晚黄昏、夜间红外补光这三种光照条件,必须按比例出现在训练集里。如果只采集白天数据,模型一遇到夜间红外画面,检测率会掉到你怀疑人生。
2.2 标注规范与工具选择
标注工具我用过LabelImg,也用过X-anylabeling,综合体验后者更顺手。它支持图像和视频直接标注,输出格式能导出YOLOv8需要的txt格式,也就是每个目标一行:
类别编号 中心点x/图片宽 中心点y/图片高 框宽度/图片宽 框高度/图片高类别方面我没有分公鸡母鸡、大鸡小鸡,全部统一为一个chicken类别。原因是在实际画面里,鸡的个体差异肉眼能看出来,但模型从像素层面很难学到稳定区分的特征,硬分只会让每个类别的样本量下降,精度反而更差。
标注细节上有几条经验:
- 边界框紧贴目标轮廓,不要留大块背景,也别把相邻的鸡框进同一个框里。
- 两只鸡重叠时,框可见部分的轮廓,不要凭想象去补全被遮挡区域。
- 标注框边缘误差尽量控制在5个像素以内,误差太大会直接干扰回归训练。
- 俯视图中密集的小鸡,宁可多花时间逐个标,也不要图省事框成一个大矩形。
初版数据集我保留了2500张有效图片,标注完成后做一次统计,检查每个时间段、每个机位的样本量是否均衡,不均衡的话针对性补采。
2.3 增强策略与数据集划分
数据增强解决的是样本多样性问题,我用的标配组合是:随机翻转、90度旋转、HSV色域扰动、随机缩放和裁剪,以及YOLOv8自带的mosaic增强。mosaic会把四张图拼成一张,强制模型学习不同场景下的目标特征,对小目标检测提升明显。
还有一个针对本项目场景比较关键的做法:把白天和红外的样本按比例混合后,再统一做一次灰度扰动。鸡舍里夜间补光会有明显偏色,模型在这种环境下容易把颜色特征当成主导,提前做通道扰动可以缓解这个问题。
划分比例我采用8:2,train 2000张、val 500张。划分时按照“同一段视频抽出的帧尽量分到同一侧”的原则,避免训练集和验证集之间出现相似度过高的数据泄漏,否则验证精度会虚高,一换新场景就现原形。
3. YOLOv8训练关键细节:参数选择、曲线观察与导出
3.1 环境与模型规格选择
环境配置是很多人卡壳的第一步。我整理的依赖大致长这样:
- Python 3.9以上
- PyTorch 2.x,CUDA版本根据显卡驱动对应安装
- 官方YOLOv8工程库
- OpenCV、NumPy、pandas等常规依赖
训练之前先把工程库跑一遍自带的小demo,确认环境闭环没问题,再开始正式训练。这一步能省下后面排查环境问题的大量时间。
模型规格对照,我在表里列一下实际感受:
| 模型 | 参数量 | 推理速度 | 精度表现 | 适用场景 |
|---|---|---|---|---|
| YOLOv8n | 约320万 | 最快 | 中等 | CPU实时、低功耗设备 |
| YOLOv8s | 约1110万 | 快 | 较好 | 项目最终选型 |
| YOLOv8m | 约2590万 | 中等 | 好 | GPU服务器、追求精度 |
| YOLOv8l | 约4370万 | 较慢 | 最好 | 离线高精度分析 |
我最终选择YOLOv8s作为主力模型,在6GB显存的显卡上跑得很从容,推理速度也足够带动实时视频流。如果部署端只有CPU,那就退到YOLOv8n,精度会有一定损失,但依然远好于传统方案。
3.2 训练参数含义与一次典型训练
YOLOv8的训练入口是命令行,我用的关键参数如下:
yolo detect train data=chicken.yaml model=yolov8s.pt epochs=200 imgsz=640 batch=8 device=0chicken.yaml是数据集配置文件,核心内容长这样:
path: datasets/chicken train: images/train val: images/val nc: 1 names: ["chicken"]几个关键参数的实际含义:
imgsz:训练分辨率。640是速度精度的平衡点,如果小目标漏检严重,可以试960,显存占用和训练时间会明显上升。epochs:我跑了200轮。数据量不大的情况下,150到200轮基本能收敛,再往后收益很小。batch:6GB显存跑YOLOv8s,batch设8比较稳。显存不够就降batch,不要硬扛。device:0表示第一块GPU,CPU训练就填cpu,但速度会慢到怀疑人生。
训练过程在工程库输出里能看到每个epoch的loss数值。我重点盯三个loss:box_loss是边界框回归损失,cls_loss是分类损失,dfl_loss是分布焦点损失,它们整体呈下降趋势就说明模型在正常收敛。
3.3 训练过程的观察与判断
训练完成后再跑一次验证命令,重点看这几个指标:
- precision(查准率):检测出来的框里确实是鸡的比例。
- recall(查全率):画面里实际的鸡被找出来的比例。
- mAP50:IoU阈值为0.5时的平均精度,项目落地主要看它。
- mAP50-95:更严格的综合精度指标。
实际训练中我见过一个典型情况:train loss持续下降,val loss在第140轮左右开始反弹,这就是过拟合信号。此时早停或者把epochs减掉,别硬拖到最后。
另外提一个很多新手容易慌的点:训练前期mAP会是0,这是正常的。模型还在学习阶段,等loss降到一定水平,mAP会突然跳变式上升,属正常现象。
3.4 模型导出与部署前验证
训练完成保留下来的就是专用的鸡类检测模型。继续下一步之前,先跑一遍图片验证,用模型自己的可视化结果看看检测框和置信度是否合理。这一步我发现过个别误检,比如鸡食盆被当成鸡,原因是标注阶段漏了这类负样本,后面补标注重新训练才解决。
推理测试没问题之后,模型导出为ONNX格式:
yolo export model=best.pt format=onnx half=Truehalf=True表示导出半精度,模型体积更小,推理速度更快。如果要进一步上TensorRT加速,再在ONNX基础上转换;这一步在后面的实时跟踪和UI环节里能让帧率肉眼可见地提升。
4. 从检测到跟踪:稳定ID分配的工程实现
4.1 为什么单帧检测不够用
YOLOv8处理单帧图片,输出的是这一帧里的检测框坐标、类别和置信度,它不关心前一帧那只是不是同一只。做实时统计时,如果没有跟踪,同一只鸡在连续帧里会被反复计数,完全没法用。
跟踪算法的本质,就是把相邻帧中属于同一个目标的检测框关联起来,给它们分配并维护同一个ID。这样每只鸡在画面上就有了稳定的身份,计数、轨迹记录、异常停留检测,全都基于这个ID展开。
4.2 DeepSORT和ByteTrack在实际鸡场景中的取舍
跟踪算法我实际对比了两个方案。
DeepSORT是经典的多目标跟踪方案,核心组合是卡尔曼滤波预测位置、匈牙利算法做帧间匹配、外加ReID外观特征辅助识别。它的外观模型在行人场景很有效,但鸡的外观特征高度相似,ReID模型的区分度极低,等于核心模块失效,安全剩下运动和位置关联,优势体现不出来。
ByteTrack走的是另一条路:不依赖外观特征,主要靠检测框之间的IoU和位置预测做匹配。它的特别之处在于,低置信度的检测框也会参与匹配,这对拥挤遮挡场景非常关键。
| 对比维度 | DeepSORT | ByteTrack |
|---|---|---|
| 外观ReID依赖 | 强依赖 | 完全不依赖 |
| 遮挡处理 | 中等 | 较好 |
| 工程复杂度 | 高,需要额外训练ReID | 低,检测器输出即可 |
| 鸡群场景实测 | 特征失效,ID易丢 | 稳定,速度快 |
最终我选了ByteTrack路线。实际运行效果也验证了这个判断,在鸡群互相遮挡的拥挤画面里,ByteTrack维持ID稳定的能力明显强于DeepSORT。
4.3 跟踪链路与参数调节
检测和跟踪的完整链路大致这样:
视频帧 -> YOLOv8检测 -> 过滤低置信度检测框 -> 跟踪器预测下一帧位置 -> 与当前帧检测结果匹配 -> 更新轨迹 -> 输出带ID的检测框代码结构上,我在入口处创建了一个全局跟踪器,视频流循环里先做检测,再把检测结果喂给跟踪器:
import numpy as np model = load_yolov8_model("chicken.pt") tracker = ByteTrack( track_thresh=0.5, match_thresh=0.8, track_buffer=30 ) for frame in video_stream: dets = model.predict(frame, conf=0.35, iou=0.7) boxes = dets.boxes.xyxy.cpu().numpy() confs = dets.boxes.conf.cpu().numpy() tracks = tracker.update(boxes, confs, frame.shape[:2]) for track in tracks: track_id = int(track.track_id) x1, y1, x2, y2 = track.tlwh # 实际API不同会略有差异 # 绘制检测框和ID跟踪器的三个关键参数,我实测下来的调节经验:
track_thresh:参与跟踪的检测框置信度门槛,设太低会引入大量噪声轨迹,设太高又容易漏掉真实目标。0.5起调。match_thresh:匹配阈值,越低匹配越宽松。鸡群拥挤容易ID切换时,适当调低这个值。track_buffer:目标丢失后轨迹保留的帧数。超过这个帧数还没重新匹配,轨迹就删除。我设了30,能扛住大部分短暂遮挡。
计数逻辑基于跟踪ID实现:维护一个已出现ID的集合,每当跟踪器生成新ID就计数加一,同一ID只记录一次,天然避免重复统计。
4.4 跟踪效果怎么看才靠谱
跟踪质量不能只看检测指标,要同时关注MOTA(多目标跟踪准确度)、ID Switch(身份切换次数)和FP/FN(误检/漏检)。我在验证集上重点观察两类场景:一是鸡群密集扎堆时ID会不会跳变,二是某只鸡被短暂遮挡后重新出现时还能不能找回原ID。
实测下来,ByteTrack最大的风险点在密集扎堆时两个目标几乎完全重叠,只有一只露出来,另一只的检测框会被抑制掉,跟踪就断了一次。这在养殖场景里很难完全避免,需要用遮挡感知策略去缓解,后面章节会提到。
5. UI界面:把算法封装成非技术用户也能用的工具
5.1 界面功能拆解
模型训练再漂亮,最终使用的人不会去跑命令行。整套系统能否交付,很大程度看UI是否顺手。
我设计的界面是经典三段式布局。
左侧是控制区:打开本地视频、打开摄像头、加载模型三个按钮,下方是置信度阈值滑块、IoU阈值滑块和跟踪参数输入框。右侧是信息区:实时帧率、当前画面检测数量、累计识别ID数量、轨迹提示。中间主区域是视频显示画布,检测框、跟踪ID、置信度全部叠加绘制在这块画布上。
文件选择用系统文件对话框,模型选择同样走对话框加载权重文件。阈值滑块做成实时联动,拖动时立刻生效,方便使用方在画面里直观看到检测灵敏度变化。
5.2 线程模型与实时刷新
UI最容易犯的错误是把推理循环直接塞进主线程,界面按钮直接卡死。正确的做法是把视频流读取和推理放到后台线程,UI线程只负责接收结果并刷新画面。
我用QThread管理推理线程,线程内部跑视频循环,每一帧检测完成后把图像转换好,通过信号发射给主窗口。转换代码核心就这几行:
def convert_cv_to_qimage(cv_img): rgb = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB) h, w, ch = rgb.shape bytes_per_line = ch * w return QImage(rgb.data, w, h, bytes_per_line, QImage.Format_RGB888)整个处理链路按顺序执行:取帧、YOLOv8检测、跟踪器更新、绘制框和ID、统计数量、图像格式转换、发信号给界面、界面刷新。主线程和推理线程之间用信号-槽机制通信,实测跑1080p视频时界面依然流畅,拖动进度条也不会有明显卡顿。
5.3 打包与交付细节
UI开发和调试完成后,打包成Windows可执行程序。这里有几个经验值得记录:
- PyInstaller打包时加上
--noconsole参数,避免运行后弹出黑色控制台窗口。 - 模型文件不要塞进代码里写死路径,用相对路径识别,否则换电脑就崩。
- 如果引用了ONNX等外部运行时,记得在打包时把相关动态库一起带上,否则目标机器上会报缺库错误。
- 打包完成后,在一台干净的机器上测试一遍全流程,确认不需要额外安装Python环境也能运行。
包装层界面让整套系统从“跑得通的脚本”变成了“能交出去的工具”。使用方不需要理解YOLOv8、不需要知道ByteTrack是什么,只需要打开界面、选个视频、看画面,就能直接使用。
6. 实测效果、踩坑记录与下一步扩展
6.1 实际精度、速度与部署结果
最终测试用的是三段不同场景的实测视频:白天散养鸡舍、夜间红外笼养鸡舍、午后强光户外场地。模型在验证集上的mAP50达到了0.94左右,mAP50-95在0.68上下,属于够用的水平。
速度方面,使用YOLOv8s加TensorRT加速,1080p视频在主流显卡上推理耗时约15毫秒每帧,加上跟踪和绘制,整个管线稳定跑在35帧以上。CPU上跑YOLOv8n,帧率在12到15帧之间,虽然能看但是体感会卡。
夜间红外场景初版表现不佳,检测率只有白天的一半左右。补采了300张夜间样本重新训练后,夜间检测率提升到了接近白天水平。这个结果让我更加确认:场景覆盖是检测精度最大的杠杆。
6.2 高频踩坑与解决方案
顺着项目推进顺序,把踩过的坑集中列一下:
| 问题现象 | 根本原因 | 解决方式 |
|---|---|---|
| 小鸡苗漏检严重 | 目标尺寸太小,640输入下特征不足 | 提高imgsz至960,或降低摄像头安装高度 |
| 鸡食盆被识别成鸡 | 负样本缺失 | 收集并标注不含鸡的画面,加入训练集 |
| 扎堆时ID频繁切换 | 目标重叠导致检测框互相抑制 | 调低match_thresh,提高track_buffer |
| 夜间画面检测率低 | 数据光照分布不均衡 | 补齐夜间样本后重新训练 |
| 密集拥挤时漏检 | 非极大值抑制过强 | NMS阈值调至0.3~0.4,优先保住重叠框 |
| 界面拖动卡顿 | 推理阻塞主线程 | 改QThread后台推理,信号-槽传帧 |
其中NMS阈值这个坑最隐蔽,默认的0.7在人群和车流场景挺好用,但鸡群扎堆时目标框大量重叠,阈值太高的结果就是只保留一个框,其余全部被抑制。调低之后漏检明显减少,代价是个别目标会出现重复框,实际接受度反而更高。
6.3 从检测跟踪走向行为分析
这套系统跑通后,往行为分析延伸是顺理成章的。基于跟踪得到的轨迹数据,可以做吃食频次统计、区域停留时长分析、鸡群活跃度曲线,再结合场景密度图,就能实现自动压堆预警。如果能接入姿态估计模型,还可以进一步分析病鸡的站立、行走姿态异常,提前发现躺卧不起的个体。
我在实际使用中还发现,轨迹数据比单纯检测框有价值得多。比如某只鸡长期在角落徘徊,本来没有任何报警机制,但跟踪系统天然记录了它的轨迹历史,一旦设置“同一ID短时长内反复经过同一区域”这样的规则,就能自动标记异常。这个方向比单纯看数量统计更有管理价值,也是我希望继续深挖的部分。
另一个值得做的改进是模型蒸馏。YOLOv8s在CPU上实时性不够,通过让大模型教小模型的方式,把YOLOv8l的精度压缩到YOLOv8n的推理速度,这样整套系统未来就能脱离GPU,直接跑在普通工控机或者边缘终端上,部署成本会再降一个档次。