尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

牛脸识别检测全流程实战:从YOLO检测到多帧投票的智慧畜牧方案

发布时间:2026/9/28 17:19:58

资讯中心
01
ARTICLE

牛脸识别检测全流程实战:从YOLO检测到多帧投票的智慧畜牧方案

牛脸识别检测全流程实战:从YOLO检测到多帧投票的智慧畜牧方案
简介本资源面向深度学习目标检测初学者与计算机视觉方向的学生、开发者提供一套基于YOLOv5算法实现牛只识别检测的完整工程方案可用于畜牧场景下的目标计数、行为分析与智能养殖研究。压缩包共79个文件约42.58MB涵盖py源码、yaml配置、pt权重、pyc缓存、sh脚本及dockerfile等并附有训练与推理所需的模型文件、依赖清单和详细使用说明。资源内含迭代200次的训练结果配套loss下降曲线、Recall召回率曲线、Precision精确度曲线及mAP等评估指标图模型拟合效果较好训练集包含4000多张图片、8000多个“牛”目标数据分布均匀便于复现与二次调参。目前已有273人学习浏览读者可据此快速搭建检测流程、理解YOLOv5训练与评估细节并借助曲线图判断模型收敛情况适合作为课程设计、毕业设计或算法入门的实践参考。1. 牛脸识别到底难在哪从一段牧场视频说起牧场里给牛做身份登记传统做法是打耳标、绑项圈或者干脆靠人拿本子记。耳标会掉、会磨损项圈成本高还容易被蹭掉人工记录更不用说几百头牛转一圈下来认错、漏记是常事。牛识别检测这套方案要解决的就是让摄像头拍到的每一头牛自动对应到它的身份编号——不接触、不打扰、全天候。它属于深度学习视频分析里比较典型的「检测 识别」两段式任务先用目标检测把画面里的牛框出来再对每个框做身份比对。适合谁做智慧畜牧的工程团队、想拿真实场景练手深度学习的学生、以及手里已经有牧场监控视频、想验证能不能跑通识别链路的开发者。这个方向值不值得投入关键看你能不能把检测精度、身份库维护和视频流吞吐这三件事同时压住下面我按自己踩过的路子拆开讲。2. 视频分析链路拆解检测、跟踪、识别三段怎么接2.1 为什么不能一步到位做「牛脸分类」很多人第一反应是把牛脸裁出来直接丢进一个分类网络输出牛编号不就完了我一开始也这么想结果翻车。原因是视频里牛是动的分类网络要求输入是「已经对齐好的单张脸」而原始帧里牛可能侧身、低头吃草、被别的牛挡住。你没法保证每一帧都能裁出一张正脸。所以工业上常见的做法是拆成三段目标检测负责「哪里有牛」多目标跟踪负责「这头牛从上一帧到这一帧是同一头」识别模块负责「这个框属于哪一头牛」。三段解耦的好处是每一段可以单独换模型、单独调参出问题也好定位——是漏检了还是跟踪 ID 跳变了还是识别库匹配错了一眼能看出来。2.2 检测段YOLO 系列在牛体检测上的取舍检测段我一般用 YOLO 系。标题里带「视频分析」就意味着要跑连续帧速度比单张图更重要。YOLO 的推理速度在同类里属于能打的而且导出 ONNX 之后部署路径清晰。牛体检测和行人检测不一样的地方在于牛的目标框长宽比更接近方形甚至横向而且牛群密集时框会大量重叠。所以锚框anchor尺寸要重新聚类不能直接用人脸或 COCO 的默认值。下面是我常用的一个检测推理骨架重点是输入尺寸和置信度阈值的处理。import cv2 import numpy as np import onnxruntime as ort # 加载导出的 ONNX 检测模型providers 按机器实际情况选 session ort.InferenceSession(cow_det.onnx, providers[CPUExecutionProvider]) input_name session.get_inputs()[0].name def preprocess(frame, size640): # letterbox 保持长宽比避免牛体被拉伸变形 h, w frame.shape[:2] scale size / max(h, w) nh, nw int(h * scale), int(w * scale) resized cv2.resize(frame, (nw, nh)) canvas np.full((size, size, 3), 114, dtypenp.uint8) canvas[:nh, :nw] resized blob canvas[:, :, ::-1].transpose(2, 0, 1).astype(np.float32) / 255.0 return np.expand_dims(blob, 0), scale def detect(frame, conf_thres0.45, iou_thres0.5): blob, scale preprocess(frame) preds session.run(None, {input_name: blob})[0] # preds 形状通常是 [1, N, 5类别数]按需解析 boxes, scores [], [] for p in preds[0]: score p[4] if score conf_thres: continue cx, cy, bw, bh p[:4] x1 (cx - bw / 2) / scale y1 (cy - bh / 2) / scale boxes.append([x1, y1, bw / scale, bh / scale]) scores.append(float(score)) idx cv2.dnn.NMSBoxes(boxes, scores, conf_thres, iou_thres) return [boxes[i] for i in idx], [scores[i] for i in idx]这段代码里三个参数最要命。size640是检测输入分辨率牛体在画面里占比小的时候要往上调但调大推理变慢得权衡。conf_thres0.45是置信度门槛牛群遮挡严重时调低会引入大量误检调高又漏检我一般从 0.4 开始试。iou_thres0.5控制重叠框合并牛挨得近的时候这个值要适当放大否则两头牛会被合并成一个框。预处理里的 letterbox 不能省直接 resize 会把牛拉变形检测框会飘。2.3 跟踪段给每头牛一个稳定的临时 ID检测只告诉你「这一帧有几头牛」不告诉你「这头牛是不是上一帧那头」。跟踪段就是补这个。常见做法是 ByteTrack 或 DeepSORT 这类基于检测的跟踪器。ByteTrack 的好处是不依赖外观特征纯靠运动预测和 IoU 匹配速度快DeepSORT 会额外算一个外观 embedding牛长得像的时候更稳但慢。牧场场景里牛的花色差异其实挺大我一般先用 ByteTrack 跑通如果发现 ID 频繁跳变再换 DeepSORT。跟踪输出的 track_id 是临时的只在当前视频片段里有效它的作用是让你能对同一头牛的多帧结果做投票而不是直接当身份用。2.4 识别段把 track 里的多帧结果聚合成身份识别段才是真正决定「这头牛是谁」的地方。我的做法是对每个 track_id抽取若干帧的牛体裁剪图送进一个特征提取网络比如 ResNet 或轻量化的 MobileNet 骨干得到每帧的特征向量然后对这个 track 的所有特征做平均或取中位数再和身份库里的注册特征做余弦相似度比对超过阈值就判定身份。这里的关键是「多帧聚合」——单帧识别很容易被姿态和光照带偏聚合之后稳定性明显提升。身份库的注册特征怎么来一般是每头牛提前拍几十张不同角度的图跑同一个特征网络取平均存成一个向量。新增牛只时补注册就行不用重训模型。3. 源码结构与环境配置从解压到跑通第一条视频3.1 拿到压缩包后先看什么这类「源码 模型文件 评估指标曲线 使用说明」的包解压后通常长这样一个src或code目录放训练和推理脚本一个weights或models目录放.pt/.onnx/.pth模型文件一个runs或results目录放评估曲线图loss 曲线、mAP 曲线、PR 曲线根目录一份 README 或使用说明。我拿到手第一件事不是急着跑而是先看模型文件的格式和输入尺寸再看评估曲线里的 mAP 数值和训练轮数判断这个模型是不是在合理的数据上训出来的。如果曲线里 loss 一直震荡不收敛或者 mAP 只有零点几那这个模型基本没法直接用得自己重训。3.2 环境配置版本对齐比装最新版重要深度学习环境配置是新手最容易卡住的地方。血泪经验不要盲目装最新版要按源码里requirements.txt或使用说明指定的版本来。下面是我常用的一个隔离环境搭建流程。# 创建独立环境Python 版本按说明来一般 3.8~3.10 比较稳 conda create -n cowid python3.9 -y conda activate cowid # 先装 PyTorch注意 CUDA 版本要和显卡驱动匹配 # 这里以 CUDA 11.8 为例具体按自己机器改 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 再装其余依赖 pip install -r requirements.txt # 验证 GPU 是否可用 python -c import torch; print(torch.cuda.is_available())torch.cuda.is_available()返回 False 是最常见的翻车点原因通常是 CUDA 版本和驱动不匹配或者装成了 CPU 版。解决办法是先nvidia-smi看驱动支持的 CUDA 上限再选不超过这个上限的 PyTorch 版本。另外requirements.txt里如果有opencv-python和opencv-python-headless同时出现会冲突留一个就行。3.3 跑通第一条视频命令行参数怎么给环境好了之后先用包里自带的示例视频或自己截一段跑通推理确认整条链路没问题。常见做法是提供一个inference.py或demo.py参数包括输入视频路径、模型路径、输出路径、置信度阈值。python inference.py \ --source ./samples/cow_test.mp4 \ --weights ./weights/cow_det.onnx \ --reid-weights ./weights/cow_reid.pth \ --conf 0.45 \ --output ./outputs/result.mp4--source可以是视频文件也可以是摄像头编号比如0。--conf就是前面说的置信度阈值第一次跑建议先用默认值看输出视频里框得准不准再决定调高还是调低。--output指定结果保存路径如果只想看不想存很多脚本支持--show参数直接弹窗。跑完先看输出视频框有没有漏、有没有把别的物体框成牛、同一头牛的 ID 有没有频繁跳。这三样没问题再往下做身份识别。4. 模型文件与评估指标曲线怎么判断这个模型能不能用4.1 模型文件格式与加载方式包里的模型文件可能是.ptPyTorch 原生、.pth权重、.onnx跨平台推理几种。.pt和.pth用 PyTorch 直接torch.load加载但要注意源码里定义的网络结构和权重是否对得上结构改了权重就加载失败。.onnx用 onnxruntime 加载跨平台部署方便但导出时的输入尺寸是固定的换分辨率要重新导出。我一般优先用.onnx做推理因为不依赖训练环境部署到别的机器上省事。4.2 评估指标曲线里该看哪几条评估指标曲线不是摆设它能告诉你这个模型是怎么训出来的。重点看三条训练 loss 曲线、验证 mAP 曲线、学习率曲线。loss 曲线如果一直下降但验证 mAP 不涨说明过拟合了mAP 曲线如果在某个点之后走平甚至下降说明再训也没用该早停。学习率曲线能看出用的是哪种调度策略余弦退火还是阶梯下降。下面这张表是我判断一个检测模型是否可用的经验阈值仅供参考具体场景要具体看。指标可用参考线说明mAP0.5大于 0.85牛体检测场景不极端的话这个线比较合理mAP0.5:0.95大于 0.6更严格反映框的定位精度推理单帧耗时小于 50ms视频分析要实时GPU 上一般能到身份识别 Top-1大于 0.9识别段单独评估和检测分开看如果包里的曲线显示 mAP 只有 0.5 左右别急着用大概率是训练数据太少或者标注质量差。这时候要么自己补数据重训要么只把这个模型当预训练权重在自己的数据上微调。4.3 用评估脚本复现指标光看曲线不够最好自己跑一遍评估脚本确认指标能复现。常见做法是包里带一个eval.py指定验证集路径和模型路径输出 mAP 和各类别 AP。python eval.py \ --data ./data/cow_val.yaml \ --weights ./weights/cow_det.onnx \ --img-size 640 \ --batch-size 8--data指向数据集配置文件里面写清楚验证集图片路径和类别名。--img-size要和推理时保持一致否则指标对不上。--batch-size按显存调显存小就调小。跑出来的数值如果和曲线里差很多先检查数据集划分是不是一样再看预处理有没有对齐。这一步能帮你确认模型文件没损坏、评估流程没写错。5. 避坑与排查牛识别检测里最容易翻车的五件事5.1 现象白天识别准晚上全乱原因训练数据几乎全是白天光照模型没见过夜间红外或低照度画面特征分布完全对不上。解决补夜间数据重训或者在推理前加一个低光增强预处理。如果牧场夜间用红外摄像头那训练集里必须包含红外图不能只靠可见光数据。5.2 现象同一头牛在视频里 ID 频繁跳变原因跟踪段 IoU 匹配阈值太严牛转身或短暂遮挡时匹配失败track 断裂。解决适当降低跟踪的匹配阈值或者换用带外观特征的跟踪器。另外检测框抖动也会导致匹配失败可以在检测后加一个简单的框平滑。5.3 现象识别段把两头花色相近的牛搞混原因特征网络区分度不够或者注册特征只用了单张图代表性不足。解决注册时每头牛多拍几个角度取平均识别时用多帧聚合而不是单帧。如果还不行考虑换更强的骨干网络或者加入牛脸局部特征。5.4 现象推理速度远低于预期原因模型没导出成 ONNX或者用了 CPU 推理或者输入分辨率给太大。解决确认torch.cuda.is_available()为 True导出 ONNX 并用 onnxruntime 的 GPU provider输入尺寸按实际需要调小。视频分析还可以抽帧处理不必每帧都跑。5.5 现象换一台机器模型加载报错原因PyTorch 版本不一致或者模型保存时用了torch.save(model)整个对象而不是state_dict。解决统一环境版本优先用state_dict保存和加载。跨平台部署直接上 ONNX能绕开大部分环境问题。6. 进阶技巧用抽帧 多帧投票把识别准确率再抬一档跑通基础链路之后想再往上提准确率我常用的一个技巧是「抽帧 多帧投票」。视频里同一头牛连续几十帧都在画面里没必要每帧都做识别隔几帧取一次把整个 track 的识别结果做投票票数最高的身份作为最终结果。这样做有两个好处一是省算力二是抗单帧噪声。具体实现上对每个 track_id 维护一个计数字典每识别一帧就给它对应的身份加一票track 结束时取票数最高的。from collections import defaultdict, Counter # track_votes: {track_id: [身份1, 身份2, ...]} track_votes defaultdict(list) def vote_identity(track_id, pred_identity, min_votes5): track_votes[track_id].append(pred_identity) # 票数不够先不判定避免早期误判 if len(track_votes[track_id]) min_votes: return None counter Counter(track_votes[track_id]) top_identity, top_count counter.most_common(1)[0] # 最高票占比过低说明识别不稳定返回未知 if top_count / len(track_votes[track_id]) 0.6: return unknown return top_identitymin_votes5是攒够 5 帧再判定太少容易误判太多则响应慢。0.6是最高票占比门槛低于这个值说明模型自己都拿不准宁可返回 unknown 也不要给错身份——牧场场景里认错牛比认不出牛麻烦得多。这个技巧配合前面的多帧特征聚合一起用识别准确率通常能再涨几个点。我自己做这类项目养成的习惯是先把检测和跟踪的稳定性调到位再动识别段因为前两段不稳识别段再怎么调都是白费。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。