厨师帽检测数据集VOC转YOLOv5实战:2090张标注数据训练与避坑指南
简介本资源为面向计算机视觉开发者与目标检测学习者的厨师帽检测数据集采用Pascal VOC标注格式适用于餐饮后厨场景下的厨师帽佩戴识别、人员头部定位等任务可支撑YOLO系列等检测模型的训练与验证。压缩包共约2000个文件包含2090张jpg图片与2090个对应xml标注文件另附一份使用说明txt整体约174.79MB图片与标注一一对应便于直接接入主流训练框架。标注由labelImg完成采用矩形框方式涵盖chef hat与head两类其中chef hat标注框4174个、head标注框1553个类别分布清晰适合作为二分类检测任务的训练素材。目前已有1534人学习下载读者可据此快速搭建数据加载流程、验证标注质量并参考作者基于yolov5的演示视频理解实际检测效果为后厨合规检测等应用提供可复用的数据基础。1. 厨师帽检测数据集2090 张 VOC 标注能不能直接喂给 YOLOv5后厨监控里要判断厨师有没有按规定戴帽子靠人盯屏幕不现实落地时第一步往往不是选模型而是找一份标注干净、类别定义明确的厨师帽检测数据集。这次拆的是一份 Pascal VOC 格式的厨师帽检测数据集2090 张 jpg 图片配 2090 个同名 xml 标注文件类别只有两个chef hat 和 head。chef hat 一共 4174 个框head 1553 个框标注工具是 labelImg规则就是矩形框。它适合做后厨合规检测、明厨亮灶、食堂卫生巡检这类目标检测任务也适合刚接触 VOC 数据集、想拿真实标注练手 YOLOv5 或 YOLOv8 训练流程的人。数据集本身不承诺任何模型精度只保证标注合理这点在选型时反而要看清它给的是原料不是成品。2. VOC 格式拆解2090 张图怎么读、怎么核对、怎么转 YOLO2.1 先看清 VOC 的目录结构和 xml 字段Pascal VOC 格式不是单一文件而是一套约定图片放 JPEGImages标注放 Annotations两者文件名主干必须一致。这份数据集给的是 firc_chefhat_1819.xml 这类命名对应图片就是 firc_chefhat_1819.jpg。xml 里真正影响训练的是几个节点filename 记录图片名size 记录宽高和通道object 下面有 name、pose、truncated、difficult、bndbox。name 就是类别名这份数据里只会出现 chef hat 或 headbndbox 的 xmin、ymin、xmax、ymax 是左上角和右下角坐标单位是像素。常见做法是先写个脚本统计一遍确认图片数、xml 数、类别分布和框的合法性。不要一上来就转格式先核对能省掉后面很多玄学问题。import os import xml.etree.ElementTree as ET from collections import Counter ann_dir Annotations img_dir JPEGImages xml_files [f for f in os.listdir(ann_dir) if f.endswith(.xml)] jpg_files [f for f in os.listdir(img_dir) if f.endswith(.jpg)] print(xml 数量:, len(xml_files)) print(jpg 数量:, len(jpg_files)) cls_counter Counter() bad_boxes [] for xf in xml_files: tree ET.parse(os.path.join(ann_dir, xf)) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) for obj in root.findall(object): name obj.find(name).text.strip() cls_counter[name] 1 box obj.find(bndbox) xmin int(float(box.find(xmin).text)) ymin int(float(box.find(ymin).text)) xmax int(float(box.find(xmax).text)) ymax int(float(box.find(ymax).text)) # 越界或宽高为 0 的框要单独记下来 if xmin 0 or ymin 0 or xmax w or ymax h or xmax xmin or ymax ymin: bad_boxes.append((xf, name, xmin, ymin, xmax, ymax)) print(类别分布:, cls_counter) print(异常框数量:, len(bad_boxes))这段脚本做三件事统计 xml 和 jpg 是否一一对应统计两个类别的框数是否和简介里的 4174、1553 对得上找出越界或退化的框。参数上只需要改 ann_dir 和 img_dir 两个路径。如果类别分布对不上说明有 xml 缺失或重复如果异常框很多转 YOLO 之前要先决定是修正还是丢弃别直接带着脏框训练。2.2 转成 YOLO txt归一化坐标和类别映射YOLOv5、YOLOv8 吃的是每张图一个 txt每行是 class_id x_center y_center width height全部归一化到 0 到 1。VOC 给的是绝对像素坐标转换时要用图片宽高做除法。类别映射必须固定顺序比如 chef hat 映射成 0head 映射成 1写进 data.yaml 时顺序不能乱否则模型学出来的类别会整体错位。import os import xml.etree.ElementTree as ET classes [chef hat, head] # 顺序必须和 data.yaml 的 names 一致 cls_to_id {c: i for i, c in enumerate(classes)} ann_dir Annotations img_dir JPEGImages out_dir labels os.makedirs(out_dir, exist_okTrue) for xf in os.listdir(ann_dir): if not xf.endswith(.xml): continue tree ET.parse(os.path.join(ann_dir, xf)) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in cls_to_id: continue box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 归一化中心点和宽高 xc (xmin xmax) / 2.0 / w yc (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_to_id[name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) txt_name os.path.splitext(xf)[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines))转换逻辑里有两个容易翻车的点一是 xmax 和 xmin 的顺序labelImg 正常导出不会反但人工改过的 xml 可能反转换前最好加一层 min/max 保护二是归一化用的宽高必须来自 xml 的 size而不是想当然用固定尺寸这份数据图片尺寸未必统一。转换完成后labels 目录里的 txt 数量应该也是 2090少一个都说明有 xml 没被处理。2.3 划分训练集和验证集别让同一场景泄漏2090 张图不算大划分时最怕的是同一段视频或同一场景的连续帧被同时分进训练和验证导致验证指标虚高。常见做法是按 8:2 或 9:1 划分并且先按文件名排序再打乱避免原始顺序里隐含的采集批次。如果数据来自连续视频抽帧更稳妥的是按场景或时间段切分而不是纯随机。import os import random import shutil random.seed(42) img_dir JPEGImages lab_dir labels out_root dataset for split in [train, val]: os.makedirs(os.path.join(out_root, images, split), exist_okTrue) os.makedirs(os.path.join(out_root, labels, split), exist_okTrue) names [os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(.jpg)] random.shuffle(names) split_idx int(len(names) * 0.8) train_names names[:split_idx] val_names names[split_idx:] for split, subset in [(train, train_names), (val, val_names)]: for n in subset: shutil.copy(os.path.join(img_dir, n .jpg), os.path.join(out_root, images, split, n .jpg)) shutil.copy(os.path.join(lab_dir, n .txt), os.path.join(out_root, labels, split, n .txt))seed 固定成 42 是为了可复现实际项目里换 seed 多跑几次看指标波动也很有必要。划分完要检查 train 和 val 的类别分布是否接近如果 val 里 head 特别少验证指标会抖得厉害。data.yaml 里 train、val 指向这两个目录nc 写 2names 顺序和转换脚本保持一致。3. 拿这份数据训练 YOLOv5配置、参数和验证口径3.1 data.yaml 与模型选型YOLOv5 的目录约定是 images 和 labels 平行且路径里用 images 替换成 labels 就能找到标注。data.yaml 写清楚三个路径和类别即可。模型选型上2090 张图属于小数据集直接上 yolov5x 容易过拟合yolov5s 或 yolov5m 更稳先跑通再考虑换大模型。path: ./dataset train: images/train val: images/val nc: 2 names: 0: chef hat 1: head这里 nc 必须是 2names 的键值顺序要和前面 cls_to_id 完全一致。很多人转完格式发现模型把帽子识别成头八成就是这里顺序反了。path 用相对路径时训练命令要在 dataset 的上一级目录执行否则会报找不到图片。3.2 训练命令与关键参数python train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data data/chefhat.yaml \ --weights yolov5s.pt \ --project runs/train \ --name chefhat_exp1img 640 是常见起点如果原图分辨率远大于 640小目标 head 可能被缩得看不清可以试 960 但显存要够。batch 16 在 8G 显存上比较稳爆显存就降到 8。epochs 100 对小数据集够用重点看验证集 mAP 是否在后期还在涨如果 30 轮就平了加轮数意义不大。weights 用预训练权重比从头训收敛快得多这是小数据集的常规操作。训练过程中重点盯三个指标box_loss 是否稳定下降mAP0.5 是否在验证集上同步上升以及 chef hat 和 head 两个类别的 AP 是否差距过大。如果 head 的 AP 明显低通常是 head 框更小、遮挡更多可以考虑提高输入分辨率或做针对性增强。3.3 推理验证拿没参与训练的图看效果训练完不要只看指标要拿真实后厨图跑一遍。用 detect.py 指定权重和图片目录看输出的框和置信度。简介里提到有基于 yolov5 训练模型的演示视频且视频数据未参与训练这种留出视频做验证的思路是对的能看出模型在连续帧上的稳定性而不是只在验证集上好看。python detect.py \ --weights runs/train/chefhat_exp1/weights/best.pt \ --source test_images \ --img 640 \ --conf-thres 0.4 \ --save-txtconf-thres 0.4 是起步值漏检多就降到 0.25误检多就升到 0.5。save-txt 会把检测结果存成 txt方便后续统计。重点看两类错误把没戴帽子的人头误判成 chef hat以及把远处的帽子漏掉。前者影响合规判断后者影响召回业务上哪个更不能接受决定了阈值往哪调。4. 避坑与排查这份 VOC 数据集最容易翻车的五件事4.1 现象训练时提示找不到标签loss 一直是 nan原因通常是 images 和 labels 的目录结构不符合 YOLOv5 约定或者 txt 文件名和图片名主干不一致。VOC 转 YOLO 时如果 xml 里有 filename 和实际 jpg 名不同的情况按 xml 名生成 txt 就会对不上。解决方法是转换脚本里统一用 xml 文件名主干生成 txt并在划分后抽查几个样本确认 images/train 下的每张图在 labels/train 下都有同名 txt。4.2 现象模型把 head 识别成 chef hat或者两个类别混在一起原因基本是 data.yaml 的 names 顺序和转换时的类别映射不一致。VOC 里类别名是字符串YOLO 里是整数 id中间这层映射一旦错位模型学到的就是错的对应关系。解决方法是把 classes 列表和 data.yaml 的 names 放在同一处维护转换和训练都引用它改的时候一起改别两边各写一份。4.3 现象验证集 mAP 很高实际后厨图效果很差原因是训练集和验证集划分时同一场景泄漏或者验证集图片和训练集过于相似。2090 张图如果来自少数几个摄像头随机划分很容易让验证集变成训练集的近邻。解决方法是按摄像头或时间段分组划分保证验证集里的场景在训练集里没出现过这样指标才接近真实泛化能力。4.4 现象小目标 head 大量漏检原因是 head 的框普遍偏小缩放到 640 后像素太少。解决方法是提高训练和推理的 img 尺寸到 960或者在数据增强里减少缩放幅度也可以针对小目标单独统计 AP。不要指望只调置信度阈值能救回来漏检是特征层面的事阈值只能微调。4.5 现象xml 里有框但转出来的 txt 是空的原因是 bndbox 坐标越界或宽高为 0被转换脚本过滤掉了或者类别名带了多余空格导致匹配不上。解决方法是转换前先跑一遍统计脚本把异常框和未知类别名打印出来人工确认是修正坐标还是丢弃样本。带空格的类别名用 strip 处理别直接拿原始文本去查字典。5. 进阶技巧用这份数据做类别不平衡处理和阈值标定这份数据里 chef hat 有 4174 个框head 只有 1553 个比例接近 2.7:1属于轻度不平衡。直接训练时 head 的召回往往吃亏因为模型见到的 head 样本更少。我一般会先看两个类别的 AP 差距如果 head 明显低再考虑在损失里给 head 更高权重或者对含 head 的图片做重复采样。YOLOv5 本身没有直接的类别权重参数常见做法是复制含 head 的样本进训练集但要注意别把验证集里的图复制进去否则指标就假了。另一个实用技巧是阈值标定。业务上判断“有没有戴帽子”最终往往要落成一个二分类决策而不是看两个类别的框。可以拿验证集跑一遍推理统计不同 conf-thres 下 chef hat 的召回和误报画一条简单的权衡曲线选一个业务能接受的阈值。比如后厨巡检宁可多报也不能漏报就把阈值压低如果是自动抓拍处罚就要抬高阈值减少误报。这个标定过程比单纯看 mAP 更贴近落地。import os from collections import defaultdict # 假设 detect.py --save-txt 输出的每行是 cls xc yc w h conf pred_dir runs/detect/exp/labels gt_dir dataset/labels/val def load_gt(path): boxes defaultdict(list) for f in os.listdir(path): with open(os.path.join(path, f)) as fp: for line in fp: c, xc, yc, w, h line.split() boxes[f].append((int(c), float(xc), float(yc), float(w), float(h))) return boxes gt load_gt(gt_dir) # 统计每个阈值下 chef hat 的预测框数量和 gt 对比做召回估计 for thres in [0.25, 0.35, 0.45, 0.55]: total_pred 0 for f in os.listdir(pred_dir): with open(os.path.join(pred_dir, f)) as fp: for line in fp: parts line.split() if float(parts[5]) thres and int(parts[0]) 0: total_pred 1 print(f阈值 {thres}: chef hat 预测框数 {total_pred})这段脚本只是做数量级对比真正算召回还要做 IoU 匹配但先用它看趋势已经够用。参数上改 pred_dir 和 gt_dir 两个路径阈值列表按业务需要增减。跑完你会发现阈值从 0.25 提到 0.55预测框数量掉得很快这就是为什么不能拍脑袋定阈值。从那以后我每次拿到 VOC 数据集都强制先跑一遍统计脚本核对类别分布和异常框再转格式、再划分、再训练顺序一步都不省。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

History API导航埋点事件的幂等处理

History API导航埋点事件的幂等处理

直答:pushState、replaceState 不触发 popstate,只有前进后退才触发。导航埋点重复,多半是把路由变化在多个钩子里各报一次。幂等要做三层:队列去重、事件标识去重、服务端去重。先把事件模型拆开看,再谈怎么去重。单页…

2026/10/11 5:53:55 阅读更多 →
对话式AI记忆系统设计:从抽取、存储到召回的全链路工程实践

对话式AI记忆系统设计:从抽取、存储到召回的全链路工程实践

1. 从"claude-mem"这个名字说起:它到底想解决什么问题第一次看到"claude-mem"这个命名,我的直觉是:这是一个围绕对话记忆做文章的项目。拆开来看,"claude"指向的是对话式AI助手的交互场景&#xff…

2026/10/11 5:53:54 阅读更多 →
为何酒店行业要MCP,而不仅仅是API?

为何酒店行业要MCP,而不仅仅是API?

在 AI 圈聊 MCP,十篇有九篇在讲通用工具。今天换个视角,聊一个具体行业:酒店。 有个问题值得所有酒店 IT 和旅游科技从业者想想:酒店行业用 API 对接分销渠道已经二三十年了,OTA、GDS、直连,体系成熟得不能…

2026/10/11 5:53:54 阅读更多 →

最新新闻

Shardeum 网络升级指南:硬分叉与软分叉如何安全完成

Shardeum 网络升级指南:硬分叉与软分叉如何安全完成

Shardeum 网络升级指南:硬分叉与软分叉如何安全完成 【免费下载链接】shardeum Shardeum is an EVM based autoscaling blockchain 项目地址: https://gitcode.com/GitHub_Trending/sh/shardeum Shardeum 是一个基于 EVM 的自动扩容区块链(autosc…

2026/10/11 9:06:46 阅读更多 →
多语言食堂供餐系统实战:Java/JS/Python/C实现对比与避坑指南

多语言食堂供餐系统实战:Java/JS/Python/C实现对比与避坑指南

这道题我在实训平台上刷到过不止一次,新卷、满分100分、食堂供餐,四个语言一起上。第一次看到“Java & JS & Python & C”这个组合的时候,我心想这不就是同一个业务用四种语言各写一遍吗,能有多难。真正动手才发现&am…

2026/10/11 9:06:46 阅读更多 →
基于Spark和Hive的地震数据分析与预测系统

基于Spark和Hive的地震数据分析与预测系统

1. 这个课题到底值不值得做:先看清楚里面的门道每年毕业季前后,后台总能看到一批类似"地震预测系统""大数据毕业设计"的热搜词。说实话,这类题目在计算机毕设里属于一眼能看出价值、但很多人做一半就放弃的类型。原因无外…

2026/10/11 9:06:46 阅读更多 →
2026论文AI工具终极排名⚡定稿/盲审/答辩保命版!别再用错翻车

2026论文AI工具终极排名⚡定稿/盲审/答辩保命版!别再用错翻车

2026届注意!!现在AI论文工具不是谁好用就用谁,是谁安全用谁😭今年高校严查:AIGC标记、文献造假、逻辑漏洞、模板化严重、前后内容矛盾。很多同学初稿写得很好,最后栽在「工具选错」上!不吹不黑、…

2026/10/11 9:06:46 阅读更多 →
YOLOv8路面裂缝检测系统:轻量化部署与中英文双语工程实践

YOLOv8路面裂缝检测系统:轻量化部署与中英文双语工程实践

1. 项目概述:为什么一个“路面裂缝检测系统”值得花两周时间重做三版?YOLOv8、路面裂缝、中英文双版、完整源码、效果演示——这五个词凑在一起,不是某高校课程设计的应付作业,而是我在去年接手某市政养护平台升级任务时&#xff…

2026/10/11 9:06:46 阅读更多 →
200Gb/s以上速率的通道信号完整性设计和优化经验(二)

200Gb/s以上速率的通道信号完整性设计和优化经验(二)

200Gb/s通道信号完整性要求 A) PCB设计 通道插入损耗指标,源于布线物理需求:如图 1 (a)所示,在 1 机架单元(RU)服务器内,需要从 ASIC 交换机四周引出 1024 对差分信号对,并连接至服务器前面板。 PCB 设计(包括垂直过孔结构以及各层图形化传输线)占据了损耗预算的绝大…

2026/10/11 9:05:46 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →