
简介面向目标检测入门与实战的人行道crosswalk检测数据集特别适合需要训练行人过街场景检测模型的开发者与研究人员可用于YOLO系列或VOC格式模型的训练与评估。该数据集中包含793张真实场景图片均提供Pascal VOC格式xml标注与YOLO格式txt标注类别为单一的cross共805个目标框标注信息规范清晰可直接适配常见检测框架。资源包内共2000个文件以txt、xml、jpg三类为主其中xml与txt分别对应两套标注体系jpg为原始图像整体压缩包约39.45MB便于快速下载与解压使用。该资源目前已有144人学习下载。借助这套数据读者可以省去自行采集与标注的时间直接开展模型训练、精度对比或数据增强实验也可作为了解VOC与YOLO标注格式转换的参考样例适用于课程设计、算法研究或竞赛预热。1. 人行道检测为什么要单独建数据集700 张图能撑起什么项目人行道检测数据集在目标检测任务里属于“基础设施要素识别”这一类它和行人检测完全是两个方向行人检测找的是“人”人行道检测找的是“道”。真正做过这类项目的工程师都有体会人行道和普通路面的纹理、颜色太接近模型经常把铺装停车场当成行人区或者把马路牙子边缘当成目标框出来。这个压缩包里的 700 张 VOC YOLO 双格式数据价值在于省掉了最脏的标注整理环节解压后能直接进 YOLO 训练流程适合智慧城市、盲道占用巡查、市容监测、以及拿目标检测做毕业设计的人。接下来按“格式检查 → 接进训练 → 参数调整 → 结果验证”的顺序把整个落地过程讲清楚。2. 压缩包里到底有什么VOC 与 YOLO 双格式的目录和标注约定拿到 zip 别急着解压丢给训练脚本先把两种格式的内部目录和标签含义对齐。这类数据包最常见的打包习惯有两种一种是 VOC 和 YOLO 各一个根目录共用同一批原图另一种是只给 VOC 原始标注附带一个转换脚本YOLO 格式需要自己生成。不管你拿到的是哪种下面这几个目录和字段都要心里有数否则后面训练出的模型类别错位都查不出来。2.1 VOC 侧目录JPEGImages、Annotations、ImageSets 各管什么VOC 格式的目录结构是固定的三层。JPEGImages 放全部原图Annotations 放与图片同名的 xml 标注文件ImageSets/Main 是划分文件列表通常有 train.txt、val.txt里面每一行是图片名不带扩展名。如果包里没有 ImageSets说明划分要自己做这反而是常见情况很多数据集打包者默认使用者会用脚本自己划分。每个 xml 内部的结构值得花两分钟确认因为后面所有转换逻辑都建立在它上面。一个典型的标注对象是这样组织的我截一个最小片段annotation filenameIMG_0023.jpg/filename size width1920/width height1080/height /size object namesidewalk/name bndbox xmin320/xmin ymin540/ymin xmax1280/xmax ymax860/ymax /bndbox /object /annotationxml 里的 name 是类别名bndbox 是目标的左上角和右下角像素坐标。重点检查两件事一是 name 是否统一有时候一个包里 sidewalk 和 Sidewalk 两种大小写混着标会导致你的类别数凭空多出 1二是 bndbox 是否越界xmax 大于图片宽度、ymin 是负数这类问题在手工标注里非常常见。想要快速确认标注是否合理可以用 labelImg 或 X-AnyLabeling 这类目标检测常用标注工具直接打开 xml 看一眼几秒钟就能发现框和路面轮廓对不对。ImageSets 里的 txt 划分还有一个隐含约定如果只有单一文件列表而没有明确 train/val 分离那这个包大概率没做数据划分你需要自己按图名哈希或随机切分。切分时我一般会故意留出同一街区的图片不要同时出现在训练和验证集里否则验证的 mAP 会虚高这个问题后面第 4 章会展开说。2.2 YOLO 侧格式归一化坐标、类别序号与空标签文件的约定YOLO 格式这边简单很多每张图对应一个同名 txt每一行代表一个目标0 0.416667 0.648148 0.500000 0.296296四个数字的含义是类别序号、中心点 x、中心点 y、宽度、高度全部除以原图宽高做了归一化取值在 0 到 1 之间。类别序号必须严格对应 data.yaml 里 names 列表的下标这是双格式转换时最容易翻车的点——VOC 的 name 是人读的字符串YOLO 的类别是模型读的数字两边顺序一旦错位模型就把人行道学成了另一类。表格对比一下两种格式的差异对比项VOC xmlYOLO txt坐标表示左上角 右下角像素值中心点 宽高归一化 0~1类别表示字符串 name数字序号 class id文件对应Annotations/同名.xmllabels/同名.txt无标注图片没有 xml通常不生成 txt或保留空文件还有一个容易被忽略的约定YOLO 里“没有 txt”和“txt 是空的”在训练中表现不同。没有 txt 的图会被当作背景负样本参与训练空 txt 也是负样本但如果你用脚本批量扫描“空文件”来判断哪些图没标注会把两者混淆。我建议在清洗阶段明确区分异常漏标导致的空文件和有意保留的纯背景图分开存放后面调背景误检时要用到纯背景图。2.3 双格式互转的核心坐标原点、归一化分母与类别对齐理解了两种格式之后转换逻辑其实就是小学数学但三个细节必须盯住。第一坐标原点VOC 和 YOLO 的通用约定都以左上角为原点但有些标注工具导出时用了左下角为原点转换后所有 y 坐标都会镜像错位症状是框的上下方向完全反过来这个一眼能看出来。第二归一化分母YOLO 的宽高除以的是图片实际宽高不是 xml 里 size 节点写的宽高这两个值在图片被压缩过、重新保存过的情况下会不一致除以 size 里的数值会产生一层不易察觉的缩放误差。第三类别对齐如果原始数据里混了 crosswalk、zebra 这类“斑马线”标签而你的业务只需要人行道需要先在 xml 层做标签合并或过滤再到 YOLO 里重排序号不要等到训练时再处理。大部分打包者提供的 YOLO 格式版本转换时用的都是标准公式center_x (xmin xmax) / 2 / width宽高同理。这也意味着如果你后续要自己补标注最好固定用同一套 VOC → YOLO 的转换流程不要某些图手写 YOLO 坐标、某些图走转换脚本格式源头不统一后面所有数据增强和验证都会跟着出错。3. 把数据集接进 YOLO 训练格式体检、转换脚本与最小命令格式看明白了下一步就是把它变成能跑的训练项目。这一章我给出一条完整的最小路径先体检再转换最后用一条命令跑通训练。先说明一下我的环境假设Linux 或 macOSPython 3.10已经装好 ultralytics 库GPU 可选——700 张图用 CPU 也能训只不过慢很多建议至少一张 8GB 显存的卡。3.1 先跑一次标注体检统计类别、框数、异常框很多人的习惯是拿到数据集直接开训这样处理数据集用于 yolov8 训练前我建议多花十分钟跑一遍体检脚本它能帮你提前发现第 2 章提到的类别名混乱、异常框、漏标问题。下面这个脚本扫描整个 Annotations 目录统计类别分布、框总数、平均框尺寸并把宽高小于等于 1 像素的异常框数量报出来import os import xml.etree.ElementTree as ET from collections import Counter annotations_dir Annotations/ stats Counter() widths, heights [], [] total_boxes 0 bad_boxes 0 for xml_name in os.listdir(annotations_dir): tree ET.parse(os.path.join(annotations_dir, xml_name)) root tree.getroot() for obj in root.iter(object): name obj.find(name).text.strip() box obj.find(bndbox) w float(box.find(xmax).text) - float(box.find(xmin).text) h float(box.find(ymax).text) - float(box.find(ymin).text) stats[name] 1 widths.append(w) heights.append(h) total_boxes 1 if w 1 or h 1: bad_boxes 1 print(类别分布:, dict(stats)) print(总框数:, total_boxes) print(平均框宽高: %.1f x %.1f % (sum(widths)/len(widths), sum(heights)/len(heights))) print(异常框数量:, bad_boxes)脚本里我用了 strip 去除类别名首尾空格这是很多人会漏掉的细节xml 里name sidewalk /name这种带空格的情况很常见不去空格会平白多出一个类别。输出的类别分布里如果出现了超过预期的类别名比如 sidewalk 和 Sidewalk 同时存在说明原始标注不干净需要先做合并。平均框宽高则用来预估目标尺寸如果平均框宽只有 30 像素而图片宽度是 1920说明数据里小目标占比高后面的 imgsz 和增广策略都要往小目标方向调这个经验值我会在下一节直接用上。3.2 VOC 转 YOLO转换脚本与四个边界处理体检没问题之后写一个 VOC 转 YOLO 的脚本。网上类似的脚本很多但多数只处理理想情况我把真实数据最常见的四个边界情况都处理进去了类别不在预期列表里、坐标越界、宽高为负、图片路径缺失import os import cv2 import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, img_dir, out_dir, classes): os.makedirs(out_dir, exist_okTrue) tree ET.parse(xml_path) root tree.getroot() img_name root.find(filename).text img_path os.path.join(img_dir, img_name) img cv2.imread(img_path) if img is None: print(图片读取失败跳过:, img_path) return False h, w img.shape[:2] lines [] for obj in root.iter(object): name obj.find(name).text.strip() if name not in classes: print(未知类别 %s已跳过 % name) continue cls_id classes.index(name) bb obj.find(bndbox) x1 float(bb.find(xmin).text) y1 float(bb.find(ymin).text) x2 float(bb.find(xmax).text) y2 float(bb.find(ymax).text) # 越界裁剪避免负宽高和超出画布 x1, x2 max(0, x1), min(w, x2) y1, y2 max(0, y1), min(h, y2) if x2 - x1 1 or y2 - y1 1: continue cx ((x1 x2) / 2) / w cy ((y1 y2) / 2) / h bw (x2 - x1) / w bh (y2 - y1) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) if lines: txt_name os.path.splitext(img_name)[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines) \n) return True这段代码的关键参数都在边界处理上。classes 列表的顺序必须和你之后 data.yaml 里的 names 完全一致比如classes [sidewalk]转换后所有 txt 的类别号都是 0。坐标裁剪用max(0, x1)和min(w, x2)把越界框拉回画布内避免出现像 xmin1980、原图宽 1920 这种负宽度框YOLO 训练遇到负宽高会直接报错或者产生 NaN 损失。图片读取失败时不中断整个批处理只打印一行日志方便转换结束后统一排查哪些 xml 对应的原图缺失。转换完还要做一次反向抽检随机挑 5 到 10 张图把 txt 里的坐标换算回像素画出来和原图叠加肉眼确认框的位置、类别编号正确。这个抽检步骤很值得做它能发现坐标除以了错误分母这类脚本层面看不出来的问题。3.3 整理目录、写 data.yaml、跑通最小训练命令转换完成后的目录推荐按 YOLO 惯例组织train 和 val 分开images 和 labels 平行mkdir -p datasets/sidewalk_yolo/{images/{train,val},labels/{train,val}} cp VOC/JPEGImages/*.jpg datasets/sidewalk_yolo/images/train/ cp YOLO/labels/*.txt datasets/sidewalk_yolo/labels/train/如果原始包已经给了 train/val 划分按它的文件列表复制没给的话700 张图按 8:2 随机划分即可但注意按第 2 章说的尽量避免同一街区的照片同时出现在两侧。目录就位之后写 data.yamlpath: ../datasets/sidewalk_yolo train: images/train val: images/val nc: 1 names: 0: sidewalknc 表示类别数是 1names 列表的顺序和下标必须和转换脚本里的 classes 一一对应这是整个流程里最容易犯的错第 2 章和第 3 章我反复强调因为一旦错位模型训练不会报任何错误只会默默学错。最后跑训练。我用 yolov8n 做演示它在小数据集上收敛快、显存需求低如果你有更好的卡可以换 yolov8s 或 yolov8m精度会高一些但训练时间翻倍yolo detect train \ datadata.yaml \ modelyolov8n.pt \ imgsz640 \ epochs100 \ batch16 \ lr00.001 \ patience20 \ device0参数上我特意做了几个和默认值不同的选择。lr0 从默认的 0.01 降到 0.001因为 700 张小数据集用大学习率很容易导致 yolo 训练中 bn 崩溃那类损失震荡patience 设 20 表示连续 20 轮验证集没有提升就提前停止小数据集通常 60 轮左右就收敛了没必要傻等全部 100 轮。batch 至少要 16因为下面第 4 章会讲到batch 太小会触发 BN 层统计量不稳定。第一次跑通之后打开 runs/detect/train 里的 results.png看损失曲线和验证指标确认 yolov8 训练自己的数据集这条流程整体正常再进入参数调优阶段。4. 训练中的 4 个典型翻车点从 BN 崩溃到背景误检的排查数据量 700 张不算大训练过程里的坑反而比大数据集更集中。这一章我把最常踩的四个问题按“现象 → 原因 → 解决”写清楚你在自己的机器上大概率会遇到其中一个。4.1 现象训练到一半 loss 变 NaN、mAP 突然归零训练曲线前期看着正常跑到十几轮的时候损失突然变成 nan或者验证 mAP 从某个点直接砍到 0这种“腰斩”是小数据集训练最典型的翻车。原因通常是两层叠加一是 batch 太小BN 层的均值和方差估计不稳定个别异常样本就把统计量带崩二是学习率偏大梯度更新一步迈过头。另有一个隐蔽诱因是 labels 目录里有 0 字节的 txt模型读到空目标时产生无效梯度。解决分三步。第一步检查数据扫描 labels 目录里所有 0 字节文件确认它们是纯背景图而不是漏标注漏标注的图从训练集移出。第二步调参batch 拉到 16 以上lr0 降到 0.001 以下这两个参数对训练的稳定性影响最大。第三步如果还崩用预训练权重并从第 0 层开始冻结前 10 层只训练检测头这是目标检测模型微调崩了的时候最稳的兜底方案。做完这三步BN 崩溃基本不会复现。4.2 现象人行道和普通路面分不清误检集中在硬质铺装区域模型把停车场、广场砖、甚至柏油路边缘框成人行道这是人行道检测最让人头疼的问题本质上是类别定义问题而不是模型问题。人行道和普通路面都是灰色硬质铺装视觉特征高度重叠单纯靠 700 张标注图很难把边界学清楚尤其是标注里如果连“斑马线人行横道”和“连续人行道”都混在了同一个 name 下模型会更加困惑。解决这个问题的核心是补负样本和统一标签语义而不是调模型。先花半小时抽查 30 张标注图确认“人行道”这个标签到底对应哪些区域如果斑马线和连续铺装混标建议把业务上不需要的那一类删掉或单独分出去重新对齐。然后收集一些不含人行道的街景图、停车场图、公园步道图作为纯背景加入训练集YOLO 训练会自动把这些图当作负样本误检率会肉眼可见地下降。这个“补负样本”的动作比任何数据增强都有效我后面第 5 章还会展开。4.3 现象近处人行道能检出远处全漏验证集里近景的人行道基本能框住中远景的人行道要么漏检要么框偏这是小目标问题的典型表现。700 张图里远处人行道在画面中往往只占几十到一两百像素宽imgsz640 的情况下这部分目标经过下采样后特征图上的尺寸已经很小了检测头很难给出稳定预测。我的调整路径是这样把 imgsz 从 640 提到 768 或 896能明显改善小目标召回代价是训练和推理都变慢同时调整马赛克增强概率ultralytics 默认 mosaic1.0但小数据集建议降到 0.5 左右避免马赛克裁剪把小目标切掉。另一个有效办法是把含小目标的图片做离线拼接比如把 12 张含远距离人行道的图拼成一张大图相当于变相增加了小目标的密度这个做法对这类区域型目标比单纯复制粘贴更有效。如果推理场景固定是无人机俯拍或高位摄像头还可以考虑切片推理把大图切成 640 的小块分别检测再合并很多做自动驾驶数据集的人就是这么处理远距离目标的。4.4 现象验证 loss 在降mAP 纹丝不动损失曲线一路向下但验证集 mAP 始终在低位徘徊甚至震荡这说明模型在“背”训练集而不是“学”特征。原因大概率出在数据而不是模型上一是训练集和验证集分布重叠太大比如随机划分时同一街区的照片同时进了两边验证指标虚高迁移到新场景就崩二是标注噪声大框偏大偏小、边缘贴得不紧模型学到的是“大概在那个位置”而不是“精确到路面轮廓”。我一般会先检查划分方式。按场景或拍摄街区分组划分而不是全量随机打散验证结果更接近真实部署。然后检查标注质量重点看框的下边界——人行道检测的框如果下边界经常压住马路牙子或干脆延伸到路上需要重新对齐标注。还有一个细节如果验证集里每一张图都有目标mAP 会被拉高真实场景里大量图片没有目标所以验证集里刻意放一些空场景图更符合实际部署评估。5. 700 张不够用的补法数据增广与迁移学习的参数调整700 张图对目标检测来说是个“能跑但偏少”的量级。它够你做实验、够你出 demo、够毕业设计展示效果但如果你想让它稳定接手真实场景数据层面必须补东西。这一章讲清楚怎么判断够不够、补什么、以及迁移学习的参数怎么配。5.1 先算算这 700 张够不够有效样本量与场景覆盖判断数据量够不够不能只看图片数要看“有效正样本数”和“场景多样性”。如果平均每张图有 2 到 3 个标注框那么 700 张图能提供约 1500 到 2000 个正样本这个量级训练一个单类检测器是可行的前提是场景足够分散——不同道路结构、不同光照、不同拍摄高度都要覆盖。反过来如果 700 张图都是同一个街区同一个机位拍的那模型本质上只学会了一个固定视角换个城市直接失效。我的判断标准是光源变化顺光、逆光、阴天、夜间灯照、路面材质砖石、沥青、彩色透水砖、遮挡程度停放的车辆、摊位、行人遮挡这三个维度每个维度至少有 30 张以上样本覆盖。如果打开压缩包发现大部分图集中在晴天白天同一个视角那这个数据集只适合做算法验证不适合直接做产品模型。这时候要做的工作不是简单增广而是先明确你的目标场景再有针对性地补拍或者找公开街景数据。5.2 人行道适合的增广组合不要无脑复制粘贴数据增强是补数据最省成本的方式但要按目标的物理特性来选。人行道是地面静态目标语义对翻转相对稳定但纹理细节对扭曲和裁剪非常敏感。我整理了一张常用增广的配置表按人行道场景的适用性排序增广方式推荐参数适用性说明HSV 色彩抖动h0.015, s0.7, v0.4很推荐人行道颜色受天气和光线影响大随机翻转水平 0.5垂直不开水平翻转安全垂直翻转会破坏街景语义Mosaic概率 0.5提高小目标密度但小概率会裁剪掉目标Copy-Paste概率 0.2人行道区域大直接粘贴容易纹理断裂谨慎用Random Erase概率 0.2模拟车辆、行人遮挡对遮挡场景有效尺度缩放0.5~1.5模拟远近变化对小目标训练帮助大重点提醒一下 Copy-Paste。行人、车辆这类独立目标适合复制粘贴但人行道是连续的地面区域把一块人行道贴到另一张图上接缝处的纹理不连续模型容易学出“人行道必须带边框感”的错误特征。我一般只在目标比较完整、占比不大的图上用而且概率压得很低。相比之下HSV 抖动和尺度缩放是投入产出比最高的两个增广。5.3 微调参数预训练权重、冻结层与学习率怎么配小数据集从零训练效果通常不好正确做法是拿 COCO 预训练的权重做迁移学习。这里给出我实测稳定的参数组合已经在多个类似的地面目标检测项目上验证过你可以直接作为起点参数建议值说明modelyolov8n.pt / yolov8s.pt数据量小优先用轻量预训练模型freeze10冻结主干前 10 层保留基础特征lr00.001默认 0.01 对小数据偏大lrf0.01余弦退火到初始学习率的 1%epochs100结合早停一般在 60 轮左右收敛batch16~32越大 BN 越稳定显存不够就降 imgszwarmup_epochs3~5预热期加长避免开局震荡freeze10 的意思是前 10 层参数不参与更新只微调后面的层。好处是能用预训练模型在 ImageNet 或 COCO 上学到的底层纹理特征避免小数据集把主干带偏。如果你的数据里路面纹理和 COCO 差异很大比如大量俯拍红外图freeze 可以减小到 5 甚至 0让主干更快适应新域。这里的取舍是数据越接近自然光街景越适合多冻结数据越风格化越要少冻结。跑完一轮之后把学习率和冻结层各做一个简单的网格搜索lr0 在 0.0005~0.002 之间试两档freeze 在 5 和 10 之间试两档基本就能找到这个数据集的甜点区。不要一上来就套用大模型的默认参数那是目标检测模型微调最容易崩的根源之一。这笔时间花得很值后面验证阶段的收益全看这一节参数选得稳不稳。6. 结果怎么才算合格混淆矩阵、误检回看与数据回填训练结束别急着看 mAP 就下结论。我会先跑一次验证把预测结果和混淆矩阵一起导出来yolo detect val \ modelruns/detect/train/weights/best.pt \ datadata.yaml \ conf0.25 \ save_jsonTrue这一步会输出混淆矩阵图片、PR 曲线和各类别指标。很多人看到混淆矩阵的格子加起来不等于 1 会慌这是正常的——它按行做了归一化每行代表一类真实目标的召回分布行内数值相加才是 1跨行看总和没有任何意义yolo 混淆矩阵总合不唯一是可视化设定问题不是模型缺陷。真正要看的是对角线之外的那一格人行道被分到背景的比例高说明漏检严重背景被人行道占的比例高说明误检严重。结合这两列才能准确判断模型卡在哪个环节。然后做一件事从验证集里挑出置信度在 0.3 到 0.7 之间的预测图一张一张看。这个置信度区间是误检和漏检最集中的区域比单纯看最高分的图更能暴露问题。如果发现误检集中在某个固定背景比如红色透水砖的广场那就回到第 4 章的思路把这些背景图作为纯背景样本回填到训练集再训一轮。这种“验证 → 回填 → 重训”的循环是我做人行道检测这类地面目标项目最常用的迭代方式比反复调网络结构见效快得多。最后一条个人习惯每次训练完先看预测图再看指标。指标会骗人但图上框的位置和边界不会。这个数据集的正确打开方式是先花半小时做格式体检和标签语义确认再进训练而不是解压后直接开跑。按这条路径走下来700 张数据足够让你在一个周末内得到一个可演示、可继续迭代的单类人行道检测器。希望帮到你。本文还有配套的精品资源点击获取