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

瓷砖缺陷检测数据集:从COCO JSON到YOLOv8训练的完整路线

发布时间:2026/9/24 18:52:45

资讯中心
01
ARTICLE

瓷砖缺陷检测数据集:从COCO JSON到YOLOv8训练的完整路线

瓷砖缺陷检测数据集:从COCO JSON到YOLOv8训练的完整路线
简介面向瓷砖制造质检、安装评估与建筑检测等场景这份瓷砖缺陷检测数据集覆盖边缘崩裂、破洞、裂缝等多类缺陷可用于训练YOLO等目标检测模型帮助自动化识别生产线上的次品、到货瓷砖中的残次品及铺贴前的瑕疵。数据集源自7992张原始图像的采集成果当前压缩包内收录1997张JPG图像及3个JSON标注文件文件总数2000个压缩包大小579.25MBCOCO JSON格式可直接对接主流检测框架省去标注格式转换环节。对从事工业视觉、缺陷识别算法研究或智能质检系统开发的工程师与学习者而言既能直接用于模型训练、验证与调参也可通过标签和图像目录分析缺陷类别分布、核验标注一致性快速搭建基线实验。目前已有646人学习下载适合需要真实瓷砖样本验证算法效果的中高级开发者以及希望为传统质检流程引入AI能力的团队。1. 瓷砖缺陷检测数据集7992张标注图从COCO JSON到YOLOv8训练的完整路线做工业视觉的朋友应该都有体会缺陷检测最难的往往不是模型而是数据。瓷砖这行尤其典型——生产线上的瓷砖表面纹理、釉面反光、窑变差异都很大想要一个能扛住现场光照变化和缺陷形态变化的模型没有足够多样的标注数据根本跑不起来。这份瓷砖缺陷检测数据集一共7992张原始图用COCO JSON格式标注覆盖边缘崩裂、破洞、裂缝三类最常见缺陷也附带YOLO和PASCAL VOC格式的标签文件。它能直接喂给检测模型做训练适合做质检方案验证、算法选型对比以及瓷砖相关的视觉检测项目起步。对于刚入行缺陷检测的工程师这套数据可以帮你省掉最痛苦的标注环节直接进入模型训练和调参阶段对于已经在做工业视觉的熟手它也能作为预训练数据或补充样本用于提升模型对瓷砖这类高纹理目标的泛化能力。下面按我实际拆这套数据的路径来讲先看数据长什么样再讲怎么转换格式喂给模型最后聊聊那些容易翻车的细节。2. 数据集结构与COCO JSON标注拿到手先做三件事分享一个处理任何标注数据集的第一步不要急着跑训练先把数据结构和标注格式摸清楚。尤其是COCO JSON这种格式标注信息藏在annotation字段里不熟悉的人第一次打开容易懵。2.1 目录结构与文件命名规律这套数据的目录结构是典型的Roboflow导出风格图片文件名带哈希后缀比如_MG_2376_jpg.rf.b9291a74b96c722d37e4a26d3089e752.jpg。这种命名规则是Roboflow平台在处理重复文件名时自动加的目的是避免不同来源的图片重名覆盖。实际使用中这个哈希值不影响训练但你如果自己写脚本做数据划分建议直接解析_jpg.rf.之后的那段哈希作为唯一标识不要用完整文件名做字典键——不同批次导出的数据文件名前缀可能不一样。拿到的压缩包解压后常见做法是先按下面这个结构整理tile_defect_dataset/ ├── train/ │ ├── images/ # 训练集图片约6400张 │ ├── _annotations.coco.json │ └── labels/ # 如果是YOLO格式这里有同名txt ├── valid/ │ ├── images/ # 验证集图片约800张 │ └── _annotations.coco.json ├── test/ │ ├── images/ # 测试集图片 │ └── _annotations.coco.json └── README.txt # 类别名和数据集说明很多从Roboflow导出的数据集默认按这个比例划分我拿到这套数据后第一步是用tree命令确认实际的目录层级和文件数量避免脚本路径写错。find tile_defect_dataset -type f | wc -l # 预期输出图片文件数 JSON文件数 可能的txt标签数这一步能很快发现文件是否完整比如图片7992张但JSON只有三个那大概率是没带YOLO格式的txt标签。确认完文件数量下一步就是检查JSON内容是否和图片对得上。2.2 COCO JSON字段解析与类别映射COCO JSON的结构核心是images、annotations和categories三个数组。图片信息存在images里每个元素有id、file_name、width、height标注信息存在annotations里每个元素通过image_id关联回图片bbox是[x, y, width, height]格式category_id指向类别IDcategories数组定义了ID到类别名的映射。我一般用下面这个脚本快速检查标注的完整性import json with open(train/_annotations.coco.json, r) as f: coco json.load(f) print(类别映射:, {c[id]: c[name] for c in coco[categories]}) print(图片数量:, len(coco[images])) print(标注数量:, len(coco[annotations])) # 统计每张图的标注数量分布 from collections import Counter img_ann_counts Counter() for ann in coco[annotations]: img_ann_counts[ann[image_id]] 1 counts list(img_ann_counts.values()) print(f每图标注数: min{min(counts)}, max{max(counts)}, avg{sum(counts)/len(counts):.1f})这里重点看两个值每张图的平均标注数以及类别映射是否符合预期。我的经验是如果平均标注数偏低比如小于1.5说明有大量背景图这种数据训练出来的模型容易偏向低召回如果某张图的标注数特别多需要检查是不是缺陷被重复框了或者一张大图上包含了许多小缺陷但没被标全。这个检查过程能提前暴露数据质量问题比训练到一半发现loss异常再回头查要省事得多。2.3 标签分布与类别不平衡评估缺陷检测数据集最常见的坑是类别不平衡。瓷砖的裂缝和边缘崩裂出现的频率天然不一样如果某类缺陷只占5%的标注框数模型学起来会非常吃力。仔细统计每一类缺陷的框数和占比至关重要。import json from collections import Counter with open(train/_annotations.coco.json, r) as f: coco json.load(f) cat_id_to_name {c[id]: c[name] for c in coco[categories]} cat_counter Counter() cat_area_counter Counter() for ann in coco[annotations]: cat_id ann[category_id] cat_name cat_id_to_name[cat_id] cat_counter[cat_name] 1 bbox ann[bbox] # COCO的bbox是[x, y, width, height]面积用宽高相乘 area bbox[2] * bbox[3] cat_area_counter[cat_name] area total_box sum(cat_counter.values()) for cat_name in cat_counter: ratio cat_counter[cat_name] / total_box * 100 avg_area cat_area_counter[cat_name] / cat_counter[cat_name] print(f{cat_name}: {cat_counter[cat_name]}框, 占比{ratio:.1f}%, 平均面积{avg_area:.0f}px)我在实际项目中看过太多只统计框数不统计面积的这其实不够全面。比如同样多的框一类缺陷平均是200×200的大块崩裂另一类平均是20×20的小裂缝模型对两类缺陷的学习难度完全不同。小目标缺陷需要更高分辨率的输入或专门的特征层大目标缺陷可以在下采样后依然保留特征这两类放在一起训练输入尺寸不调整的话小目标那类基本学不好。3. 从COCO JSON到YOLOv8训练格式转换脚本与关键参数拿到COCO格式的数据集直接训练YOLO系列模型是行不通的。YOLO训练需要的是每张图片对应一个txt文件每行是class_id x_center y_center width height坐标值归一化到0到1。这块转换逻辑并不复杂但坐标归一化方向错了、类别ID没对齐、或者宽高写成整数的坑我见过不少。3.1 编写COCO转YOLO的转换脚本下面的Python脚本将COCO JSON转换成YOLO格式的txt标签。注意这里有一个关键点YOLO的坐标是归一化后的中心点坐标和宽高不是左上角坐标加宽高。转换时别忘记已经转换了坐标系。import json import os from pathlib import Path def coco_to_yolo(coco_json_path, output_label_dir): 将COCO JSON标注转为YOLO格式txt coco_json_path: 标注文件路径 output_label_dir: 输出txt标签目录 with open(coco_json_path, r) as f: coco json.load(f) # 建立 image_id - file_name 的映射 img_id_to_info {img[id]: img for img in coco[images]} # 建立 category_id - 从0开始的连续index cat_id_list sorted(set(ann[category_id] for ann in coco[annotations])) cat_id_to_yolo_id {cat_id: idx for idx, cat_id in enumerate(cat_id_list)} print(YOLO类别顺序:, {k: v for k, v in cat_id_to_yolo_id.items()}) # 按图片ID分组所有标注 anns_by_img {} for ann in coco[annotations]: img_id ann[image_id] if img_id not in anns_by_img: anns_by_img[img_id] [] anns_by_img[img_id].append(ann) os.makedirs(output_label_dir, exist_okTrue) for img_id, anns in anns_by_img.items(): img_info img_id_to_info[img_id] img_w img_info[width] img_h img_info[height] # 输出文件与图片同名但后缀是.txt img_name Path(img_info[file_name]).stem label_path os.path.join(output_label_dir, f{img_name}.txt) lines [] for ann in anns: cat_id ann[category_id] yolo_id cat_id_to_yolo_id[cat_id] # COCO bbox: [x, y, width, height] 是左上角坐标 x, y, w, h ann[bbox] # 转YOLO: 中心点坐标 宽高全部归一化到[0,1] x_center (x w / 2) / img_w y_center (y h / 2) / img_h w_norm w / img_w h_norm h / img_h # 裁剪到[0,1]范围防止边缘处标注越界 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) w_norm min(max(w_norm, 0.0), 1.0) h_norm min(max(h_norm, 0.0), 1.0) lines.append(f{yolo_id} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}) with open(label_path, w) as f: f.write(\n.join(lines)) print(f转换完成共生成 {len(anns_by_img)} 个txt文件) # 使用示例分别转换train和valid coco_to_yolo(train/_annotations.coco.json, train/labels)这个脚本里几个参数需要根据实际情况调整。首先是file_name的解析Roboflow导出的图片名带.rf.哈希后缀取stem后得到的标签文件名要和图片名完全一致否则YOLO训练时找不到对应标签。其次是类别ID的重映射COCO JSON里的category_id不一定是连续的可能是1、3、7YOLO要求类别ID从0开始连续递增所以脚本里用了enumerate重新映射。如果你下载的数据里categories顺序已经是0、1、2那这一步可以跳过但保留着更稳妥。3.2 YOLOv8的配置文件与训练启动参数格式转换完成后还需要准备YOLOv8的YAML配置文件指定训练和验证集的图片路径、类别数以及类别名。# tile_defect.yaml path: ./tile_defect_dataset # 数据集根目录 train: train/images # 训练集图片路径 val: valid/images # 验证集图片路径 test: test/images # 测试集图片路径可选 nc: 3 names: 0: edge_chip # 边缘崩裂 1: hole # 破洞 2: crack # 裂缝这里path路径尤其容易出问题。如果你用的是相对路径工作目录必须是数据集根目录的上一级如果训练时找不到图片报错信息通常明确写着image not found这时把路径改成绝对路径更省心。另外一个容易被忽略的细节是YAML文件里不要写注释里的中文——有些版本PyYAML解析中文注释会报编码错误建议要么全英文注释要么不写注释。启动训练的常用命令yolo detect train \ modelyolov8m.pt \ datatile_defect.yaml \ imgsz640 \ epochs100 \ batch16 \ patience15 \ device0 \ cacheram \ project./runs \ nametile_defect_v8m几个参数的实际含义imgsz640是输入尺寸瓷砖缺陷中的裂缝属于细长型目标如果原图分辨率较高且小裂缝多建议试imgsz960或imgsz1280代价是显存占用和训练时间几乎翻倍。batch16在16GB显存上跑YOLOv8m是安全的如果显存小就调到8不要硬塞导致CUDA out of memory。patience15是早停轮数连续15轮验证集mAP没提升就停止训练可以防止过拟合同时节省时间。3.3 训练过程中的指标观察与常见信号训练启动后不应该只是干等它跑完。训练日志里输出的box_loss、cls_loss、mAP50、mAP50-95这几个指标是判断模型学习状态的窗口。以我的经验前10轮看得最多的不是mAP而是cls_loss是不是在稳定下降。如果cls_loss下降到一定程度后震荡徘徊说明类别区分已经到瓶颈要么是特征不明显要么是数据量不够如果box_loss降得很慢先检查是不是学习率太高导致震荡再看标注框是否准确。训练中运行到一半时按CtrlC中断输出目录里已保存的best.pt是可以正常使用的不用等全部epoch跑完。早期中断的模型往往比跑满epoch最后过拟合的模型更好用所以不用心疼中断训练——实践中提前停掉的模型经常是验证集上表现最好的那个。4. 避坑指南瓷砖缺陷检测数据集训练中的五个典型翻车点这套瓷砖缺陷数据集我前前后后跑了三轮实验踩了不少坑。有些坑是数据本身的有些是标注格式转换时埋下的这里挑五个最典型的记录一下每条都是现象、原因、解决的老三段式。4.1 训练时loss值异常偏高问题出在标签文件里现象YOLOv8训练启动后loss值在2.5以上下不来震荡剧烈而且持续到第20轮也没明显下降。原因检查标签文件后发现部分txt是空的还有一些行的宽高数值超过了1.0。追根溯源是转换脚本里没有做异常值过滤标注文件里存在坐标为负数或宽高为0的异常框。这部分标注是原始数据集里就有的脏数据不是转换脚本的锅。解决在转换脚本里加一个过滤条件丢弃w 0 or h 0的标注同时对归一化后的坐标做clip。我后来写了个脚本扫了一遍所有标签文件把空标签文件和超界坐标统一修复。这个问题排查完loss值马上降到1.5以内。4.2 裂缝类缺陷几乎检测不到小目标问题被忽视了现象训练完的模型在验证集上mAP50有0.85但仔细看各类指标裂缝类的AP只有0.3边缘崩裂类0.92破洞0.88。这意味着模型基本不认识裂缝。原因瓷砖裂缝的特点是细长、低对比度在640×640的输入尺寸下原本可能占图片8%的裂缝缩成了十几个像素宽的细线特征在多次下采样后直接消失。加上裂缝类标注框数量本身偏少模型学习到的有效特征更少。解决把imgsz从640提高到960同时用YOLOv8自带的mosaic增强默认开启的保证小目标在拼接后仍有足够像素。训练参数里也可以把anchor适配打开让模型根据标注框分布自动调整anchor尺寸。关键逻辑是检测小目标输入分辨率是第一位的模型架构是第二位的。4.3 模型对釉面高光区域产生大量误检背景纹理被当成了缺陷现象验证集推理结果里大量白色瓷砖的高光区域被框成“边缘崩裂”误检率高达35%。但同样的模型在哑光砖上表现正常。原因高光区域在图像里呈白色亮斑边缘对比强烈和边缘崩裂的视觉特征非常相似。数据集里白色亮面砖占比较高模型学到的是“高对比度边缘区域 缺陷”而不是真正的裂纹特征。解决首先在数据层面做增强对训练集加入亮度抖动和Gamma变换让模型见过不同光照下的瓷砖表面减少对绝对亮度的依赖。其次在推理阶段加入一个后处理规则对置信度低于0.25的检测框额外检查一下框内区域的灰度直方图如果方差很小说明是均匀高亮而非表面破损则过滤掉。这个方法虽然粗暴但在现场环境里能压掉不少误检。4.4 边缘崩裂和破洞的类别混淆严重标注边界本身模糊现象验证集上边缘崩裂的类别被预测为破洞的比例接近20%混淆矩阵里这两个类别的交叉点颜色很深。原因瓷砖边缘崩裂后露出的坯体颜色和破洞露出的坯体颜色几乎一样只是位置不同一个在边缘一个在内部。部分标注员对两者的边界定义不一致同一个缺陷形态在不同图里被标成不同类别——这是标注一致性问题的典型案例。解决类别定义需要明确语义边界。我重新梳理了标注规则只有缺陷中心位于瓷砖边缘区域距离边界小于缺陷宽度的才算边缘崩裂其余内部塌陷算破洞。用这套规则对训练集做了一次半自动修正然后加了一个后处理约束——根据预测框的中心位置是否靠近图像边缘来修正输出。经过这个处理混淆比例降到8%。4.5 验证集mAP虚高但实际场景表现差同源数据导致的乐观偏差现象训练时验证集mAP50一直有0.88但拿到工厂现场采集的新图片上测试mAP直接掉到0.5。现场反馈完全没法用。原因数据集的train/valid划分是随机划分的同一块砖在不同角度、不同光照下的照片可能一张在train一张在valid。模型在验证时相当于见过这些砖的“熟人”指标自然漂亮。而现场的新瓷砖表面纹理是模型从未见过的效果急剧下降。解决不要把随机划分的验证集指标当作真实水平。我把所有图片按拍摄批次分组再划分同一个批次的图片全部进train或全部进valid保证验证集的数据分布更接近真实场景。如果你的数据里没有批次信息退而求其次的做法是按文件名前缀分组划分也能在一定程度上降低同源数据的影响。5. 进阶用法用训练好的模型做批量推理与置信度调优模型训练完成后离真正能用还有一步把模型部署到图片或者视频流上做批量推理。这里有一个常常被忽略但能让结果差出好几个点的小技巧——置信度阈值的选择不能拍脑袋必须根据实际误检和漏检的代价来定。5.1 批量推理脚本从模型到结果的完整链路用训练好的best.pt做批量推理常用脚本如下from ultralytics import YOLO # 加载模型 model YOLO(runs/train/tile_defect_v8m/weights/best.pt) # 对某张图推理conf0.25是置信度阈值iou0.5是NMS的IoU阈值 results model.predict( sourcetest/images/, conf0.25, iou0.5, imgsz960, save_txtTrue, save_confTrue, saveFalse )这里两个参数在工业场景下的调法conf越低召回越高但误检多conf越高误检少但漏检风险大。在瓷砖质检场景漏检一个缺陷的成本远高于多检一个良品所以conf应该往下调到0.15到0.2。iou是NMS合并重叠框的阈值如果同一缺陷被重复框出多个框把iou调低到0.4合并更激进如果相邻缺陷被合并成一个框说明iou太低要往0.6调。推理完成后save_txtTrue会在图片对应的目录下生成同名txt文件内容格式是class_id x_center y_center width height conf。这个文件就是给现场条码系统或分拣设备用的信号来源。5.2 置信度校准画一张PR曲线找出合适的阈值很多人在训练完后直接默认conf0.25其实这个值未必适合你的数据。正确做法是在验证集上画出PR曲线看Recall掉点的地方在哪里然后反向选择阈值。from ultralytics import YOLO model YOLO(runs/train/tile_defect_v8m/weights/best.pt) # 在验证集上做评估会打印各类别在不同阈值下的AP metrics model.val( datatile_defect.yaml, imgsz960, conf0.001, # 评估时conf设极小值让所有候选框都参与计算 iou0.5 ) # 输出里查各类别的PR曲线数据 print(metrics.box.pr_curve)执行这段代码后关注验证时输出中的F1-Confidence曲线。这个曲线是经验最直接的风向标它在哪个置信度位置达到峰值那个就是当前数据分布下的最优阈值。我在这个瓷砖数据集上的实验结果是阈值0.17到0.2之间F1最高远远低于默认的0.25。从那以后我每次训练完模型都会先跑一遍阈值搜索把conf和iou当成超参数来调再决定部署时的数值而不是直接信任默认值。这也算是我做缺陷检测以来坚持最久的一个习惯希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

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

03
WHY YAOTU

想打造同款高转化官网?

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

场景化定制

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

营销型架构

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

全周期服务

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

免费获取你的建站方案

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