资讯动态

钢筋计数数据集标注与训练全攻略:从YOLO到密度图

发布时间:2026/10/5 2:50:52 来源:尧图企业网站定制
简介人工智能钢筋计数数据集的训练集标注文件包面向建筑工地钢筋清点、智能盘点等应用场景的算法工程师与研究人员可用于训练钢筋数量统计模型替代传统人工计数方式提升盘点效率。该数据集以VOC格式组织压缩包共568个文件全部为XML格式文件整包仅1.07MB每个XML文件记录钢筋目标的边界框坐标与类别信息可直接导入目标检测框架进行模型训练与精度验证。需要说明的是完整数据集因单文件大小限制被拆分为多个此部分为训练集标注文件测试集未标注图片不在包内。目前已有659人浏览学习适合需要快速获得规范化钢筋标注数据、开展钢筋计数算法预研与模型迭代的开发者参考博客可查看图片质量便于确认数据是否符合需要后再获取。1. 钢筋计数的数据集为什么说标注文件比算法更值钱工地上清点钢筋老统计员一根根数一垛钢筋动辄上千根大热天里爬垛清点既费时又有安全风险。用人工智能做钢筋计数本质上是在做密集小目标的检测与数量回归——模型需要在照片里把相互搭叠、半遮挡的钢筋端面逐根找出来再按视觉特征确定性地给出根数。这个需求落地得顺不顺不在于你选 YOLO 还是 DETR而在于你手里那套数据集和标注文件的质量。钢筋计数数据集的核心资产恰恰是标注文件框得准不准、边界怎么定义、半根算不算一根、遮挡怎么标直接决定模型训练出来是「能数大概」还是「每垛都准」。我拿到过不少自称能用的钢筋计数数据集真正打开标注文件后才发现问题比想象的多有的框把两根并排的钢筋框成一个目标有的只标了前端可见的断面而漏掉压在下层的根数还有的标注软件导出时把类别名写成了中文导致训练直接报编码错。这类数据集的正确用法不是解压后立刻丢进 YOLO 开训而是先做一次格式梳理和标注质量审查。这篇文章就沿着「标注文件长什么样 → 怎么训练 → 参数怎么调 → 坑在哪 → 怎么做得更准」这条线讲透读者不管是拿现成数据集做毕设还是在工地现场自己标数据建私有集都能照着一套可复现的流程走下来。2. 钢筋计数数据集的标注格式从一根一框到端到端数量标签2.1 标注文件里到底该有什么钢筋计数数据集最常见的标注形式是目标检测框每根可见钢筋在图片上用一个矩形框框起来。以 YOLO 格式为例每张图片对应一个同名的 .txt 文件每行记录一个目标类别编号、归一化中心坐标 x、y 和归一化宽高 w、h。因为钢筋端面近似圆形高宽比接近 1所以标出来的框通常是接近正方形的小框这些框的中心点密集分布在整张图片上。但如果把钢筋计数只当成普通目标检测来做很容易掉进一个坑当一垛钢筋有几百上千根时标注工作量巨大而且检测器天然倾向于漏掉被遮挡的那一部分。所以现在更实用、从业者更常采用的标注方式有两类。第一类是检测框加数量标签混合对可见钢筋逐根画框同时在图片级元数据里记录总根数训练时配一个额外的计数头来回归总数量。第二类是更激进的密度图方案不逐根画框只按规则在每根钢筋中心点打点由脚本把点图展开成高斯密度图模型输出密度图后对峰值进行计数。从标注成本和模型可解释性平衡来看我一般建议先做检测框方案框的数量能顺便当计数用等识别精度上来后发现漏检成为瓶颈再升级为检测头加计数头联合训练。对于标注文件除了框坐标类别命名也必须干净例如统一叫 rebar不要一张图一个名字。标注平台导出时注意检查是否把「背景」也写成了 0 类目标后面训练时会造成一票误检。2.2 标注规则边界是数据集的生死线真正决定数据集价值的不是框的绘制精度而是标注规则的一致性。钢筋垛侧面看过去是一个密集的圆形排列工人清点时有一个约定俗成的逻辑看一眼正面可数的断面按排数乘列数得出总量。标注时如果只标正面可见断面模型就只学会数表面如果通过半遮挡的轮廓推断下层钢筋模型可能学出一套现场老师傅的清点逻辑。这两者没有绝对对错但一个数据集里不能混着用。我常用的规则是「可见即标」加「确定性优先」两条原则。可见即标指每根能从图像上确认存在的钢筋都要框出来哪怕只有半圈轮廓。确定性优先指标注时只按当前图像能确认的信息判断不允许标注员靠猜测补全被完全遮死的钢筋。这样做出来的标注文件有一个好处模型学习的是「从视觉证据推断根数」而不是「记忆目标数量」泛化到新垛型时不容易翻车。再具体到框的贴合度钢筋端面是圆盘状标注框贴着圆形边缘画圆框或者紧致的矩形框都可以但不要画成带大块背景的松框。松框会把旁边的钢筋边缘也包进特征区域训练时模型分不清到底学的是哪根钢筋的特征。如果项目用的是旋转框检测器那框贴合度的问题会略有缓和但大多数钢筋计数场景还是水平框为主。标注时框边和钢筋边缘的缝隙控制在 1 到 2 个像素内即可。标注格式内容适用场景计数方式工作成本YOLO 检测框每根钢筋一个矩形框中低密度钢筋垛千根以内类别置信度过滤后统计中等点标注 密度图每根钢筋一个点脚本展开高斯图高密度、高度遮挡的钢筋垛密度图峰值定位后求和低检测框 数量标签框 图片级总根数希望同时输出位置和目标总数的场景检测框计数与回归头整合较高2.3 把现成标注统一成训练格式处理脚本与四个边界坑网上能找到的钢筋计数数据集来源很杂有的给 VOC 格式 XML有的是 COCO 的 JSON有的是 LabelMe 导出的形状文件。统一格式是最耗时但必须做的一步。下面这个脚本能把 VOC 的 XML 标注转成 YOLO 格式同时过滤掉被标记为 difficult 的目标。import os import xml.etree.ElementTree as ET from PIL import Image def voc_to_yolo(xml_path, img_path, out_path, class_names): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): cls obj.find(name).text.strip() if cls not in class_names: continue if obj.find(difficult) is not None: if obj.find(difficult).text 1: continue box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) x_c (x1 x2) / 2 / img_w y_c (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{class_names.index(cls)} {x_c:.6f} {y_c:.6f} {w:.6f} {h:.6f}) with open(out_path, w) as f: f.write(\n.join(lines)) class_names [rebar] voc_to_yolo(annotation/001.xml, images/001.jpg, labels/001.txt, class_names)这段脚本做的事情不复杂但有四个边界坑要留意。第一XML 里的框坐标有 1-based 和 0-based 的差异个别标注工具会从 0 开始计直接除图宽图高会整体偏移一个小像素归一化后虽然肉眼不明显但密集场景下会导致后续按中心点计数的逻辑出错。第二difficult 标签一定要过滤掉钢筋数据集中那些严重模糊或者只露出一角的钢筋如果被当成训练目标模型学到的特征就是残缺的推理时会输出大量低置信度框。第三图片实际尺寸和 XML 里 size 节点不一致的情况时有发生脚本里直接取 XML 的尺寸是默认信任标注工具稳妥做法是每次读取图片实际尺寸覆盖 XML 值。第四输出文件末尾不要留多余空行yolo 训练脚本读 txt 时遇到空行容易报错。3. 把钢筋计数拆成模型问题选型为什么不能直接抄通用检测方案3.1 密集小目标场景下通用检测器为什么集体翻车钢筋端面目标在 1080P 图片上通常只有 8 到 16 像素的直径属于典型的小目标。以 YOLOv8 这类单阶段检测器为例backbone 经过四次下采样后再进入检测头小目标的特征图分辨率已经被压得很低一个 8 像素的钢筋端面在下采样四倍后只剩 2 个像素几乎无法表达有效的纹理信息。所以直接用通用检测配置去训钢筋数据集最常见的结果是精度看起来还行但数量一统计就差几十根。解决路径有两条。第一是使用 P2 层特征图即把模型的检测头接到下采样两倍的特征图上牺牲一些速度来保留小目标的细节。这个改动在 YOLO 系里是一行配置的事但对显存的要求会明显上升。第二是改用无锚框的 DETR 类检测器DETR 通过可变形注意力在特征图上直接做集合预测天然对小目标更宽容但代价是训练收敛轮数更长且对标注质量敏感。钢筋计数这类场景我更推荐 DETR 的轻量化变体比如 RT-DETR它在密集小目标上的稳定性比 YOLO 系更高推理速度也在工业可接受范围内。这里还要敲一个重点钢筋计数模型追求的不是框和真值框的 IoU 有多高而是「数出来的数量」和真实数量一致。检测器输出的框哪怕偏移了几个像素只要中心点正确、置信度够高数量就不会错。反过来如果每个框都偏得准但漏了 5 根数量就直接不对。训练时的评价指标不能只看 mAP还要把「计数误差」拆出来单独跟踪。3.2 一个可落地的检测加计数联合方案针对钢筋计数我常用的方案是检测头加计数头的双头结构检测头负责对每根钢筋输出框和类别置信度计数头在特征图后端接一个全局池化回归出这一张图片的钢筋总根数。训练时两个头的损失加权相加推理时以检测头为主、计数头作交叉验证如果两者差值过大就触发人工复核。这个设计的好处是能针对「检测头漏检导致的计数偏小」做兜底计数头学的是全局密度特征漏检状态下它依然能输出接近真实值的数量。下面的配置片段以 YOLO 风格训练框架中的模型 yaml 为例展示如何把检测头扩展为双头结构。实际落地时不同框架的写法有差异但思路是一致的。# rebar_counter.yaml backbone: - [-1, 1, Conv, [64, 3, 2]] - [-1, 1, Conv, [128, 3, 2]] - [-1, 3, C2f, [128, True]] head: - [-1, 1, Conv, [256, 3, 2]] - [-1, 3, C2f, [256, True]] - [-1, 1, Conv, [512, 3, 2]] - [-1, 3, C2f, [512, True]] - [-1, 1, Detect, [1, [16, 32, 64]]] - [-1, 1, CountHead, [1]] # 全局池化 全连接回归总数这段配置里 Detect 层的三个锚框尺寸 [16, 32, 64] 是按钢筋端面的像素范围设定的如果采集图片距离远近变化大锚框尺寸也要跟着调整。CountHead 后面接的是全连接层直接输出一个标量损失函数用 Smooth L1权重设置为 0.5检测头的分类和框回归损失权重保持默认 1.0。这里的关键点在于两个头的损失需要在一个 batch 内同步计算不能先训检测头再训计数头否则计数头会干扰检测特征的学习。训练时数据增强也要针对小目标做调整。马赛克增强用默认配置即可但随机缩放的范围要收窄到 0.8 到 1.2 之间。缩放范围过大时钢筋端面会被缩成 2 到 3 像素的小点模型学到的基本上是噪声。随机上下翻转要关掉或者只保留水平翻转因为钢筋垛的排列方式与重力方向有关垂直翻转后模型会学到错误的排列规律。4. 训练一份能用的钢筋计数模型关键参数与后处理配置4.1 最优先调整的三个参数图片尺寸、batch size、anchor 分布训练钢筋计数模型时我通常先把输入图片尺寸定为 1280 乘 1280。这个尺寸对 1080P 的现场施工照片来说是一个放大上采样的过程虽然会增加训练耗时但对小目标召回率的提升是其他参数替代不了的。显存有限的情况下优先保图片尺寸而不是 batch size可以用梯度累积来模拟较大的 batch但不要为了 batch 而把图片缩到 640 以下。batch size 的选择上8 到 16 都是常见取值。如果训练过程中发现 loss 震荡明显先检查是不是 batch 太小导致 BN 层统计量不稳定。轻量化模型可以加大 batch但 DETR 类模型对 batch 敏感太大的 batch 会导致训练初期收敛过慢。另一个容易被忽略的参数是 anchor锚框分布如果你的框架支持自动聚类 anchor用训练集里的真值框重新聚类一次。钢筋端面的宽高比非常集中重新聚类后生成的 anchor 会更贴近真实分布模型训练起点更高。后处理时的置信度阈值也要单独调。通用检测任务里 0.25 是常见的默认值但钢筋计数场景中因为目标小且密集置信度普遍偏低0.25 会漏掉大量真目标。我一般把置信度阈值调到 0.1 到 0.15再用 NMS 的 IoU 阈值压到 0.5 来控制重叠框的保留。这两个值是在验证集上扫出来的不是拍脑袋定的。每次训练完成后导出一份「不同置信度阈值下的计数误差曲线」看曲线的平台段在哪就选哪。4.2 训练命令与 Loss 曲线判读用一个支持检测加计数双头的训练脚本命令大致如下python train.py \ --data rebar.yaml \ --model rebar_counter.yaml \ --img 1280 \ --batch 8 \ --epochs 300 \ --hyp hyp.rebar.yaml \ --weights yolov8n.ptrebar.yaml 里需要配置训练集和验证集路径、类别数、类别名。hyp.rebar.yaml 是超参数文件重点调整这几个值lr0 设为 0.001因为小目标检测任务初始学习率太大容易把特征学坏warmup_epochs 设为 3让模型先用小学习率热身。训练过程中重点看两个曲线总 loss 的下降趋势和验证集上的计数误差。这里说一个血泪经验不要只看 mAP。当一张钢筋照片有 800 根钢筋时模型漏掉 20 根可能 mAP 只掉了不到一个点但现场计数绝对误差是 20 根这已经无法接受了。必须额外写一个简单的评估脚本统计每个验证图片的预测根数与真值根数的差值分布。差值呈正态分布且标准差小于 5 的时候模型才算是真的学会了数钢筋。5. 标注文件里的 5 个常见坑现象、原因与解决5.1 编码把类别名搞乱训练时报 unexpected indent现象数据集里的 label 文件看起来正常但训练脚本加载时直接抛 UnicodeDecodeError 或者类别名变成了乱码。原因Windows 下用记事本编辑过标签文件后文件被存成了带有 BOM 的 UTF-8 格式python 的 open 函数默认用 UTF-8 读取时会读进 BOM 头类别名拼接时出现不可见字符轻则警告重则报错。还有一类是标注工具导出的标签文件用了 GBK 编码而训练脚本期望 UTF-8。解决统一用脚本清洗一遍所有标注文件把编码转为 UTF-8 without BOM同时把行尾符统一为 LF。检查标签中的类别名是否完全匹配配置文件中 classes 列表多余的空格或缩进都可能导致类别索引错位。5.2 漏标是计数不准的头号原因现象模型训练完大部分图片计数只差 5 到 10 根但个别图片差 50 根以上且误差集中在钢筋垛的中下部。原因标注员在疲劳状态下系统性漏标了被遮挡或者光线较暗的钢筋。这类错误极其隐蔽因为漏标不会让训练报错只会让模型学成「看不到的钢筋就不用数」。解决用训练好的模型对训练集做一次预测把预测框叠回原图抽检那些模型“多标出来”的区域看是模型幻觉了还是标注漏了。最好随机抽 10% 的训练图片做二次标注覆盖所有标注员的成果。数据集中如果存在这种系统漏标宁可删掉这几张图也不要留着因为它教给模型的是错误的视觉关联。5.3 钢筋端面的“咬边”与虚影导致框漂移现象模型预测框都落在钢筋端面边缘的明亮半圆弧上而不是落在整个圆形端面上计数对但对不准后续做定点复查困难。原因施工现场的钢筋端面往往有反光标注时如果只框了亮的那一半弧模型就只关注亮度特征而不是完整的圆形特征。反过来有些数据集用低分辨率截图标注钢筋边界模糊产生了虚影标注员把虚影也框了进来。解决在标注规范里强制要求框的上下左右边界都要在钢筋圆形轮廓的 4 个极点上拿不准的时候放大到 200% 再标。已经标完的数据用边缘检测算法或人工抽检筛掉那些框面积明显小于同类平均值的标注例如同一张图中同类目标框面积中位数的 60% 以下基本可以判定为半框。5.4 同一张图里两类标签混用现象训练时 loss 出现周期性跳变验证集计数误差忽大忽小。原因数据集由多人协作标注部分标注员对「可见即标」和「半遮挡推断」的理解不一致有人只标完整端面有人把轮廓可见的都标进来。这导致模型一会学完整目标特征一会学残缺目标特征。解决标签规范化脚本中增加一项检查统计标注文件的平均目标数偏离全局中位数太多的文件单独拉出来复核。更彻底的方案是对全部标注做一次可视化审查把标注框叠到图片上滚动检查人和人的标准差异必须回退到标注规范层面统一。5.5 验证集划分不当同场景照片泄露现象验证集指标非常好计数误差几乎为 0但模型到了新工地立刻翻车。原因数据划分时直接按图片随机 shuffle同一个钢筋垛从不同角度拍的十几张照片同时进了训练集和验证集验证集实际上变成了「见过的场景再考一遍」。解决按钢筋垛或者按拍摄批次划分数据集保证同一个物理对象的所有照片都在同一个集合里。更严格的做法是按工地划分训练集来自两个工地验证集来自第三个工地这样才能验证模型对新场景的泛化能力。这也是工业落地时最容易踩但最晚被发现的一个坑。6. 让计数精度再上一个台阶Slicing 推理与密度图校准到了模型能跑通、计数误差在可接受范围之后还有两个技巧能显著压降误差。第一个是 Slicing Inference把大图切成若干有重叠的子图分别推理再合并结果。钢筋垛现场照片动辄 4000 乘 3000 像素直接缩放进模型会丢失大量钢筋端面细节切成 1280 乘 1280 的子图后每根钢筋的像素直径能翻倍检测头更容易识别。切图时重叠率取 20%重叠区域的框需要去重合并合并的逻辑是两框中点距离小于阈值就视为同一根。第二个是密度图校准。用点标注生成密度图训练一个轻量计数模型每根钢筋中心点生成一个高斯峰推理时对密度图取局部极大值得到计数。这个模型的精度不一定比检测头高但它的错误模式与检测头不同检测头在严重遮挡时漏检密度模型在严重遮挡时会因为周围峰的叠加而出现少量漂移。把两个模型的输出做加权融合误差能再降 10% 到 15%。import numpy as np from scipy.ndimage import maximum_filter, label def count_from_density(density_map, min_distance6, threshold0.3): max_val maximum_filter(density_map, sizemin_distance) peaks (density_map max_val) (density_map threshold) labeled, num label(peaks) return num density_map model.predict(preprocessed_image)[0] rebar_count count_from_density(density_map, min_distance6, threshold0.3)这段代码里 maximum_filter 的作用是保留局部极大值区域min_distance 控制两个峰之间的最小像素距离阈值 threshold 过滤掉低置信度的杂散峰。钢筋端面直径在特征图上的像素大小直接决定 min_distance 该设多少特征图上一个钢筋端面映射为 6 到 8 个像素时min_distance 取 6 是一个稳健起点。如果发现计数结果偏高通常是杂散峰太多提高 threshold 而不是调 min_distance。最后说一个我自己的习惯。每次拿到新数据集我会先把全部标注文件跑一遍统计脚本输出类别数、总目标数、单张最大目标数、图片尺寸分布、框面积分布。这几项数字能快速判断数据集是否可用远比打开几张图片肉眼抽查更靠谱。做钢筋计数的模型不难难的是有一份边界干净、规则一致的标注文件它能帮你省下后面几周调参的时间。希望这些经验能让你在这个方向上少走一段弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑