ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

钢筋计数数据集与YOLO标注:从标注体检到目标检测训练实战

钢筋计数数据集与YOLO标注:从标注体检到目标检测训练实战 简介面向人工智能钢筋计数算法开发的VOC格式标注文件包共包含568个xml文件压缩包整体大小仅1.07MB。该标注包属于完整钢筋计数数据集中的训练集标注部分需与对应训练图片配套使用二者结合后即可构成用于目标检测模型训练的标准VOC数据集。每个xml文件都记录了对应图片中的钢筋目标标注信息包含目标框坐标与类别标签等关键字段能直接用于YOLO、Faster R-CNN等主流检测框架的数据格式转换大幅削减人工标注钢筋的时间和成本。资源目前已有659人学习或下载在钢筋自动盘点、智慧工地、建材数量统计等实际场景中具有较高参考价值。开发者可参考博客中的图片质量预览确认标注风格是否匹配自身需求后再获取并利用这份标注文件快速搭建钢筋计数算法实验环境顺利开展训练、验证与效果对比。1. 钢筋计数数据集工地清点为什么非要一套带标注文件的图像库“钢筋计数数据集”这几个字一出来常做智慧工地项目的朋友应该立刻有画面一堆钢筋卸在料场监理要在一个小时内清点这车货的根数。人工数法是用粉笔在每根端头画一道蹲着绕着钢筋走几百根下来腰酸眼花还容易数漏。现在的做法是拍一张俯拍照交给目标检测模型自动数。要让模型会数先得有一批照片和对应的标注文件——每根钢筋在图上哪个位置、属于哪一类都要写进标签里。这份人工智能钢筋计数数据集的核心资产就在标注文件上它决定了模型学会的是“数根数”还是“数捆数”也直接决定验收时误差有多大。适合谁做智慧工地物料盘点、搞目标检测毕设、以及想从通用检测切到细分场景的工程师。2. 先看懂标注文件YOLO、VOC、COCO三种格式下的钢筋目标长什么样拿到钢筋计数数据集第一步不是急着训练而是先解压把标注文件读一遍。这类数据集通常是一个图片文件夹加一个标注文件夹图片和标签同名用扩展名区分。标注文件的价值在于把“哪里有什么”量化成模型能学的数字读不懂它后面所有训练和排查都像在黑匣子里碰运气。2.1 标注文件里到底记了什么类别、坐标和难样本标志YOLO格式的txt标注最简单每一行是五个数类别id、中心点x、中心点y、框宽、框高其中x、y、宽、高都除以图片宽高做了归一化。VOC格式用xml存储标签里是xmin、ymin、xmax、ymax这类像素绝对坐标肉眼核对最直观。COCO格式则是一个json文件bbox、area、segmentation打包在一起适合用pycocotools做评价。一个钢筋计数数据集里通常不会只有一种格式作者可能同时提供多种转换结果也可能只给一种。先确认手上是什么格式再决定训练流程。目标类型要分清楚。钢筋计数数据集里的目标一般有两种单根钢筋端面以及整捆钢筋的外包框。端面目标在照片里是圆形或椭圆标注时用矩形框包住它成捆钢筋则是长条形状。这两种目标的像素尺寸差很多端面在一张2000像素宽的图片里可能只有20x20像素属于标准的小目标。标注文件里偶尔还会带一个难样本标记用来表示被遮挡超过一半、人眼都吃不准的端面。训练时可以选择忽略难样本也可以把它们当成负样本这需要看设计说明——如果没有注明我建议把难样本从训练集里挑出来单独验证避免模型被迫拟合模糊样本。2.2 自己动手写一个标注解析脚本验证数据集是否干净拿到标注文件先别直接训练写个脚本做基础体检。下面的脚本解析YOLO标签检查字段数、坐标越界、宽高非正、类别编号异常等常见问题。# 解析YOLO格式标注文件并做基础检查 from pathlib import Path def check_yolo_label(txt_path: Path, img_w: int, img_h: int): issues [] with open(txt_path, r, encodingutf-8) as f: for line_no, line in enumerate(f, 1): parts line.strip().split() if len(parts) ! 5: issues.append(f行{line_no}: 字段数不为5, 内容{line.strip()}) continue cls int(float(parts[0])) xc, yc, bw, bh (float(v) for v in parts[1:]) if not (0 xc 1 and 0 yc 1): issues.append(f行{line_no}: 中心点越界 xc{xc}, yc{yc}) if bw 0 or bh 0: issues.append(f行{line_no}: 宽或高为非正数 bw{bw}, bh{bh}) x1, y1 (xc - bw / 2) * img_w, (yc - bh / 2) * img_h x2, y2 (xc bw / 2) * img_w, (yc bh / 2) * img_h if x1 -1 or y1 -1 or x2 img_w 1 or y2 img_h 1: issues.append( f行{line_no}: 框超出图像边界 x1{x1:.0f}, y1{y1:.0f}, fx2{x2:.0f}, y2{y2:.0f} ) return issues # 用法: 遍历labels目录, 传入对应图片的宽高 for label_file in Path(rebar_data/labels/val).glob(*.txt): img_file Path(rebar_data/images/val) / (label_file.stem .jpg) if not img_file.exists(): print(f缺少对应图片: {label_file}) continue # 实际项目里用cv2.imread读取后取shape problems check_yolo_label(label_file, img_w1920, img_h1080) if problems: print(f{label_file.name}:) for p in problems[:5]: print( -, p)这段脚本的逻辑是按行解析出五个字段先做数值合法性检查再把归一化坐标还原成像素坐标判断框有没有超出图像边界。最容易被忽略的是越界检查很多转换脚本在裁剪图片时会顺手改标注但改完的框可能已经跑到图外。脚本里的img_w和img_h要传原图的实际尺寸不要传模型输入尺寸否则检查结果没有意义。建议先跑一遍val集把有问题的文件单独拎出来同时统计没有标注文件的图片——在目标检测里一张图没有任何标签要么是纯背景负样本要么是漏标。提示标注文件是模型学习的唯一答案。如果标签本身越界、错位、漏标训练时模型会把这些错误当成“正确答案”等推理阶段发现问题再回头查标注成本比一开始慢得多。2.3 钢筋计数的“目标”边界按根数数还是按捆数数同样是钢筋计数数据集标注口径不同模型能回答的问题完全不同。标注对象是单根端面模型输出的是根数标注对象是成捆钢筋的外包框模型输出的是捆数。拿到数据先看类别名和说明类别里只有一个class那就数一下每张图的框数分布一张图七八十个框的多半是端面级一张图只有五六个框的多半是捆级。这个判断直接决定误差容忍度数根数允许几个百分点的误差数捆数是0误差——捆数错了就是漏计一车货。另一个边界问题是“算不算被挡住的钢筋”。标注规范里如果不写明“完全被遮挡的端面不标”不同标注员会按自己的理解处理有的标了一半遮挡的有的只标完整露出的模型学到的目标定义是矛盾的。我一般会拿数据集的说明文件和3张最乱的图对一下如果完全遮挡的端面也被标了那模型要去猜根本看不见的物体工程上很难接受。这种时候宁可用“只数可见端面”作为验收口径让模型把能数的数准。如果数据集给的是VOC或COCO格式还要做好转换。常见做法是用ultralytics自带的JSON转YOLO脚本或者用labelimg等工具重新导出。转换时最容易翻车的是类别id顺序对不上——COCO里可能是空的类别占位符YOLO的类别编号必须连续从0开始一旦id错位训练出来的模型会把钢筋识别成背景。转换完用2.2的解析脚本再跑一遍确认没有越界和id问题。这一条检查接近数据集的“后悔药”错过之后再改等于重训。3. 用标注文件训练钢筋计数模型YOLOv8从零跑通的最小流程标注文件检查通过就可以进入训练环节。目标检测方向用YOLOv8最省心官方仓库把数据加载、增强、评估都封装好了站在前人的肩膀上可以少写很多底层代码。算力有限的团队用yolov8n或yolov8s起步先跑通再换大模型。3.1 环境准备与数据集目录结构环境准备两条命令pip install ultralytics pip install sahi # 后面切片推理会用到ultralytics会顺带把torch、torchvision装好前提是本机cuda环境可用。装完后先跑一个命令验证环境yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg。这是业内标准做法能最快暴露cuda和显存问题。数据集目录结构按YOLO惯例组织rebar_data/ ├── images/ │ ├── train/ # 训练图片 │ └── val/ # 验证图片 ├── labels/ │ ├── train/ # 与图片同名的txt标注 │ └── val/ └── rebar.yaml # 数据集配置rebar.yaml内容如下path: ./rebar_data train: images/train val: images/val names: 0: rebar_end 1: rebar_bundle如果数据里只有一种目标names只写一行。注意path推荐写相对路径和images/labels在同一层不要写绝对路径项目换机器后绝对路径直接翻车。图片和标注文件必须严格同名jpg对应jpg.txt训练前确认val目录里的图在labels里有对应文件否则yolo会报“found no labels”这是最常踩的第一道门槛。3.2 训练参数怎么设imgsz、batch、epochs对密集小目标的影响训练命令yolo detect train \ modelyolov8n.pt \ datarebar.yaml \ imgsz1280 \ batch8 \ epochs100 \ patience15 \ mosaic0.5 \ project./runs/rebar_countimgsz1280是钢筋计数场景的必调项。端面目标只有20x20像素用640训练时下采样32倍后只剩1个像素的有效信息模型几乎不可能学到端面纹理。升到1280后小目标在特征图上的响应明显增强。代价是显存8GB显卡开batch8直接OOM先降到batch4或者打开AMP混合精度。如果显存还是不够优先保证imgsz把batch压到2也比用640训练强。batch太小会导致BN统计不稳定常见做法是batch4起步开AMP训练完再调。epochs先设100用patience15早停模型一般到50个epoch就收敛。mosaic增强在密集小目标场景建议降到0.5甚至关掉——马赛克把多个图拼在一起钢筋端面会被切到图片边缘标注框跨图模型学到的是被截断的钢筋假象。血泪教训默认mosaic1.0在钢筋数据集上反而掉点。3.3 训练完先别信mAP用推理脚本统计单图计数误差训练结束会打印验证集mAP50和mAP50-95但计数任务的考核标准是“数得准不准”不是“框得准不准”。我在项目里从不在mAP上验收而是直接在验证集上数一遍# 在验证集上统计单图计数误差 from ultralytics import YOLO import numpy as np from pathlib import Path model YOLO(./runs/rebar_count/weights/best.pt) def read_yolo_count(label_path: Path) - int: count 0 if label_path.exists(): for line in label_path.read_text().strip().splitlines(): parts line.split() if len(parts) 5 and int(float(parts[0])) 0: # 只数类别0 count 1 return count errors [] for img_path in sorted(Path(rebar_data/images/val).glob(*.jpg)): results model.predict(sourcestr(img_path), conf0.25, iou0.45, verboseFalse) pred sum(1 for b in results[0].boxes.cls if int(b) 0) # 预测根数 true read_yolo_count(Path(rebar_data/labels/val) / (img_path.stem .txt)) errors.append(pred - true) errors np.array(errors) print(fMAE: {np.mean(np.abs(errors)):.2f}) print(f最大单图偏差: {np.max(np.abs(errors))})这里的逻辑是遍历验证集图片预测出属于钢筋端面这个类别的框数量和标注文件上的框数量做差。注意类别过滤如果数据集里同时有端面和捆两类统计根数时只数端面类把捆类框忽略掉。conf0.25是默认阈值如果推理时误检多可以提高到0.4看误差变化。mAP会骗人一个模型可能框的位置都很准但在密集区漏了一半目标mAP只掉几个点MAE却翻了倍。反过来mAP略低的模型可能计数很稳。上线前一定以计数误差为准mAP只当辅助参考。确认误差能接受后再进入切片推理和密度图方案。4. 数据集最常见的4个坑标注错位、漏标重标、小目标和背景干扰钢筋计数数据集在工地场景里拍出来的图和公开的通用目标检测数据集差别很大密集、遮挡、现场光照差。这些客观条件最终都沉淀到标注文件上变成模型学习的噪音。如果这些坑全踩一遍模型效果不会崩得很难看但计数误差会一直卡在5%以上下不去怎么调参都没用。我见过不少团队把时间花在刷模型结构上最后发现瓶颈在标注。下面列几个最容易翻车的点每个都配排查方法。4.1 标注错位标签框中心偏移半根钢筋AP掉得悄无声息**现象**训练loss正常下降验证集mAP50也有0.85以上但把预测框画出来看框的中心整体偏向端面的右下侧。计数时边缘的钢筋因为框偏移后IoU不足被NMS滤掉单图少三五根。**原因**半自动标注工具上一轮自动检测的结果粘贴时锚点错位或者数据转换脚本里减偏移量的公式写错导致所有框往同一个方向偏。错位不严重时模型会学着把“偏移后的框”当成正确答案所以loss照样收敛这属于最难发现的隐蔽问题。**解决**随机抽30张验证图用opencv把预测框和标注框一起画在原图上做对比人工看错位方向。更快的办法是做一个自动统计对每张图把预测框中心和标注框中心做最近邻配对统计x、y方向的平均偏移偏移超过3个像素就说明标注或推理有系统偏差。修正标注后重新训练不要在原标注上凑合。4.2 漏标与重复计数密集遮挡下的标注不一致**现象**同一个端面在标注文件里出现两个重叠的框或者某个端面一个框都没有。模型在重叠框位置学出两个相邻的置信度峰值推理计数时多算一根训练时漏标区域被当背景推理时该处又出现误检。**原因**钢筋堆叠时端面彼此紧贴标注员一屏看几十个目标很容易把相邻两根看成一根或者把一个端面框了两遍。密集场景下不同标注员的漏标率能达到5%以上。**解决**一致性检查。常见做法是拿同一张图找两个标注员各标一遍对两个标注结果做匹配IoU大于0.5的算一致匹配不上的框单独抽出来人工复核。没有两个标注员时做一个启发式检查统计所有框中心点的两两距离距离小于4像素的重叠对直接标记为“疑似重复”。漏标最集中的区域通常是图片边缘和堆叠中心这两处优先复查。4.3 小目标与模糊端面为什么钢筋端面在YOLO里这么难学**现象**端面在训练集里学了100个epochrecall仍然只有0.7漏掉的基本是远处料堆上的小端面模糊得人眼都要凑近看。**原因**YOLO下采样32倍一个16x16像素的端面落到特征图上只有半个像素数据增强里的随机裁剪也会把端面切出框外。小目标占框面积小在回归loss里权重天然低模型优先顾及大目标。**解决**imgsz提到1280是第一步再结合切片推理兜底。训练时用copy-paste增强把标注框里的端面贴片随机复制到图的其他位置让模型见到更多小端面。还有一个工程习惯把模糊端面统一标记为难样本训练时降低难样本的loss权重避免模型为了拟合看不清的目标牺牲清晰目标的精度。4.4 类别失衡与背景干扰钢筋缝隙里的垫木纹理被当成目标**现象**推理结果里出现一串细长框打在钢筋之间的垫木缝隙或混凝土模板纹理上单图误检十几根。**原因**垫木纹理的灰度分布和钢筋端面接近但背景没有负样本标签模型无法区分“像钢筋但不是钢筋”的区域。类别失衡的本质是正样本太多、负样本缺失。**解决**在数据集里加入不含任何目标的纯背景图数量占训练集5%左右图片上做一个空的标注文件。训练时yolo会把这类图当成负样本学。另一个立竿见影的手段是推理时把conf阈值从0.25提到0.4代价是召回略降但误检大幅下降。如果这两招都不够考虑给背景单独加一个类别用少量背景框做显式负样本。排查顺序建议是先看纯背景图有没有加再看conf阈值能不能提最后才考虑给背景加类别——前两步5分钟能验证第三步要改标注文件重新训练。5. 让计数更准密度图回归与SAHI切片推理的取舍检测框计数在端面清晰、遮挡不严重的场景下够用一旦钢筋堆成小山端面互相遮挡检测框方案漏检会变得明显。这时要决定是换密度图回归还是继续用检测框但配合切片推理。5.1 检测框计数 vs 密度图计数什么时候换方案检测框计数的输出是每个目标的位置和置信度可解释性强能和标注框做逐点对比对误检漏检定位精确。它的上限受标注质量影响遮挡严重的区域本来就是标注难点漏标直接变成漏检。密度图计数则是回归一张密度图对全图做积分得出目标总数思路源自crowdhuman数据集这类密集人群计数任务在极端密集场景下不用关心单个目标是否被标注完整只要总数对得上就行。方案输出密集遮挡鲁棒性可解释性标注依赖检测框计数每个目标的框和置信度中高每个目标都要标密度图计数每像素密度积分得总数高低只需点标注或总数我的选择习惯是端面平均像素尺寸大于40x40用检测框平均只有20x20且重叠率30%以上优先密度图。密度图需要单独准备标注——点标注中心生成高斯密度图不能直接用检测框训练。工程上两者并不互斥可以先训检测框模型再在困难验证集上对比两种方案的MAE让数据说话。5.2 用SAHI对高分辨率钢筋堆放图做切片推理高分辨率原图直接进模型会先被resize到1280远处的小端面缩放后丢失。sahi库的切片推理是常见解法把原图切成小块每块独立推理后再合并结果。# 使用SAHI对高分辨率钢筋照片做切片推理 from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction detection_model AutoDetectionModel.from_pretrained( model_typeultralytics, model_path./runs/rebar_count/weights/best.pt, confidence_threshold0.25, image_size640, # 切片输入尺度, 不是原图尺度 devicecuda:0 ) result get_sliced_prediction( imagerebar_site.jpg, detection_modeldetection_model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2, ) # 统计所有属于端面类别的预测框 rebar_count sum( 1 for obj in result.object_prediction_list if obj.category.id 0 ) print(预测根数:, rebar_count)切片大小和重叠率是必调参数。slice_height和slice_width取640或1280目标越小切片越小但切片太小会让同一根钢筋被切成多块合并阶段容易重复计数。overlap_height_ratio和overlap_width_ratio取0.2作用是让跨切片的钢筋至少在一个切片里完整出现。显存充裕时用1280切片、0.2重叠计数稳定性最好显存紧张时降到640代价是推理时间变长。切片会带来后处理合并sahi默认做了nms如果计数仍然偏高检查是不是同一目标在相邻切片被保留了两个框。5.3 验证结果用MAE和RMSE替代mAP考核计数任务计数任务的标准验证不是mAP而是直接对比预测总数和真实总数的误差。常用三个指标# 计算计数误差的三个指标 import numpy as np from sklearn.metrics import mean_absolute_error, mean_squared_error # y_true: 每张验证图的真实根数 # y_pred: 每张验证图的预测根数 y_true np.array([42, 38, 55, 61, 47]) y_pred np.array([44, 37, 58, 66, 45]) mae mean_absolute_error(y_true, y_pred) rmse np.sqrt(mean_squared_error(y_true, y_pred)) mape np.mean(np.abs(y_true - y_pred) / np.clip(y_true, 1, None)) * 100 print(fMAE{mae:.2f}, RMSE{rmse:.2f}, MAPE{mape:.2f}%)MAE是最直观的平均误差RMSE会放大个别大误差样本如果某张图偏差20根RMSE会显著变大适合暴露极端情况MAPE是相对误差适合向监理汇报“平均误差3%”。注意MAPE在真实计数为0的图上会除零要先clip或过滤纯背景图。这三个指标比mAP更容易向非技术角色解释验收会上直接报“平均误差2.3%最大单图偏差6根”比报“mAP50 0.88”有说服力得多。6. 把数据集用出价值交付模型前先做一轮标签体检与数据闭环模型训练完、计数误差也验证过整个工程还差最后一步把这份标注文件真正变成可维护的数据资产。钢筋计数数据集不只是用来训一次模型它会在不同工地、不同光照、不同堆放角度下反复迭代。6.1 动手前先做一轮“标签体检”微调模型或者换新工地之前先对现有标注做一轮统计体检确认标签质量没有随迭代变差。# 快速检查: 统计类别分布与框尺寸分布 from pathlib import Path import numpy as np sizes [] cls_counts {} for txt in Path(rebar_data/labels/val).glob(*.txt): for line in txt.read_text().strip().splitlines(): parts line.split() if len(parts) ! 5: continue cls int(float(parts[0])) bw, bh float(parts[3]), float(parts[4]) cls_counts[cls] cls_counts.get(cls, 0) 1 sizes.append((bw, bh)) print(类别分布:, cls_counts) sizes np.array(sizes) print(f框宽均值{sizes[:,0].mean():.3f}, 框高均值{sizes[:,1].mean():.3f})这个脚本能快速暴露两类问题类别框数量分布严重不均以及标注框尺寸与目标真实尺寸不符。比如框宽均值0.01说明大量目标只有十几个像素宽后续必须用SAHI或更高分辨率训练某个类别框数只有另一个类别的十分之一说明数据不平衡要先补样本。我拿到的第一批钢筋数据就是靠这个体检发现“捆”和“根”两个类别混标比例的偏离肉眼根本看不出来。6.2 数据闭环从现场照片到可迭代数据集把标注文件用起来的关键是形成闭环。完整流程是现场按规范拍照俯拍为主、避免强逆光、让端面尽量出现在画面中部把照片交给初版模型做自动预标注人工只修正错漏修正后的标注补进训练集再增量训练。增量训练用已有权重而不是从头训epochs设20到30就够重点是不要让新标注里的噪音污染旧标注学到的特征。我第一次做钢筋计数时拿到标注文件没做任何体检就训完一版验证集MAE一直卡在7%下不去调了几天参数毫无起色。后来用标签体检脚本逐类排查发现标注口径里混了一半“捆”一半“根”模型在两个目标定义之间反复横跳。把标注统一成“根”之后MAE直接掉到2.5%。这件事之后我的习惯是任何数据到手先体检、再训练、后迭代把标注文件当成和模型权重一样重要的交付物。这份人工智能钢筋计数数据集的真正价值不在图片张数而在标注文件的准确性和口径一致性。希望帮到你。本文还有配套的精品资源点击获取
返回列表