
简介这份带标注的红外热成像建筑缺陷识别数据集面向建筑质量检测、计算机视觉目标检测方向的研究者与工程师配合YOLOv12训练流程使用据标注信息训练可达到约91.5%的识别率可用于墙体裂缝、渗漏、保温层脱落等典型缺陷场景的自动识别。压缩包内共1401个文件包含700张JPG红外图像、700个对应的TXT标注文件记录缺陷类别与边界框坐标以及1个YAML配置文件定义类别名称与路径参数总体积仅34.53MB轻量易部署。目前已有53人学习下载。数据集与YOLO系列标注格式直接兼容下载后即可开始训练省去繁琐的标注整理环节同时多场景样本有助于提升模型泛化能力适合用于算法研发、毕业论文实验以及工程化落地前的模型验证。无论是初学目标检测的新手还是需要快速验证算法的研究者都能从这套规范的标注数据中直接受益。1. 带标注的红外热成像建筑缺陷识别数据集能复现91.5%还是只能跑demo先看这几件事做建筑外墙检测的人都有个共同痛点可见光照片拍不出裂缝背后的渗水和空鼓必须上红外热成像。热像仪把温差变成图像缺陷一目了然但回来就得让算法接住而算法得靠带标注的数据喂。红外建筑缺陷数据集本来就少能直接跑YOLOv12的更稀罕。看到“带标注的红外热成像建筑缺陷识别数据集支持YOLOv1291.5%识别率700张图”这个项目多数人第一个念头是能不能直接用训练坑多不多。这700张带检测框的热像图配好YOLOv12训练配置等于把采集、标注、训练、评估串成完整链路。适合两类人刚接触目标检测、想快速用红外图出模型的工程技术人员已经在做可见光缺陷检测、想迁移到热成像场景的算法工程师。后面按数据格式、训练流程、踩坑和提点技巧的顺序讲透。2. 红外热成像建筑缺陷数据集数据构成、标注规范与YOLOv12适配方式2.1 红外热成像为什么是建筑缺陷识别的最优选型先说原理。建筑缺陷在热像图上不是靠“形状”暴露的而是靠“温度”暴露的。裂缝和空鼓区域的热传导路径被切断表面温度与周边完好区域出现温差渗水区域因为水分比热容大升温降温都比干燥墙体慢在热像图上表现为一块块边界模糊的低温或高温区域。红外热成像把这种温差变成可视化图像缺陷识别任务就从“找纹理”变成了“找温度异常区”这对检测模型来说是本质不同的任务。这也是为什么同样是YOLO可见光模型直接拿去跑红外图会掉点。可见光图有丰富的颜色和边缘信息红外图是单通道灰度对比度低、纹理少、噪声大。模型学到的特征不一样必须用红外数据本身去训练或者至少做充分的域适应。标题里这个数据集压在91.5%识别率就是建立在“缺陷在热像图上的温度表现是稳定可学”这个前提上这一点决定了后续所有训练策略的取向。所以拿到这个项目不要一上来就套用你之前的RGB训练配方。先把图当作红外图来对待灰度、单通道、可能有伪彩映射这些细节在训练参数上的影响第4章会专门讲。这里先记住一个结论红外热成像建筑缺陷识别不是换了个数据集那么简单它换了一个成像模态训练策略必须跟着换。实际采集的时候还有一个很容易忽略的条件温差建立。热像仪拍建筑缺陷讲究的是在日出后或者日落后等外墙温度场快速变化的窗口期去拍这时候裂缝、空鼓与背景的温差最大缺陷在热像图上最清晰。如果图源是在中午拍的整个墙面温度均匀缺陷和背景几乎没有温差标注员看原图都费劲标出来的框质量就可想而知。拿到数据集先看有没有采集时间信息或者直接从图里感受对比度对比度差的图源后面再怎么调参都补不回来。2.2 标注体系缺陷类别、标注格式与工具链这个数据集的标注对象通常是几类常见建筑缺陷开裂、渗水/潮湿、空鼓、保温层缺陷、锈蚀有的还会把“疑似缺陷”单独分一类。类别数量一般不会太多目标检测在5到8个类这个量级上最稳类别太多且样本不平衡时小样本类别的AP会掉得很明显。拿到数据后第一件事就是把类别清单列出来确认每类对应的标签编号这一步不做后面训练百分百翻车。下表是按热像图表现归纳的常见类别标注时可以参考这个逻辑来确定框的贴合方式类别热像图上的典型表现标注难点开裂线状温度突跳通常比周围低长宽比极端框要贴合细长区域渗水/潮湿大面积低温区域边界模糊容易把框画大把完好墙面圈进来空鼓温差斑块形状不规则边界不清晰标注靠经验判断保温层缺陷大范围温差过渡带和目标边界不清容易漏标锈蚀局部高温点尺寸小易漏标标注格式上既然标题点名支持YOLOv12最稳妥的约定就是YOLO格式的txt标注每个txt文件对应一张同名图片每一行是“类别编号 x_center y_center width height”后面四个值都除以图片宽高做了归一化。这个格式是所有YOLO系列模型的通用语言YOLOv12也不例外。如果你手里的原始标注是CVAT导出的COCO JSON或者LabelImg导出的XML就得先转换转换脚本在第3章里给。这里顺带提一句数据标注工具的选择。做这类数据集的标注常见做法是用CVAT或LabelImg这两者在目标检测标注工具里属于最主流的。CVAT适合团队协作能在线标导出格式多LabelImg轻量单机标注方便。不管用哪个导出后统一转成YOLO格式这一步都少不了而且建议转完后随机抽几张图把框画出来做人工核验别信“导出即正确”。红外图中“边界模糊”的缺陷特别考验标注员耐心框稍微画大一点模型学到的边界就是错的这个隐患会一路传导到识别率里。2.3 YOLOv12适配数据集的目录组织与data.yamlYOLOv12在数据加载上沿用了Ultralytics系的路子数据集的目录结构要求固定images下放图labels下放同名txt再加一个data.yaml描述路径和类别名。700张图的常见划分是8比2也就是约560张训练、140张验证下面这个结构可以直接套用building_defect_dataset/ ├── data.yaml ├── images/ │ ├── train/ # 约560张红外热像图 │ └── val/ # 约140张红外热像图 └── labels/ ├── train/ # 与images/train同名的txt标注 └── val/ # 与images/val同名的txt标注目录只要符合这个约定训练脚本不用改路径逻辑。data.yaml的内容也很标准关键是把names列表和你的类别编号严格对应# building_defect_dataset/data.yaml path: /path/to/building_defect_dataset # 数据集根目录的绝对路径 train: images/train val: images/val names: 0: crack 1: moisture 2: delamination 3: insulation_defect 4: corrosion这里的参数要盯死两点。第一path建议写绝对路径相对路径在换机器跑的时候经常因为工作目录不同而找不到图。第二names的索引顺序必须和txt标注里的类别编号一致比如0对应crack那txt里类别编号0就只能是裂缝不能是别的。见过不少人在这上面出错最常见的是把类别编号从1开始写结果模型把背景当成了第0类这个在第4章会展开讲。YAML写完后建议顺手跑一遍完整性校验统计训练集里每个类各有多少个框缺标注的图片有多少张python -c from pathlib import Path from collections import Counter cnt Counter() for txt in Path(labels/train).glob(*.txt): for line in txt.read_text().splitlines(): cnt[int(line.split()[0])] 1 print(dict(sorted(cnt.items()))) 输出结果应该和data.yaml里的names列表一一对应。如果某个类别一次都没出现就要回数据源核对该类是不是没标或标漏了。这一步在数据集交付时也可能帮你判断交付方是否真的做过质量检查。3. 用YOLOv12在本地跑通训练环境、转换脚本与训练参数3.1 环境准备把ultralytics装到能跑YOLOv12的状态YOLOv12的训练入口在Ultralytics生态里所以要先把ultralytics这个库装到位。官方建议用GPU训练至少一张显存8G以上的NVIDIA显卡显存不够可以用imgsz降到480或batch降到8来换。安装命令很简单pip install -U ultralytics装完确认环境YOLOv12的权重命名是yolov12n.pt、yolov12s.pt这套用下面的命令确认当前环境是否支持yolo help | grep -i yolov12 python -c from ultralytics import YOLO; print(YOLO(yolov12s.yaml))同时确认CUDA和PyTorch是否就位这一步能省掉后面跑训练时才发现环境问题的返工时间nvidia-smi python -c import torch; print(torch.cuda.is_available(), torch.__version__)如果第一条命令没有输出说明当前ultralytics版本不带YOLOv12需要升级或者从YOLOv12官方仓库按README把模型文件放进你的工程目录后重新导入。这一步看着简单实际是很多人卡最久的地方因为pip默认装到的旧版本并不包含YOLOv12的注意力模块定义。环境就绪后把预训练权重下载到本地建议用yolov12s.pt起步。s规模在700张图的数据集上是性价比最高的选择因为数据量小用n或s能更快收敛直接用l甚至x反而更容易过拟合后面章节会解释原因。如果你的显卡确实跑不动YOLOv12的注意力模块退一步用yolov8s.pt做初始化也完全能跑效果差距通常小于5个百分点这个数据集的算法兼容性比大多数人想象的好。3.2 把COCO/VOC标注转成YOLO格式转换脚本与参数说明如果你的标注已经是YOLO txt这节可以跳过。但据我所知这类红外数据集原始交付格式五花八门CVAT导出COCO JSON的占比很高所以这里给出一个把COCO JSON转YOLO txt的脚本直接按你的路径改就能用# convert_coco_to_yolo.py import json, os from pathlib import Path def convert(coco_json: str, img_dir: str, out_dir: str): with open(coco_json, r, encodingutf-8) as f: coco json.load(f) imgs {im[id]: im for im in coco[images]} # COCO类别的id不一定是连续的这里统一映射成从0开始的连续编号 cats {cat[id]: idx for idx, cat in enumerate(coco[categories])} anns_by_img {} for ann in coco[annotations]: anns_by_img.setdefault(ann[image_id], []).append(ann) os.makedirs(out_dir, exist_okTrue) for img_id, anns in anns_by_img.items(): im imgs[img_id] w, h im[width], im[height] lines [] for ann in anns: cls_id cats[ann[category_id]] x, y, bw, bh ann[bbox] # COCO bbox是[x, y, width, height] cx (x bw / 2) / w cy (y bh / 2) / h nw bw / w nh bh / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}) if lines: txt Path(out_dir) / (Path(im[file_name]).stem .txt) txt.write_text(\n.join(lines), encodingutf-8) if __name__ __main__: convert( coco_jsondefect_annotations.json, # CVAT导出的COCO标注 img_dirimages/, out_dirlabels/train/, )这个脚本有两点要注意。一是COCO的bbox是左上角坐标加宽高而YOLO格式是中心点坐标加宽高换算公式就是脚本里那四行别把原始坐标直接抄进去。二是COCO的类别id经常不是从0开始也不连续脚本里的cats字典做了重映射这一步能避免后面类别编号错位的坑。如果原始标注是VOC XML转换逻辑相同只是读取方式要从json换成xml.etree核心还是“左上角宽高”到“中心点宽高”的换算。转完之后不要急着训练先把txt里每个类别的框数量统计一次与data.yaml的names对照确认没有空类和编号错位。3.3 训练参数epochs、imgsz、batch与迁移学习的取舍调参之前先想清楚700张图意味着什么。700张是典型的小数据集训练时模型很容易把训练集的温度和纹理分布背下来验证集一换就掉点。针对这个量级我的经验是加大epoch但配合早停batch适中imgsz保持640或以上mosaic保持开启但注意它在末段自动关闭的机制。下面是直接可用的训练命令yolo detect train \ data/path/to/building_defect_dataset/data.yaml \ modelyolov12s.pt \ epochs300 \ imgsz640 \ batch16 \ patience50 \ cacheTrue \ device0 \ projectruns/building_defect \ nameexp_yolov12s逐个参数说含义。epochs设成300是因为小数据集每轮看到的样本少需要更多轮次来充分收敛实际用到多少看patience早停。patience50表示验证集mAP连续50个epoch不涨就自动停这是防止过拟合的最后一道闸。batch16在8G显存下跑s模型问题不大如果你的卡只有6Gbatch降到8、imgsz降到480。cacheTrue把训练图像缓存进显存或内存700张图完全放得下训练速度能快一截。显存和模型规模的对应关系按我的经验可以参考这张表来定起点显存模型imgszbatch6Gyolov12n48088Gyolov12s6401612Gyolov12s6403224Gyolov12m64032这里专门说一句mosaic。Ultralytics默认会在训练中开启mosaic拼图增强把4张图拼成1张喂进网络。mosaic对小目标多的场景收益很大但也会改变图像分布所以ultralytics训练的最后10个epoch会自动关闭mosaic。这一点不用改默认就行别手动全局关闭除非你发现目标框大量贴在图像边缘导致标签错乱。迁移学习的权重选择也有讲究。标题写“支持YOLOv12”那就从yolov12s.pt开始。如果显卡或框架跑不动YOLOv12的注意力模块退一步用yolov8s.pt做初始化也完全能跑效果差距通常小于5个百分点这个数据集的算法兼容性比大多数人想象的好。3.4 验证结果mAP、Precision、Recall怎么解读91.5%在哪一层训练结束后ultralytics会在runs/building_defect/exp_yolov12s/目录下生成weights/best.pt和last.pt以及val_batch0_pred.jpg这类可视化图。best.pt是验证集上mAP表现最好的权重训练和推理都用它。验证命令是yolo detect val \ data/path/to/building_defect_dataset/data.yaml \ modelruns/building_defect/exp_yolov12s/weights/best.pt \ imgsz640 \ batch16跑完会打印一张指标表关键是mAP50和mAP50-95两列。标题里的91.5%识别率如果对应的是mAP50那属于不错但正常的水平如果对应的是mAP50-95那说明模型泛化能力非常强。复现的时候先盯这两列别盯着Loss曲线看Loss在训练集上降得再漂亮都说明不了泛化。这里插一句血泪经验我在类似项目里吃过亏训练完只看训练集loss以为模型稳了一上验证集立刻现原形。小数据集上验证集mAP才是唯一的裁判训练集Loss只是过程指标。所以每次训练完先打开results.png看mAP50曲线的走势如果曲线在某个epoch突然掉头向下多半是早停没触发或数据增强关闭导致过拟合提前引爆。4. 训练避坑与常见问题排查红外图预处理、标签错位与小目标漏检4.1 16位热像图被当8位读对比度丢失与成像噪声放大现象训练出来的模型在验证集上mAP不高可视化预测框大量漏检尤其渗水和保温层缺陷这种大面积、低对比度的类别框得七零八落。原因不少红外相机直接输出16位PNG或TIFF温度数据以uint16存储。ultralytics加载图片走的是OpenCV的imread默认路径16位图会被截断到8位或因为像素值范围过大而整体发黑发灰原本清晰可见的温差区域被压缩成一片灰。解决先把所有训练图全部转换并增强成8位不要指望训练时自动处理。推荐用百分比截断加CLAHE的方式# preprocess_thermal.py import cv2 import numpy as np from pathlib import Path src_dir Path(raw_images) out_dir Path(images/train) out_dir.mkdir(parentsTrue, exist_okTrue) for p in src_dir.glob(*.*): img cv2.imread(str(p), cv2.IMREAD_UNCHANGED) # 按原深度读入 if img.dtype np.uint16: # 按1%和99%分位截断去掉传感器极端值保留温差主体 lo, hi np.percentile(img, (1, 99)) img_f np.clip((img.astype(np.float32) - lo) / max(hi - lo, 1), 0, 1) img_8u (img_f * 255).astype(uint8) else: img_8u img # CLAHE对热像图对比度提升非常明显clipLimit不宜太大2.0左右够用 clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)) img_enhanced clahe.apply(img_8u) cv2.imwrite(str(out_dir / p.name), img_enhanced)参数说明percentile的(1, 99)是截断区间如果图像过曝或过暗可以放宽到(0.5, 99.5)。clipLimit是CLAHE的对比度限制太大容易把热噪声一起放大2.0是经验的稳定值tileGridSize是分块尺寸8x8是默认值对建筑热像图这种大面积均匀区域比较合适。这一步做完再进YOLO效果通常立竿见影。4.2 背景被当成类别0编号错位的经典翻车现场现象训练能跑完loss也正常但验证时预测出的框全部偏移或者某一类永远检测不出来打开results.png一看混淆矩阵背景类占了一大块。原因这是目标检测数据准备的经典错误。数据集的类别编号从1开始写比如txt里写“1 0.5 0.5 0.2 0.2”但data.yaml里names列表第0个索引对应的是crack结果模型把“1”当成了背景的负样本或者把本来就该是背景的图像区域当成目标。解决训练前强制检查所有txt的类别编号最大值必须小于names列表长度并且编号从0开始连续。用一条命令就能查python -c from pathlib import Path max_id 0 for txt in Path(labels).rglob(*.txt): for line in txt.read_text().splitlines(): cid int(line.split()[0]) if cid max_id: max_id cid print(最大类别编号:, max_id, (names长度应为, max_id 1, )) 如果打印结果里最大编号是5而names只有5项那说明类别从1或2开始编了把txt里的类别号统一减到从0开始。这个操作宁可多花十秒确认也别带着错位的标签跑几十个epoch白烧卡的时间最不值钱。4.3 小目标漏检裂缝和锈蚀这类缺陷为什么推不动现象整体mAP50看着有85%以上但拆到每个类别裂缝的AP很低预测框经常只有一半盖住裂缝或者压根没框出来。红外图里裂缝只有几个像素宽几百像素长长宽比极端。原因YOLO系列的特征金字塔在高层特征图上对小目标不友好加上红外图像噪声大、边缘模糊裂缝这种极端长宽比目标的中心点回归很容易漂移。700张图里如果裂缝样本只有几十条那模型基本学不稳。解决针对小目标优先增大imgsz到960试试代价是显存翻倍batch可能得降到8。其次是考虑对小目标区域做滑窗切图把一张1024x1024的热像图切成四张512x512的图标注坐标跟着平移映射再做训练。切图能把小目标在输入里的像素占比拉大mAP提升很明显。具体做法并不复杂切图时记录每个子图的偏移量把原标注框的坐标减去偏移量滤掉完全落在子图外的框保留与子图有交集的框并把越界部分裁掉。切图建议写成独立脚本放在训练流程的预处理环节里。切出来的图数量会翻几倍正好缓解700张图偏少的问题但要注意切图后同一缺陷可能出现在多张子图里验证集统计会偏高所以切图只对训练集做验证集保持原图。4.4 700张小数据集过拟合判断Loss背出来了泛化没跟上现象训练集mAP50冲到96%验证集只有80%差距越拉越大或者验证集mAP50曲线在某个epoch掉头向下。这就是过拟合的典型信号。原因700张图对YOLOv12这种带注意力机制的大模型来说偏少模型容量太大训练集特征被快速记忆泛化能力跟不上。解决三个方向同时抓。第一用早停patience设30到50别让验证集mAP恶化后再跑几十轮。第二加大数据增强除了mosaic把fliplr、scale等增强参数调强一点ultralytics里可以在训练命令上加augmentTrue并配合自定义的增强配置。第三改用更小的模型或者从冻结权重开始先用yolov12n.pt冻结backbone训练30个epoch再解冻全模型继续训练这样既保留预训练特征又不会让小数据集把随机初始化的检测头带偏。另外验证集中单独拿出固定的一部分做评估是必要的。700张图划分时常见做法是8比2但如果各类别样本数极不均衡建议按类别比例做分层抽样保证验证集里每一类都有足够的样本。这样评估结果才不是黑匣子里的数字游戏。4.5 训练中断、显存溢出与标签非法值的排查顺序现象跑到一半报CUDA out of memory或者训练一开始就报“Label shape not compatible”之类的错误还有的图加载时报“image corrupted”。原因显存溢出通常是batch和imgsz的乘积超过了显存上限标签非法值通常是归一化坐标里有负数或大于1的数多源于标注框越界或转换脚本没做裁剪图像损坏大多是原始红外图带EXIF信息或特殊编码格式读取时出错。解决按照顺序排查。先显存把batch降到8、imgsz降到480如果还炸就是数据加载本身有问题检查cacheTrue生成的缓存是否损坏删掉datasets目录下的缓存文件重来。再查标签用一条命令找出所有坐标不在[0,1]区间的txtpython -c from pathlib import Path for txt in Path(labels).rglob(*.txt): for line in txt.read_text().splitlines(): vals list(map(float, line.split())) if len(vals) ! 5 or any(v 0 or v 1 for v in vals[1:]): print(txt, line) 这行命令把所有非法行打印出来。有非法值就是在转换脚本里没做clip或没做全重新跑一遍转换脚本并保证对cx、cy、w、h都做0到1的裁剪。最后是损坏图直接用OpenCV逐张读取读不出来的单独挑出来检查是格式损坏还是文件名带中文导致路径解析失败。这几步做完绝大多数翻车都能定位到具体环节不用全盘重来。5. 把91.5%复现到你的机器上核对清单与一条小目标进阶路线5.1 复现前的核对清单91.5%这个数字本身不可怕可怕的是你不知道它是什么口径。复现之前先确认三件事数据划分是否一致各类别样本占比是否一致评价指标是mAP50还是mAP50-95。这三个口径任何一处对不上复现出来的数字就无从比较。我的习惯是先用best.pt做一次完整推理把预测结果画到原图上人眼过一遍。画出框的位置对不对、类别贴不贴、有没有把屋面和墙体背景误报成缺陷这比看任何指标都直观。指标可以刷但漏检和误报的分布骗不了人。5.2 一条最值得试的进阶路线如果复现的精度不理想先对验证集做一次带TTA的推理确认上限在哪命令是在val里打开augmentyolo detect val \ modelruns/building_defect/exp_yolov12s/weights/best.pt \ data/path/to/building_defect_dataset/data.yaml \ imgsz640 \ augmentTrueaugmentTrue会在推理时做多尺度融合和翻转推理mAP通常能提升1到3个点代价是推理耗时翻倍适合最后压榨精度时用。如果TTA提升超过3个点说明模型本身对尺度变化敏感回头应该优先做多尺度训练而不是继续加数据。如果非得给一条优先级最高的建议我会说做滑窗切图把700张变成单类别目标占比更高的几千张子图同时保持验证集不切。这条路对裂缝、锈蚀这类小目标缺陷的提升通常比换任何模型都明显。这也是我做这类红外项目收尾时最常用的一招。写到这里刚入手的项目能跑通瓶颈也看得见了。最细的坑其实就一句话小数据集上处理好数据胜过调三个月参。希望帮到你。本文还有配套的精品资源点击获取