资讯详情 7992张瓷砖缺陷检测数据集:COCO标注与YOLOv8训练实战
📅 2026/10/11 2:40:59
简介面向质检算法工程师、机器学习学习者与制造业自动化团队的瓷砖缺陷检测数据集可用于训练目标检测模型以识别瓷砖表面的边缘崩裂、破洞、裂缝等缺陷覆盖瓷砖制造质量控制、零售库存管理、安装前评估及建筑检测等典型场景。压缩包共2000个文件主要包含1997张JPG原图和3个JSON格式的COCO标注文件整体大小约579.25MB图片与标注一一对应JSON中记录了缺陷类别、边界框及多边形轮廓方便直接接入主流检测框架进行训练与验证。目前已有646人学习下载。利用该资源学习者能拿到带精细标注的真实工业样本无需自行采集和标注可直接开展模型训练、缺陷分析及算法验证数据覆盖不同光照和拍摄角度下的缺陷形态对提升模型在真实产线中的鲁棒性很有帮助。同时其规范的标注结构也适合作为教学演示、课程设计及论文复现的基准数据集。1. 瓷砖缺陷检测数据集7992 张标注好的图先解决“没数据”的卡点搞工业视觉缺陷检测的同行基本都体会过同一个卡点模型结构选好了训练脚本写好了回头一看手里没有一张带标注的真实缺陷图。自己标几百张都费劲何况是几千张。这份瓷砖缺陷检测数据集解决的就是这个问题——7992张原始瓷砖图统一用 COCO JSON 格式标注能识别的缺陷涵盖边缘崩裂、破洞、裂缝三类下载后可以直接进训练流程省掉最耗时的数据标注环节。我拆过的所谓开源数据集不在少数要么标注格式混乱要么类别定义模糊这份数据集的格式是规范的。它适合三类人做工业质检模型落地的算法工程师、要跑缺陷检测对比实验的研究生、以及刚入门想拿真实数据集练手的目标检测新手。轴承缺陷检测、零件缺陷检测这类场景的团队同样可以复用这套标注与训练流程。2. 数据集结构与标注格式先看懂 COCO JSON 再谈训练2.1 目录结构与三种标注格式的来龙去脉这个数据集带有明显的 Roboflow 导出痕迹图片文件名的规律都是_MG_2376_jpg.rf.b9291a74b96c722d37e4a26d3089e752.jpg这种形式。中间那段rf.和后面的哈希是导出工具生成的全局唯一标识作用很简单同一张图在多轮导出、增删样本时不会因为重名被覆盖。理解这一点很重要后面按文件名匹配标注时你得知道这段哈希是文件名的一部分而不是可以随便删掉的后缀。从项目说明可以确认这份数据集同时提供了三种主流标注格式YOLO 文本框文件、COCO JSON、Pascal VOC XML。这是聚类导出包的典型结构常见的目录划分如下目录/文件内容适用场景images/train、images/val、images/test划分好的原始图片训练、验证、测试的图片输入labels/train、labels/val、labels/testYOLO 格式的 txt 标注Ultralytics YOLO 直接读取annotations/instances_train.json 等COCO JSON 标注MMDetection、MMYOLO、Detectron2annotations/*.xmlPascal VOC XML 标注旧工具链、二次人工校验我拿到包之后的第一件事是把三个格式的同一张图打开对比一遍。三种格式里优先用 COCO JSON原因有三条第一MMDetection、MMYOLO、Detectron2 这类主流框架的工具链都围绕 COCO 展开pycocotools 可以直接算 mAP 和各类别 AP第二COCO 的 categories 字段自带类别名不像 YOLO txt 只有一串索引数字排查问题时能少踩很多坑第三JSON 本身是结构化文本用 Python 几行就能统计类别分布做数据体检非常方便。YOLO txt 适合 Ultralytics 生态的快速实验Pascal VOC XML 更适合老工程里的二次校验。字段约定与 COCO2017 数据集结构同源兼容性不用担心。2.2 用 Python 解析 JSON先做一次数据体检拿到 COCO JSON 之后不要急着开训先把它变成统计数字。COCO JSON 的核心只有四个字段images 存图片路径和宽高annotations 存每个框的类别和坐标categories 存类别表。下面这段脚本把这三个字段读出来顺便统计类别实例数和平均每张图的标注密度import json from collections import Counter json_path annotations/instances_train.json with open(json_path, r, encodingutf-8) as f: coco json.load(f) # categories 是类别表输出 id 与名称的对照 print(categories) for cat in coco[categories]: print(f id{cat[id]} name{cat[name]}) # 按 category_id 统计每个类别的实例数量 cat_id2name {cat[id]: cat[name] for cat in coco[categories]} ann_per_cat Counter(ann[category_id] for ann in coco[annotations]) for cat_id, cnt in ann_per_cat.most_common(): print(f {cat_id2name[cat_id]}: {cnt} 个实例) # 统计参与标注的图片数和平均每张图的标注数 img_ann_cnt Counter(ann[image_id] for ann in coco[annotations]) print(f参与标注的图片数: {len(img_ann_cnt)}) print(f平均每张图标注数: {sum(img_ann_cnt.values()) / len(img_ann_cnt):.2f})脚本输出里最值得关注的两个数字是类别分布和平均标注数。如果平均每张图只有不到 1 个标注框说明大量图片是没有缺陷的负样本这类负样本过多时模型会偏向“无缺陷”推理阶段容易漏检如果三类缺陷的实例数差距超过 5 倍就需要在第 5 章说的类别不平衡处理上做文章。第二步是检查 bbox 是否有越界或宽高为 0 的脏数据。常见 bug 是把 COCO 的[x, y, w, h]当成[x1, y1, x2, y2]解析导致框被画得非常大甚至反向。COCO 的 bbox 约定是左上角坐标加宽度、高度单位是像素不是归一化值这个约定在写转换脚本时尤其容易错。2.3 从 COCO 转 YOLO一张图对应一个 txt我一般建议拿到什么格式就用什么格式但如果你用的是 Ultralytics YOLO还是需要把 COCO JSON 转成 YOLO txt。转换逻辑不复杂但有两个必须处理的细节COCO 的类别 id 从 1 开始编号YOLO 的类别索引从 0 开始转换时要重做映射COCO 的 bbox 是左上角坐标加宽高YOLO 需要的是中心点坐标加宽高并且都除以图片宽高做归一化。下面这段脚本可以直接抄import json import os def coco_to_yolo(coco_path, label_dir): with open(coco_path, r, encodingutf-8) as f: coco json.load(f) # COCO 的 category id 可能从 1 开始这里用 enumerate 统一成 0 打头的索引 cat_id_to_idx {} for idx, cat in enumerate(coco[categories]): cat_id_to_idx[cat[id]] idx img_id_to_info {img[id]: img for img in coco[images]} # 按 image_id 把标注分组一张图对应一个 txt anns_by_img {} for ann in coco[annotations]: anns_by_img.setdefault(ann[image_id], []).append(ann) os.makedirs(label_dir, exist_okTrue) for img_id, anns in anns_by_img.items(): img img_id_to_info[img_id] w, h img[width], img[height] txt_path os.path.join(label_dir, img[file_name].rsplit(., 1)[0] .txt) with open(txt_path, w) as f: for ann in anns: x, y, bw, bh ann[bbox] # 过滤掉宽高为 0 的脏标注避免训练时出现 nan if bw 0 or bh 0: continue cx (x bw / 2) / w cy (y bh / 2) / h nw bw / w nh bh / h cls_idx cat_id_to_idx[ann[category_id]] f.write(f{cls_idx} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}\n) coco_to_yolo(annotations/instances_train.json, labels/train)这段脚本里enumerate(coco[categories])是整段最容易写错的地方。有人直接拿ann[category_id]当类别索引写进 txt如果这份数据集的类别 id 恰好从 1 开始模型训练时就会把 edge_chip 当成索引 1 的类整体错位一个编号。另外txt 文件名必须基于图片文件名生成不能拿 annotation 的 id 当文件名因为一张图可能对应多个标注框最终一张图只允许有一个 txt。转换完成后随便打开一个 txt 看一眼第一列数字应该是 0、1、2 这种连续索引而不是 1、2、3。3. 模型选型与训练配置YOLOv8 在 7992 张瓷砖缺陷图上的调参思路3.1 为什么选 YOLO 系而不是两阶段检测器瓷砖缺陷检测是典型的工业质检场景对推理速度、部署难易度、训练成本都很敏感。两阶段检测器在精度上限上或许有优势但在这种目标不算小、结构不算复杂的场景里性价比远不如单阶段。YOLO 系现在基本成了缺陷检测的默认选项我选 YOLOv8 是因为 Ultralytics 的封装最顺滑数据格式、训练参数、模型导出全链路打通拿来就能用。v8n 和 v8s 适合显存吃紧的机器v8m 是精度和速度比较平衡的选择8GB 显存用 v8s16GB 显存可以直接上 v8m。还有一个很实际的原因工业项目早晚要上产线YOLOv8 训练完可以直接导出 ONNX、TensorRT engine部署链路短。用 Faster R-CNN 这套的话部署时还得处理 NMS、预处理对齐这些额外工作调试成本高不少。所以除非是论文里的精度对比实验否则我不建议在瓷砖缺陷这个场景里绕路。3.2 data yaml 与数据集划分Ultralytics 训练的第一步是把数据路径和类别写进一个 yaml 文件。以我常用的方式在数据集根目录建一个 tile_defect.yaml# tile_defect.yaml path: ./tile_defect_dataset # 数据集根目录 train: images/train # 训练图片目录相对 path val: images/val # 验证图片目录相对 path nc: 3 names: 0: edge_chip # 边缘崩裂 1: hole # 破洞 2: line # 裂缝有的导出版本叫 crackpath 写的是相对于当前运行目录的路径train 和 val 是相对 path 的子目录。如果下载包已经分好了 train/val/test通常可以直接用如果没分按 8:1:1 手动划分7992 张图分成训练 6394、验证 799、测试 799。划分时有一个容易被忽略的点如果同一块瓷砖有多张不同角度的照片这些照片必须划分到同一个集合里不能一部分进 train 一部分进 val否则会造成数据泄漏验证指标虚高上线后泛化能力打折扣。3.3 训练参数逐项说明第一次跑通最重要训练命令看起来不长但每个参数对缺陷检测的影响差别很大。我给出一个适合这个数据集的起点配置yolo detect train \ datatile_defect.yaml \ modelyolov8m.pt \ epochs120 \ imgsz640 \ batch16 \ patience20 \ device0 \ projectruns/tile_defect \ nameexp01epochs120 是在早停兜底的前提下给的实际如果 patience20 生效通常会在 80 轮左右收敛。imgsz640 是第一轮实验的标准配置但要注意瓷砖裂缝是细长目标如果训练后发现裂缝的召回率很低优先把 imgsz 提到 960 或 1024这比加数据增强更直接。batch16 对应 16GB 显存8GB 显存改成 8否则 CUDA OOM 会直接中断。device0 表示用第一张 GPU没有 GPU 可以去掉这行用 CPU 训练的话建议 epochs 减半先跑通流程。跑起来之后重点看三个指标box_loss 和 cls_loss 是否单调下降、mAP50 是否够高、mAP50-95 增长是否平稳。瓷砖缺陷类别少、目标相对大正常情况下 mAP50 应该在 0.93 以上。如果 mAP50 高但 mAP50-95 很低意味着框的定位不够精细这个数据集的 bbox 标注精度是像素级的不太应该出现这种情况真出现就去检查验证集里有没有标注错位的框。第一次跑建议只跑 20 个 epoch确认数据读取、loss 计算、验证流程都在正常运转再放开到完整训练省得等两小时才发现 yaml 路径写错。4. 常见问题与排查标注、转换、训练五个高频坑下面这几条都是我在类似数据集上实际踩过的坑按出现频率排序每条都给了现象、原因和解决步骤建议训练前先对号入座。4.1 坑一JSON 文件用记事本打开卡死或乱码现象下载后想看看标注长什么样用 Windows 记事本打开 instances_train.json直接卡死或者显示一堆乱码。原因COCO JSON 在 7992 张图的规模下annotations 列表轻松到几十 MB 级别记事本这类编辑器没有流式解析能力加载慢很正常。再叠加中文 Windows 对 UTF-8 无 BOM 编码的兼容问题乱码就出现了。解决换 VS Code 或 Sublime 打开但更好的做法是别用编辑器看直接让脚本去解析。注意 Windows 下部分 JSON 文件带 UTF-8 BOMjson.load 会直接抛错遇到json.decoder.JSONDecodeError时把open()的编码改成utf-8-sig再试。4.2 坑二COCO 类别 id 从 1 开始YOLO 从 0 开始导致类别错位现象训练完 mAP 看着正常一推理发现预测类别张冠李戴edge_chip 被标成 linehole 被标成 edge_chip。原因COCO 的 categories id 按 1 起编号YOLO 的类别索引按 0 起编号转格式时没做映射直接把 category_id 写进 txt所有类别整体后移一位。这类问题在训练指标上不容易暴露因为 loss 照样能降但预测结果一塌糊涂。解决转换脚本里用enumerate(coco[categories])重新建立映射表。转换完成后打印一行映射关系比如edge_chip - 0, hole - 1, line - 2训练前对着 yaml 里的 names 核对一遍。4.3 坑三文件名带 .rf. 哈希后缀导致路径读取失败现象训练能跑但验证阶段报image not found或者图片读出来了画框发现标注画在错误的图上。原因_MG_2376_jpg.rf.b929...jpg这种文件名里有两个点一部分脚本用split(.)[0]取主文件名时取到的是_MG_2376_jpg而非完整的_MG_2376_jpg.rf.b929...标签文件与图片前缀对不上。哈希字段是 Roboflow 生成的唯一标识删掉后可能和其他批次导出重名。解决保留哈希字段用rsplit(., 1)只切最后一个扩展名或者一次性批量重命名成纯数字同时把 JSON 里的 file_name 字段同步改掉。我习惯保留哈希因为它能保证全局唯一性跨批次合并数据时不容易撞名。4.4 坑四裂缝是细长目标下采样后特征丢失现象edge_chip 和 hole 的 AP 都不错唯独裂缝 recall 极低置信度也低。原因imgsz640 时YOLO 下采样 8 倍后特征图只有 80×80一条宽度 3 到 5 像素的裂缝在特征图上只剩不到 1 个像素特征直接被背景吞掉。这是小目标检测的通病在瓷砖缺陷里裂缝尤其典型。解决先把 imgsz 提到 960 或 1024观察 recall 是否回升如果显存不够把原图切分成多个 patch 分别训练和推理相当于用空间换尺度。不要做随机缩放增强裂缝这类目标对长宽比敏感缩小后更看不见。4.5 坑五边缘崩裂和裂缝互相误检现象验证集上 edge_chip 和 line 两个类别频繁互相误检人工看预测图发现有些框似乎也没标错就是模型分不清。原因这两类缺陷在视觉上都表现为瓷砖边缘的断裂如果原标注规范里没有明确界定标注人员标注时也容易摇摆类别边界本身就模糊。解决检查发布页对类别定义的说明如果没写清楚自己定规则。我一般这么定义边缘崩裂发生在瓷砖外边缘断裂口呈块状脱落裂缝可以起于边缘但延续到内部呈细长线状。按这个规则复查一批有争议的样例如果还是分不开就合并成一个“表面缺陷”大类先保召回细分等数据量上来再说。工业现场的第一诉求是有没有缺陷类别细分可以放在后续迭代里解决。5. 数据迭代与验证方法把 7992 张图的潜力榨干5.1 可视化检查训练前先画框别跳过很多新手拿到数据集就开训训完才发现标注有问题。我的习惯是训练前先把抽样图片的标注框画出来用最简单的方式做一次质检。下面这段脚本读验证集 JSON把前几十个框直接画到图上import json import cv2 coco json.load(open(annotations/instances_val.json, r, encodingutf-8)) id2name {cat[id]: cat[name] for cat in coco[categories]} img_id2info {img[id]: img for img in coco[images]} img_id2name {img[id]: img[file_name] for img in coco[images]} for i, ann in enumerate(coco[annotations][:50]): img_name img_id2name[ann[image_id]] img cv2.imread(fimages/val/{img_name}) x, y, w, h [int(v) for v in ann[bbox]] text id2name[ann[category_id]] cv2.rectangle(img, (x, y), (x w, y h), (0, 255, 0), 2) cv2.putText(img, text, (x, y - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) cv2.imwrite(fvis/{i:03d}.jpg, img)检查几个点框是否贴着缺陷边缘而不是框住整块瓷砖类别名和实际缺陷形态是否一致有没有框的宽高明显异常。Roboflow 导出的标注一般比较规整但转成 COCO 后偶尔会出现坐标溢出图片边界的情况这一步能把这类问题暴露在训练之前省掉后面排查的时间。5.2 类别不平衡的三种处理思路先跑一遍 2.2 的统计脚本如果三类实例数差距不大可以跳过这节。如果差距超过 5 倍比如 edge_chip 有 3000 个实例、hole 只有 400 个就需要处理。我按优先级试过三种方案第一种是简单过采样把少数类图片在每次 epoch 里多加载几遍实现成本最低但容易过拟合第二种是增强对少数类样本做随机旋转、亮度抖动、以及工业缺陷场景里很有效的 copy-paste把缺陷区域粘贴到无缺陷瓷砖上相当于扩充了背景多样性第三种是调整损失权重给少数类更高的 cls_loss 系数Ultralytics 里通过cls0.8这类参数控制。实际项目中过采样加增强的组合最稳先保证少数类能被稳定检出再谈精度。5.3 交叉验证评估数据集稳定性训练集划分是随机做的如果某一折恰好分到了特别多难例评估结果会偏低。我一般会把数据分成 5 折训 5 个模型看 mAP50 的方差。方差大说明划分不合理或数据集本身难例分布不均匀这时不是急着调模型而是回头查那几折里有哪些图片反复被误检。一个更轻量的做法是只跑验证集预测把置信度在 0.3 到 0.5 之间的框全部导出成图这批模糊样本往往就是下一次数据补标的目标。数据集的迭代价值就在这里7992 张图不是终点而是起点难例挖掘补标之后同样的模型结构还能再上一个台阶。6. 进阶用法把模型封装成批量质检脚本6.1 批量推理与结果落盘训练好之后最实用的动作是把模型封装成一个批量质检脚本。假设有一批新拍的瓷砖照片放在 inference 目录跑一遍就输出一份 CSV 缺陷报告from ultralytics import YOLO import glob import csv model YOLO(runs/tile_defect/exp01/weights/best.pt) imgs sorted(glob.glob(inference/*.jpg)) results [] for p in imgs: preds model.predict(p, conf0.25, imgsz640) for box in preds[0].boxes: cls int(box.cls[0]) conf float(box.conf[0]) x1, y1, x2, y2 [float(v) for v in box.xyxy[0]] results.append([p, model.names[cls], round(conf, 3), round(x1), round(y1), round(x2), round(y2)]) with open(defect_report.csv, w, newline) as f: writer csv.writer(f) writer.writerow([image, class, conf, x1, y1, x2, y2]) writer.writerows(results)conf0.25 是起点阈值实际使用建议分开看conf 在 0.25 到 0.5 之间的框单独导出一批供人工复查高于 0.5 的直接出结论。CSV 格式方便工厂端直接打开也方便后续按类别、按置信度区间做统计。6.2 难例挖掘是最省力的迭代路径模型跑完第一版后不要急着调参先做难例挖掘把验证集上误检和漏检的图挑出来按类别统计出“模型最怕什么”。对瓷砖缺陷来说常见的是低对比度的浅裂缝和光照不均导致的阴影误检。把这类图片补充进训练集增量训练 30 个 epoch 左右往往比换模型结构收益更大。从那以后我每次拿到新的数据集都强制自己先跑一遍可视化脚本再碰任何训练参数。这条习惯帮我至少避开了三次标注错位的翻车——先确认数据本身可信再谈让模型去学。希望帮到你。本文还有配套的精品资源点击获取