
简介厨房积水检测数据集面向计算机视觉目标检测方向的开发者与学习者聚焦厨房场景中泡沫foam和积水water两类目标的识别可服务于家庭安全监控、餐厅后厨卫生管理以及清洁机器人环境感知等实际需求。数据集中包含88张真实厨房图片每张图片均配有Pascal VOC格式的xml标注与YOLO格式的txt标注标注工具为labelImg全部采用矩形框准确标出目标两类目标框数合计562个覆盖不同光照与角度下的积水/泡沫形态。压缩包共268个文件以jpg原图、xml和txt标注文件为主另有少量ini配置整体仅18.23MB非常轻量下载后可直接用于训练YOLO系列、Faster R-CNN等模型也可作为数据增强或迁移学习的基础数据集。当前已有161人学习下载规模小而规范十分适合快速开展检测算法实验与教学演示。1. 厨房积水检测的88张双格式数据集能做什么、适合谁拿到这份“厨房积水检测数据集VOCYOLO格式88张2类别.7z”第一反应通常是两个88张图太少2个类别太简单。实际跑过积水检测的人都知道厨房地面的水渍是典型难样本——白色瓷砖反光像水、拖把湿痕像水、调料汁晾干后也像水传统颜色阈值方案在这种场景里几乎必翻车而目标检测要解决的恰恰是“从干扰里把真正的积水框出来”。这份数据集的定位不是让你刷出一个惊艳的mAP而是用88张带精准框的图把“图片→标注→训练→验证”整套链路跑顺顺便验证积水这一特定目标在迁移学习下的收敛表现。适合两类人刚接触YOLO、不想从零标数据的学习者以及要做厨房积水预研、需要先拿小样本验证模型选型的工程师。双格式是它最值得利用的地方——VOC方便回看和二次标注YOLO直接喂训练两边对齐之后能少踩很多暗坑。2. 拿到.7z先不乱双击安装7z、解压并核对文件清单2.1 安装7z而不是双击解压Linux和Windows的正确打开方式这个压缩包的后缀是.7z不是.zip系统自带的解压工具大概率处理不了。常见做法是装p7zipLinux下一条命令的事sudo apt update sudo apt install -y p7zip-full先执行apt update再装是为了避免装到旧版本。老版本p7zip对部分使用新压缩算法的包会直接报Unsupported Method明明文件没坏却解不开。CentOS/RHEL系用sudo yum install -y p7zip需要先开启EPEL源。Windows用户安装7-Zip官方版本安装时勾选“关联.7z文件”之后右键就能解压。macOS用户用brew install sevenzip命令行工具会安装为7zz。“双击解压”这个习惯在数据集场景里是有风险的尤其是包内含大量小文件时图形工具中途报错不会给详细位置。我更习惯命令行操作至少能看到在哪一步失败。安装完成后验证一下7z | head -5如果能打印出版本和命令用法说明安装无误。Linux下装完p7zip命令名通常是7z如果提示找不到试7za或7zr这两个是精简版功能少一些但解压这个包够用。2.2 用7z t和sha256sum验证压缩包完整性很多人拿到压缩包第一件事就是解压这是错误顺序。压缩包在传输过程中可能截断、损坏或者下载工具把文件改名直接解压到一半报错你还会误以为是数据集本身有问题。正确做法是先测完整性7z t kitchen_water.7z7z t会逐个文件校验CRC输出Everything is Ok才算通过。这一步跑完再解压。厂商或分享方如果提供了sha256校验值也应该先算一下sha256sum kitchen_water.7z把输出结果和包附带的checksum文件对比。如果包内自带checksum.sha256直接用-c参数sha256sum -c checksum.sha256显示OK代表哈希匹配。这一步看起来多余但对小数据集尤其重要——88张图本身不大一旦其中某张图片在打包时损坏训练初期不会暴露跑到几十轮后偶然读到那张图loss直接崩掉排查成本远高于提前校验的成本。坏的压缩包是“后悔药”都救不回来的删掉重新下载才是正道。2.3 解压后先数文件目录结构与数量核对校验通过后正式解压区分两个命令7z x kitchen_water.7z -o/home/yourname/datasets/kitchen_water 7z e kitchen_water.7z7z x保留压缩包内的完整目录结构数据集必须用它7z e会把所有文件平铺解压到当前目录适合只想要其中一两个文件的场景。注意-o参数后面紧跟目标路径不能有空格这是新手常踩的坑。解压完成后建议立刻核对目录结构和文件数量find images -type f | wc -l find labels -type f | wc -l如果解压出来的是一个VOC风格目录就把images换成JPEGImages、labels换成Annotations再统计。88张图对应两份标注图片数和标签数应该完全一致多一个文件都要警惕。我见过不少数据集包解压后混入Thumbs.db、.DS_Store之类的系统文件训练脚本遍历目录时会把它们当图片读然后报“无法解码图像”。数完文件再看一眼有没有README、类名说明或labelmap文件这些文件决定了后续标签映射怎么配。3. 两份标注怎么衔接VOC转YOLO的坐标换算与类名对齐3.1 VOC XML与YOLO txt的坐标换算关系VOC格式和YOLO格式的本质区别只有一个坐标表示方式。VOC用像素绝对坐标YOLO用归一化相对坐标。VOC的标注文件是XML核心结构是这样的annotation filenamekitchen_001.jpg/filename size width1280/width height720/height /size object namewater/name bndbox xmin320/xmin ymin180/ymin xmax900/xmax ymax520/ymax /bndbox /object /annotation单个目标对应一个object节点框的四个角是像素坐标。YOLO格式则是一个图片一个txt文件每行描述一个目标格式是class_id cx cy w h其中cx和cy是中心点坐标w和h是框宽高全部除以图片宽高做归一化。换算关系如下项目公式中心点x(xmin xmax) / 2 / 图片宽中心点y(ymin ymax) / 2 / 图片高框宽w(xmax - xmin) / 图片宽框高h(ymax - ymin) / 图片高需要特别注意的是转换后所有值都应在0到1之间。如果出现大于1或小于0的结果说明XML里的size和实际图片像素尺寸对不上通常是标注工具改过图片尺寸但没同步XML这时候要回头检查原图。3.2 用Python脚本把VOC转成YOLO这个数据集既然同时给了两种格式理论上不需要自己转换。但实际使用中你往往会修改标注、合并类别或者从别的数据集迁移标签所以保留一份转换脚本比直接信任现成文件更可靠。下面这个脚本专门处理VOC转YOLOimport xml.etree.ElementTree as ET from pathlib import Path voc_dir Path(Annotations) # VOC XML所在目录 yolo_dir Path(labels) # YOLO txt输出目录 yolo_dir.mkdir(exist_okTrue) # 类别到id的映射必须和解压后查看的类名定义保持一致 class_to_id {water: 0, reflection: 1} for xml_path in voc_dir.glob(*.xml): tree ET.parse(xml_path) root tree.getroot() # 优先读xml里的size不要用cv2重新读图 size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_to_id: print(f未知类别: {name}, 文件: {xml_path.name}) continue bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) cx ((xmin xmax) / 2) / img_w cy ((ymin ymax) / 2) / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{class_to_id[name]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) out_path yolo_dir / (xml_path.stem .txt) out_path.write_text(\n.join(lines), encodingutf-8)这段脚本的逻辑并不复杂但有三个参数值得解释。class_to_id必须与你数据集包内的类名严格一致这是“2类别”最容易出错的地方——你以为只有两个类结果XML里出现了第三个类名的拼写变体脚本就静默跳过了那个框。所以遇到未知类别时不要忽略而是去确认这个标签定义。img_w和img_h优先取XML里的size而不是用cv2.imread重新读图因为标注时的原始尺寸可能和当前图片不一致二次resize会让坐标整体偏移。fmt里的.6f是六位小数精度回读和训练都足够没必要保留太长。3.3 转换后回读校验标签数量和类名对齐转换完不等于可以训练。我习惯立刻做两步回读校验这能提前暴露90%的标签问题。先统计每个类别框的数量for f in labels/*.txt; do awk {print $1} $f; done | sort | uniq -cawk {print $1}取出每行第一个字段即类别idsort | uniq -c按id聚合计数。输出应该看到两类各若干行如果只出现一个数字说明另一个类几乎没框或全部被脚本跳过了88张图的小数据集里类别极度不均衡直接训练会导致少数类完全学不到特征。第二步写一个简单的回读检查把YOLO的归一化坐标乘以图片尺寸反算像素坐标验证是否在画面范围内from pathlib import Path import cv2 for txt_path in Path(labels).glob(*.txt): img_path Path(images) / (txt_path.stem .jpg) img cv2.imread(str(img_path)) if img is None: print(f图片缺失: {img_path}) continue h, w, _ img.shape for line in txt_path.read_text(encodingutf-8).strip().splitlines(): cid, cx, cy, bw, bh map(float, line.split()) x1, y1 (cx - bw / 2) * w, (cy - bh / 2) * h x2, y2 (cx bw / 2) * w, (cy bh / 2) * h if not (0 x1 x2 w and 0 y1 y2 h): print(f坐标越界: {txt_path.name}, 行: {line})这段回读有一个关键设定图片文件名的stem必须和txt完全一致任何一个文件对不上都应该停下来检查而不是继续训练。很多“训练时大量图片没有标签”的报错根源就是这一步没做。4. 把88张图喂给YOLO数据划分、增强参数与预训练选取4.1 88张图的train/val划分固定种子与文件一一对应88张图做目标检测属于“小样本量里的常规量”划分策略直接影响结论可信度。只分train和val不再单独分test测试集留到最终验收时另找真实场景图。划分脚本如下import random import shutil from pathlib import Path random.seed(42) images list(Path(images).glob(*.jpg)) labels [Path(labels) / (img.stem .txt) for img in images] # 只保留图片和标签同时存在的样本 pairs [(img, lab) for img, lab in zip(images, labels) if lab.exists()] random.shuffle(pairs) split int(len(pairs) * 0.8) train_pairs pairs[:split] val_pairs pairs[split:] for split_name, pair_list in [(train, train_pairs), (val, val_pairs)]: img_dst Path(dataset) / images / split_name lab_dst Path(dataset) / labels / split_name img_dst.mkdir(parentsTrue, exist_okTrue) lab_dst.mkdir(parentsTrue, exist_okTrue) for img_path, lab_path in pair_list: shutil.copy2(img_path, img_dst / img_path.name) shutil.copy2(lab_path, lab_dst / lab_path.name)这里用copy2而不是move是因为88张图的原始包最好保持原样后续重新划分或者增强失败时能回到起点这是给自己留的后悔药。random.seed(42)固定随机序列保证每次运行划分结果一致否则你调了几轮参数后发现跑的不是同一批验证集对比就没有意义。80/20的比例在88张下大约是70/18验证集偏小但能接受如果误差大可以改成75/25以验证图片数量不低于15张为底线。4.2 数据集yaml与yolov8训练命令Ultralytics YOLO训练时读取一个yaml文件描述数据位置和类别数这是处理数据集用于yolov8训练的关键配置。在项目根目录建一个kitchen_water.yamlpath: /home/yourname/datasets/kitchen_water train: images/train val: images/val nc: 2 names: 0: water 1: reflectionpath是数据集绝对路径train和val是相对path的子目录。names的顺序必须和标签txt里的第一个数字对应YOLO只认数字索引不认字符串。标题只说明2类别具体类名以压缩包内labels对应关系为准我这里写的water和reflection只是占位示例。训练命令用Ultralytics CLI一条命令跑通yolo detect train \ datakitchen_water.yaml \ modelyolov8n.pt \ epochs150 \ batch16 \ imgsz640 \ patience30 \ lr00.001 \ seed42 \ close_mosaic10modelyolov8n.pt表示从COCO预训练权重yolov8n.pt开始微调这是88张小数据集最务实的起点。Ultralytics在首次运行时会自动获取对应预训练权重不需要手动下载。epochs150看似多小数据集收敛慢前50轮可能都在适应新目标域。batch16在显存低于8G时降到8但不要低于4否则BatchNorm统计量不稳定。lr0我习惯压到0.001默认0.01在数据量小时容易震荡。4.3 小数据集的增强参数flipud真的别开数据增强是小数据集的关键但无脑全开就是翻车现场。这里涉及一个物理常识水受重力影响向下流动和积聚把图片垂直翻转后再检测积水形态在语义上就失真了。所以flipud垂直翻转建议设为0fliplr水平翻转大胆开到0.5。其他增强参数参考这个基调参数建议值说明fliplr0.5水平翻转厨房左右布局对积水无影响flipud0.0垂直翻转会改变水流方向不开hsv_h0.015色调轻微扰动即可过大导致灯光颜色失真hsv_s0.3饱和度可适当调大增强泛化hsv_v0.3亮度扰动模拟不同照明mosaic1.0前中期开后期用close_mosaic关闭close_mosaic10最后10个epoch关闭mosaic避免拼图假目标mosaic增强在训练后期会引入大量拼接边界让模型误把“拼缝”当积水边缘close_mosaic10在最后10轮切回原始图让模型收敛到真实分布。这些参数都不是玄学而是在积水这个特定目标下的物理约束。另一个小技巧是关注训练日志里的cls_loss和box_loss这两个损失能反应框回归和分类是否正常val loss波动大是正常现象不要因此频繁中断。5. 2类小数据集的常见坑bn崩溃、混淆矩阵与标注回读5.1 训练中bn崩溃loss变成nan的三种原因现象训练前30轮loss正常下降某一轮突然变成nan之后所有batch的输出全是nan保存的模型权重完全不可用。这是小数据集训练里最典型的中途翻车。原因有三个层级。第一学习率过大batch内梯度更新跨度过大导致数值溢出88张图只有约70张参与训练数据分布方差大默认0.01的学习率很容易中招。第二BatchNorm在小batch下统计量崩坏——batch4甚至batch2时单批均值和方差抖动剧烈BN层的running mean会逐轮漂移最终输出nan。第三mosaic增强最后没关拼接图像中的空边和纯色块生成大量异常梯度。解决把lr0降为0.001batch提到8以上并在命令里加close_mosaic10。同时固定随机种子seed42让失败可复现、修复可对比。如果nan仍然出现将model从yolov8s.pt降到yolov8n.pt小数据集不需要大模型。5.2 标签读不进来class index、路径与空格现象训练刚开始就报Dataset not found或者能读图但提示class index out of range更多时候训练能跑完但验证集的mAP恒为0。原因yaml里path路径写错是最常见的Windows下路径里有中文或空格或者解压后目录嵌套了一层实际路径和yaml不一致。class index out of range则说明txt里的类别id超过了yaml里nc定义的范围典型场景是VOC转YOLO时class_to_id映射漏了一个类生成txt里的id是乱的。解决训练前先回读标签一条命令验证for f in labels/*.txt; do cut -d -f1 $f; done | sort -ucut -d -f1按空格切分取第一列输出应该是0、1、或者包含其他数字。如果出现大于等于nc的数字回到转换脚本修正映射。同时检查find . -maxdepth 2 -type d确认yaml里写的目录真实存在别漏掉嵌套层。5.3 划分泄露为什么验证mAP高却什么都检不到现象训练时val mAP到了0.85以上拿厨房现场新拍的照片测试一个框都不出或者框的位置明显错乱。原因划分泄露。88张图的样本量本来就不多如果训练前粗暴地random.shuffle然后切分同一场景不同角度的相似图片可能同时落在train和val两边。模型在训练时已经“见过”验证集的变体val分数虚高一到新场景立即失效。还有个隐蔽泄露来自数据增强——fliplr生成的水平翻转图如果被同时用作训练和推理参考会让模型对真实积水形态产生误判。解决划分前先按场景来源分组同一时间段、同一厨房拍的一组图整体划到同一侧。另外写一个交叉检查脚本确认train和val没有重叠文件from pathlib import Path train_stems {p.stem for p in Path(dataset/images/train).glob(*.jpg)} val_stems {p.stem for p in Path(dataset/images/val).glob(*.jpg)} overlap train_stems val_stems print(f重合样本数: {len(overlap)})输出不为0就回到划分脚本重新分。对88张级别的数据宁可val集多放几张也不能让集合边界模糊。5.4 7z解压报错、乱码与文件缺失现象解压过程中报headers error或者解压完成后目录名变成乱码训练脚本找不到对应图片。原因一是压缩包传输中被截断或磁盘空间不足7z x解到一半被迫中断二是压缩包内文件名使用了非当前系统默认编码Windows简体中文环境下双击解压容易出乱码目录三是解压工具版本太旧对新的压缩算法不兼容。解决先用7z t测完整性任何Data Error都意味着重新下载。解压前用7z l kitchen_water.7z | head查看包内文件列表确认没有嵌套多余的顶层目录。乱码问题在数据集场景里最简单粗暴的解法是解压后手动把目录统一改成纯ASCII名称数据本身是图片和标签重命名不影响内容但能避免后续所有训练脚本在路径编码上出幺蛾子。5.5 混淆矩阵总和为什么对不上样本总数现象训练完看混淆矩阵把每个格子的数字加起来比验证集目标总数多或者少怎么看都对不上。原因混淆矩阵展示的是在某个置信度阈值下“预测框和真实框匹配”的结果。预测框低于置信度阈值的被当作背景没有计为检测同一真实框可能被多个预测框匹配而NMS只保留其中一个还有部分预测框落在标注框外归属为背景预测。所以混淆矩阵里的数值本身就不等于验证集的目标框总数“总和唯一”本来就是一个伪命题。解决要核对标签总量直接数验证集标注框数wc -l dataset/labels/val/*.txt | tail -1要评估模型分类能力看Precision-Recall曲线和各类别的AP值不要盯着混淆矩阵做数值合计。混淆矩阵的作用是观察两个类别之间是否互相混淆比如“积水”被大量预测成“反光”说明两个类的视觉特征在模型看来太接近这时该做的是补充区分度高的样本而不是调阈值。6. 验证技巧让模型把预测图画出来再下结论6.1 用预测图检查比mAP快训练完成后的第一件事不要看TensorBoard曲线先让模型跑一批没参与训练的真实厨房图yolo detect predict \ modelruns/detect/train/weights/best.pt \ sourcedemo_images \ conf0.25 \ saveTrueconf0.25是置信度阈值积水和反光的边界模糊阈值太高容易漏检太低会出一堆假框。预测结果默认保存到runs/detect/predict每一张图都有框和目标类别。逐张翻看重点看漏检和误检的分布大量漏检说明积水特征没学到大量误检则说明反光干扰没被抑制。mAP是一个聚合数字看不出具体失败模式而“你这张图为什么会漏框”是训练下一轮的唯一线索。6.2 用厨房外的留出图做最终验收还有一个常被忽略的验收习惯从训练集和验证集之外单独留一组“场外图”比如不同厨房、不同光照、不同手机拍的照片。88张数据集产出的模型最终要证明的不是在这88张的val子上得多少分而是在没见过的厨房里能不能用。我一般会拿模型跑20到30张场外图人工记下每张图的漏检数和误检数比单个mAP数字可靠得多。这是我带训小样本积累下来的血泪经验先看图再看数。训练了80个epochval mAP 0.85拿手机在厨房拍一帧结果一个框都不出——这不是模型算错了而是数据集本身的分布和真实场景差了一步。从那以后我拿到任何新数据集永远是先解压看结构、再写转换脚本、跑通一版推理、最后才上量训练这个顺序帮我少翻了很多次车。希望帮到你。本文还有配套的精品资源点击获取