简介:这份建筑物检测数据集面向从事目标检测与实例分割的算法工程师、高校研究者及AI学习者,聚焦城市建筑场景下的单类别识别需求。数据覆盖训练集1076张、验证集103张、测试集51张,共1230张JPEG图像,均采用YOLO格式标注边界框与类别标签,可直接接入主流深度学习框架训练。压缩包共2000个文件,含1230个txt标注文件、768个jpg图像、1个yaml数据配置及1份docx说明文档,整体约45.23MB,目录结构清晰便于快速加载。数据集可服务于城市规划与建筑监测、房地产评估、自然灾害后建筑状态排查,以及自动驾驶与无人机航拍中的建筑定位等场景。其优势在于标注精准、类别专注、场景多样,有助于提升模型在不同环境下的泛化能力。目前已有95人学习关注,适合需要快速验证建筑物检测方案或补充行业数据的中高级开发者参考使用。
1. 建筑物检测数据集:从压缩包到可训练模型的落地路径
如果你正在做遥感影像或航拍图里的建筑物提取,大概率绕不开两件事:一是找不到带像素级标注的干净数据,二是好不容易找到一份,解压后发现格式对不上、类别对不齐、训练时 loss 直接炸成 NaN。这份建筑物检测数据集_20251116_120515.zip就是冲着第一个问题来的——它是一份面向 YOLO 目标检测与实例分割任务的行业数据集,标注覆盖建筑物边界框与掩膜,适合直接喂给 ultralytics 系的模型做训练或微调。它解决的不是"有没有数据"的问题,而是"数据能不能直接进训练管线"的问题。适合两类人:一类是想快速验证建筑物检测/分割方案可行性的算法工程师,另一类是需要一份结构规整的标注数据来做课程设计或原型开发的学生和独立开发者。下面我按自己拆包、转格式、跑通训练的实际顺序,把这份资源从里到外讲一遍。
2. 拆开压缩包先看什么:目录结构与标注格式的对应关系
拿到一个数据集压缩包,我一般不会急着写 dataloader,而是先把目录树打出来,确认三件事:图像和标签是不是一一对应、标注是 YOLO txt 还是 COCO json、有没有实例分割需要的 polygon 或 mask 信息。这三件事决定了后面走检测路线还是分割路线,也决定了要不要写转换脚本。
2.1 用 tree 和文件计数快速摸清结构
解压之后第一件事是看目录层级。常见做法是 images/ 和 labels/ 平行放置,或者 train/val/test 各自带 images 和 labels 子目录。用下面这组命令可以在十秒内判断结构是否规整:
# 解压到独立目录,避免污染当前工作区 unzip 建筑物检测数据集_20251116_120515.zip -d building_dataset # 看两层目录结构,不展开到文件级别 find building_dataset -maxdepth 2 -type d | sort # 统计图像文件数量(常见后缀) find building_dataset -type f \( -name "*.jpg" -o -name "*.png" -o -name "*.jpeg" \) | wc -l # 统计标签文件数量 find building_dataset -type f -name "*.txt" | wc -l find building_dataset -type f -name "*.json" | wc -l逻辑说明:-maxdepth 2是为了不被深层文件刷屏,先看骨架;图像计数和标签计数如果对不上,说明有图没标或者有标没图,这种情况在行业数据集里并不少见,尤其是从标注平台导出时漏了某几个批次。参数上,如果你的数据是 tif 遥感影像,把后缀换成*.tif再跑一遍。
如果图像数和 txt 数一致,基本可以判断是 YOLO 格式的检测标注;如果同时存在 json 且体积不小,那大概率是 COCO 格式,里面可能带 segmentation 字段,能直接做实例分割。这一步的判断直接决定第 3 章走哪条路。
2.2 判断标注是检测框还是实例分割掩膜
YOLO 检测的 txt 每行是class x_center y_center width height,五个值,归一化到 0~1。实例分割的 txt 每行是class x1 y1 x2 y2 ... xn yn,后面跟一串多边形点,点数不固定。用一行命令就能区分:
# 取一个标签文件,看每行的字段数分布 awk '{print NF}' building_dataset/labels/xxx.txt | sort | uniq -c如果字段数集中在 5,就是纯检测;如果出现大量大于 5 且为偶数的行,就是分割多边形。这里有个容易翻车的点:有些数据集检测和分割混在一起,同一个 txt 里既有 5 字段行也有多边形行,dataloader 不处理会直接报维度错误。遇到这种,要么按任务拆成两份标签,要么在 dataset 类里做分支解析。
提示:先确认类别数。看有没有 classes.txt 或 data.yaml,里面 names 列表的长度就是类别数。建筑物检测常见是单类
building,但也有细分residential、commercial、industrial的多类版本,类别对不上会让训练结果完全不可用。
2.3 图像与标签的配对校验脚本
在正式转格式之前,我习惯跑一个配对校验,把孤儿图像和孤儿标签都揪出来。这个脚本不长,但能省掉后面训练时报"找不到标签"的反复排查:
import os from pathlib import Path img_dir = Path("building_dataset/images") lbl_dir = Path("building_dataset/labels") # 收集 stem(不含后缀的文件名) img_stems = {p.stem for p in img_dir.glob("*") if p.suffix.lower() in {".jpg", ".png", ".jpeg"}} lbl_stems = {p.stem for p in lbl_dir.glob("*.txt")} only_img = img_stems - lbl_stems only_lbl = lbl_stems - img_stems print(f"图像总数: {len(img_stems)}, 标签总数: {len(lbl_stems)}") print(f"有图无标: {len(only_img)} -> {list(only_img)[:5]}") print(f"有标无图: {len(only_lbl)} -> {list(only_lbl)[:5]}")逻辑说明:用 set 做差集是最快的配对检查方式,比双重循环快几个数量级。参数上,如果你的图像和标签不在平行目录,改img_dir和lbl_dir即可。输出里"有图无标"的数量如果超过总数的 5%,建议直接剔除这些图,否则训练时要么报错要么被静默跳过,影响 epoch 统计。
3. 转成 YOLO 训练格式:data.yaml 配置与目录重组
确认了标注格式之后,下一步是把它整理成 ultralytics YOLO 能直接吃的结构。YOLO 系对目录结构有约定:images/train、images/val、labels/train、labels/val,再加一个data.yaml指向这些路径和类别名。这一步做对了,后面model.train()基本就是一行的事。
3.1 划分 train/val 并重组目录
如果原始数据没有划分,我一般按 8:2 随机切分,并且固定随机种子,保证每次复现一致。下面这个脚本做三件事:切分、复制文件、生成 data.yaml。
import random import shutil from pathlib import Path random.seed(42) # 固定种子,保证可复现 src_img = Path("building_dataset/images") src_lbl = Path("building_dataset/labels") dst = Path("yolo_dataset") # 收集所有 stem 并打乱 stems = sorted({p.stem for p in src_img.glob("*") if p.suffix.lower() in {".jpg", ".png", ".jpeg"}}) random.shuffle(stems) split = int(len(stems) * 0.8) train_stems, val_stems = stems[:split], stems[split:] for subset, subset_stems in [("train", train_stems), ("val", val_stems)]: (dst / "images" / subset).mkdir(parents=True, exist_ok=True) (dst / "labels" / subset).mkdir(parents=True, exist_ok=True) for stem in subset_stems: # 找原图(后缀可能不统一) for ext in [".jpg", ".png", ".jpeg"]: img_path = src_img / f"{stem}{ext}" if img_path.exists(): shutil.copy(img_path, dst / "images" / subset / img_path.name) break lbl_path = src_lbl / f"{stem}.txt" if lbl_path.exists(): shutil.copy(lbl_path, dst / "labels" / subset / lbl_path.name) print(f"train: {len(train_stems)}, val: {len(val_stems)}")逻辑说明:random.seed(42)是血泪经验,不固定种子的话每次跑出来的验证集不一样,指标波动你根本分不清是模型问题还是数据划分问题。参数上,0.8 这个比例对小数据集可以调到 0.9,但验证集少于 50 张时指标会很不稳定,建议至少留 100 张做验证。
3.2 data.yaml 的字段含义与常见写错
重组完目录,写 data.yaml。这个文件看着简单,但写错一个字段训练就起不来:
path: /abs/path/to/yolo_dataset # 数据集根目录,建议写绝对路径 train: images/train # 相对 path 的路径 val: images/val nc: 1 # 类别数 names: ["building"] # 类别名,顺序必须和标注里的 class id 对应逻辑说明:path用绝对路径能避免"在哪个目录下运行脚本"导致的路径歧义,这是最常见的翻车点之一。nc和names长度必须一致,且names的顺序要和标注文件里 class id 的映射一致——如果标注里 0 代表 building,你 names 第一个写了别的,模型学出来的东西就是错的。参数上,多类数据集把nc改成实际类别数,names按 id 顺序列全。
3.3 用一行命令验证格式是否被正确解析
在正式训练前,我习惯先用 YOLO 自带的校验跑一遍,确认没有格式错误:
yolo detect train data=yolo_dataset/data.yaml model=yolov8n.pt epochs=1 imgsz=640 batch=4逻辑说明:跑 1 个 epoch、小 batch,目的不是训练,而是让 ultralytics 把数据集扫描一遍。如果标注有越界坐标、类别 id 超范围、图像损坏,这一步就会报出来,比训练到一半崩掉强。参数上,imgsz要和你的图像实际分辨率匹配,遥感图常见 512 或 640,航拍图可能到 1024,先用小尺寸验证流程通不通,再放大。
注意:如果这一步报 "Label class X exceeds nc",说明标注里的 class id 大于等于 nc,要么改 nc,要么检查标注是不是从别的数据集混进来的。这个错误在合并多个来源的数据时特别常见。
4. 实例分割任务的额外处理:从多边形到掩膜
如果第 2 章判断出标注带多边形点,那这份数据还能直接做实例分割,价值比纯检测高一档。但分割对标注质量更敏感,多边形自交、点序错乱、点数过少都会让掩膜生成失败。这一章讲怎么把多边形标注安全地喂给 YOLO 分割模型。
4.1 多边形标注的合法性检查
YOLO 分割要求每个多边形至少 3 个点,且不能自交。下面这个脚本用 shapely 做合法性过滤,把有问题的标注挑出来:
from shapely.geometry import Polygon from pathlib import Path lbl_dir = Path("yolo_dataset/labels/train") bad_files = [] for txt in lbl_dir.glob("*.txt"): for line in txt.read_text().strip().splitlines(): parts = line.split() cls_id = parts[0] coords = list(map(float, parts[1:])) # 转成 (x, y) 点对 points = [(coords[i], coords[i+1]) for i in range(0, len(coords), 2)] if len(points) < 3: bad_files.append((txt.name, "点数不足3")) continue poly = Polygon(points) if not poly.is_valid: bad_files.append((txt.name, "多边形自交或退化")) print(f"问题标注数: {len(bad_files)}") for name, reason in bad_files[:10]: print(name, reason)逻辑说明:shapely 的is_valid能同时抓出自交和退化(面积为零)的多边形。参数上,如果问题标注占比很小(比如低于 2%),直接删掉这些标注行即可;如果占比高,说明标注平台导出有问题,得回去重新导出,硬修的成本比重标还高。
4.2 分割训练配置与检测配置的差异
分割任务的 data.yaml 和检测几乎一样,区别在模型选择和训练参数。检测用yolov8n.pt,分割要用yolov8n-seg.pt:
yolo segment train data=yolo_dataset/data.yaml model=yolov8n-seg.pt epochs=50 imgsz=640 batch=8逻辑说明:-seg后缀的模型头输出掩膜系数,和检测头不通用,拿检测权重去初始化分割模型会报维度不匹配。参数上,分割任务显存占用比检测高约 30%~50%,同样 batch 下如果 OOM,先把 batch 降到 4 再试。imgsz对分割尤其关键,小目标建筑物的掩膜在 640 下可能只剩几个像素,建议至少 640,有条件的上 1024。
4.3 掩膜质量的可视化验证
训练前用几行代码把标注掩膜画出来,比看指标直观得多:
import cv2 import numpy as np from pathlib import Path img = cv2.imread("yolo_dataset/images/train/xxx.jpg") h, w = img.shape[:2] overlay = img.copy() for line in Path("yolo_dataset/labels/train/xxx.txt").read_text().strip().splitlines(): parts = line.split() coords = list(map(float, parts[1:])) pts = np.array([(coords[i]*w, coords[i+1]*h) for i in range(0, len(coords), 2)], np.int32) cv2.fillPoly(overlay, [pts], (0, 255, 0)) cv2.addWeighted(overlay, 0.4, img, 0.6, 0, img) cv2.imwrite("check_mask.jpg", img)逻辑说明:把归一化坐标乘回宽高再fillPoly,能直接看出标注是否贴合建筑物轮廓。参数上,addWeighted的 0.4 是掩膜透明度,觉得太淡可以调到 0.6。这一步能抓出"标注框对了但多边形飘了"的情况,这种问题在指标上不一定明显,但分割边缘会很脏。
5. 避坑与排查:训练前后最容易翻车的五个点
这一章是我自己在这类数据集上踩过的坑,按"现象 → 原因 → 解决"写,每条都是真实会遇到的。
现象一:训练 loss 正常下降,但验证 mAP 一直是 0。原因通常是验证集标签路径没配对,或者 data.yaml 里 val 指向的目录是空的。解决:用第 2.3 节的配对脚本对 val 目录再跑一遍,确认 images/val 和 labels/val 的 stem 完全一致。
现象二:报 "No labels found" 但目录里明明有 txt。原因是 ultralytics 默认按图像路径把images替换成labels来找标签,如果你的目录名不是这个约定(比如叫imgs和anns),它就找不到。解决:要么改成约定目录名,要么在 data.yaml 里显式指定 labels 路径。
现象三:训练几个 epoch 后 loss 变 NaN。常见原因是标注里有坐标超出 0~1 范围,或者多边形点数异常导致掩膜计算溢出。解决:跑第 4.1 节的合法性检查,把越界坐标 clamp 到 [0,1],把异常标注剔除。
现象四:显存够但训练极慢。原因是图像分辨率远大于 imgsz,dataloader 每步都在做大幅缩放。解决:提前把图像 resize 到接近 imgsz 的尺寸存一份,训练时直接读,速度能快一倍以上。
现象五:分割结果边缘锯齿严重。原因是多边形点数太少,掩膜分辨率不够。解决:如果原始标注点数就少,可以在转格式时对多边形做插值加密,但这只是缓解,根治还得靠重新标注。
注意:这五条里,前三条是配置问题,后两条是数据质量问题。配置问题改一行就好,数据质量问题往往要回到标注环节,所以拆包后的第一轮检查越细,后面返工越少。
6. 进阶技巧:用预训练权重冷启动与指标解读
数据跑通之后,真正决定效果的是两件事:怎么用预训练权重冷启动,以及怎么看指标判断模型到底行不行。这一章讲两个我常用的技巧。
6.1 冻结 backbone 做小数据集的冷启动
建筑物数据集如果只有几百张,从头训练很容易过拟合。常见做法是先冻结 backbone 训练几轮,让检测头/分割头先适配你的类别,再解冻全量微调:
# 第一阶段:冻结 backbone,只训练头 yolo detect train data=yolo_dataset/data.yaml model=yolov8n.pt epochs=20 freeze=10 imgsz=640 batch=8 # 第二阶段:解冻全量微调,学习率调小 yolo detect train data=yolo_dataset/data.yaml model=runs/detect/train/weights/best.pt epochs=50 lr0=0.001 imgsz=640 batch=8逻辑说明:freeze=10表示冻结前 10 层,YOLOv8n 的 backbone 大约就在这个范围。第一阶段用默认学习率快速让头收敛,第二阶段用lr0=0.001的小学习率精调,避免把预训练特征冲掉。参数上,数据量少于 500 张时 freeze 阶段可以拉到 30 轮,数据量上千则 10 轮就够。
6.2 看懂 mAP50 和 mAP50-95 的差距
训练完看结果,两个指标最关键:mAP50 和 mAP50-95。前者是 IoU 阈值 0.5 下的平均精度,后者是 0.5 到 0.95 每隔 0.05 取一次再平均。建筑物检测里,如果 mAP50 很高但 mAP50-95 很低,说明框的位置大致对但不够精准,常见于标注框偏大或偏小。分割任务还要看 mask mAP,它比 box mAP 低 5~10 个点是正常的,低太多说明掩膜质量有问题。
| 指标 | 含义 | 建筑物场景参考值 |
|---|---|---|
| mAP50 | IoU=0.5 的平均精度 | 单类通常 0.85+ |
| mAP50-95 | 多 IoU 阈值平均 | 比 mAP50 低 0.1~0.2 |
| mask mAP50 | 掩膜 IoU=0.5 | 比 box mAP50 低 5~10 点 |
| precision | 查准率 | 误检多时偏低 |
| recall | 查全率 | 漏检多时偏低 |
逻辑说明:这张表不是让你背,而是训练完对着看。如果 mAP50 到 0.9 但 recall 只有 0.6,说明模型很保守,很多建筑物没检出来,这时候要检查是不是小目标太多、imgsz 太小。如果 precision 低,多半是背景被误判成建筑物,看看负样本够不够。
从那以后我每次拿到新数据集,都强制走一遍"配对校验 → 格式确认 → 单 epoch 验证 → 掩膜可视化"这四步,哪怕数据看起来再规整也不跳过。这套流程帮我省下的返工时间,远比多跑几个 epoch 值钱。希望帮到你。
本文还有配套的精品资源,点击获取