新闻详情

新闻详情

首页 / 资讯中心 / 详情

无人机城市图像语义分割数据集实战:270张标注图与U-Net训练避坑指南

发布时间:2026/10/1 17:41:24来源:尧图网络
无人机城市图像语义分割数据集实战:270张标注图与U-Net训练避坑指南
简介面向计算机视觉与无人机遥感应用开发者这套高分辨率城市图像语义分割数据集覆盖建筑、公路、树木等8个常见地物类别可缓解城市场景标注数据不足的问题适合作为分割模型的训练与验证基准。压缩包共543个文件以541张PNG原图与对应掩码为主另含1个类别说明文件和1个Python可视化脚本整体约263.73MB该脚本可随机抽取一张样本将原始图像、GT真值图及GT叠加蒙版效果并排展示并保存到当前目录便于直观核对标注质量。训练集约200张、验证集约70张图像与掩码一一对应目录按训练集、验证集划分清晰PNG格式便于直接接入常见深度学习框架类别定义见classes文本可根据研究需要调整标签映射。数据既可直接用于U-Net、SwinUNet、TransUNet等分割网络的训练与评估也适合开展数据增强、迁移学习、类别不平衡等方向的小规模验证实验。目前已有386人学习下载。1. 高分辨率无人机城市图像语义分割270 张带标签数据比模型更早决定你的上限说到高分辨率无人机城市图像语义分割卡住大多数人的往往不是模型选型而是标注对齐的数据集。这份资源就是冲这个来的约 270 张无人机城市航拍图训练集约 200 张、验证集约 70 张每张原图配一张 8 类别的 GT mask覆盖建筑、道路、树木等典型地物完整类别清单以包内 classes 文件为准。解压后 train/images、train/masks、val/images、val/masks 目录规整还带一个可视化脚本随机抽图把原图、GT、半透明蒙版拼成一张图存盘。对正在调 U-Net、SwinUNet 的开发者来说它省掉的是最痛苦的环节——一张张在标注软件里画多边形再转 mask对刚入门语义分割、想完整走一遍数据到训练链路的新手来说它又是一份能直接跑通的基准数据。在无人机视觉感知项目里我最大的体会是指标虚高、换场景就崩十有八九不是模型问题而是数据切分和标签编码有问题。下面拆目录、拆脚本再把最容易翻车的几个坑逐个排掉。2. 数据集结构与标签编码270 张图、8 类 mask先验数据再定方案2.1 目录划分与文件命名规则解压之后先别急着预览图片第一件事是确认目录层级。所有训练脚本的路径、数据加载器的遍历逻辑都要围绕这个结构来写结构认错了后面每一步都跟着错。这份数据集的目录很规整常见做法是整理成下面这样drone_city_seg/ ├── classes.txt # 8 类标签清单每行一个类名 ├── visualize.py # GT 可视化脚本随机抽图出体检报告 ├── train/ │ ├── images/ # 训练原图约 200 张 PNG │ │ ├── seq3_000200.png │ │ ├── seq2_000900.png │ │ └── ... │ └── masks/ # 与原图同名的 GT一一对应 │ ├── seq3_000200.png │ └── ... └── val/ ├── images/ # 验证原图约 70 张 PNG └── masks/文件名本身就是信息。seq3_000200.png 这种命名里seq 是序列编号可以理解为一次航拍任务里的航带号后面 6 位数字是帧号。不同 seq 大概率来自不同的拍摄时段或不同区域同一个 seq 内部相邻帧的视角、光照、地面景物高度相似。这个特点直接决定训练集和验证集该怎么切如果随机切分而不是按 seq 隔离验证集里会出现和训练集几乎同画面的相邻帧测出来的 mIOU 会虚高这个问题第 4 章会展开讲。还要提醒一个细节网上的转述说“约 270 张”“训练集 200 张左右、验证集 70 张左右”解压后建议用命令核对真实数量不要照搬转述数字这类数据在二次分发时数量对不上是常事。ls train/images/*.png | wc -l ls val/images/*.png | wc -l从资源里给出的文件名样例看seq3_000200、seq2_000900、seq14_000200、seq13_000600、seq36_000400 这些序列号跨度很大说明拍摄覆盖了多条航带和多个街块不是单一路线的重复帧。这对训练泛化是有利的但也意味着如果验证集只从某几个 seq 抽评估结果会偏向那几条航带的地物风格。2.2 8 类标签与 mask 编码方式classes 文件是这份数据的“字典”格式一般是每行一个类名行号对应类别索引。摘要里明确提到的类别有建筑、道路、树其余几类以包内 classes 文件为准。特别提醒转述文档里出现过“树”被写成“书”的情况所以判断类别永远以 classes.txt 原文为准不要信二手转述。类别清单对应的语义大致如下类别索引类别名说明0背景不归属其他类的区域1建筑屋顶、墙体等建筑区域2道路车行道、路面区域3树木树冠、树丛等植被4~7以 classes.txt 为准其余类别打开文件即见这里值得多讲一句语义分割和实例分割的区别。YOLO 系列里带的是实例分割那种掩码每个目标一个 mask 实例而这份数据是像素级的语义分割标签全图每个像素都属于且只属于一个类别同一类别的多个对象共享同一个索引。数据加载、评估指标的计算方式都要按语义分割来不能拿实例分割的思路去套否则会出很多底层错误。mask 的编码方式直接决定 DataLoader 怎么写。常见做法有两种一种是单通道索引图像素值就是类别索引另一种是 RGB 调色板图看起来是彩色的但本质仍然是索引。打开任意一张 mask 用这段代码确认import numpy as np from PIL import Image # 检查单张 GTshape 和类别取值决定后续预处理方式 mask np.array(Image.open(train/masks/seq3_000200.png)) print(shape:, mask.shape, dtype:, mask.dtype) print(unique values:, np.unique(mask))如果 shape 是 (H, W) 且 unique values 落在 0~7说明是单通道索引图直接交给 CrossEntropyLoss 就行如果 shape 是 (H, W, 3)说明 GT 存成了三通道形式需要在预处理里先降维。这段判断代码建议写进数据加载模块每次启动训练自动检查一次而不是靠人肉记忆。2.3 训练集验证集划分与适用场景270 张左右的总量训练集约 200 张、验证集约 70 张比例大约是 74/26。对中小规模的无人机城市分割任务来说这个切分合理训练量足够微调一个 U-Net 或 SwinUNet 的编码器验证集也能看出趋势。但要清醒一点这个量级不适合从零训练大模型更适合做三类事情——迁移学习、改进算法的横向对比、验证你自己的数据管线是否可靠。落到实操上这份数据最常见的用法是加载预训练权重把最后的分割头换成 8 类输出冻结编码器只训解码器或者全量微调。270 张图在小模型上单卡 2~4 小时能跑完一个完整训练周期非常适合做消融实验。动手之前建议做一次重叠检查统计 train 和 val 里各自出现了哪些 seq 编号确认没有同一个 seq 的帧同时出现在两边。把文件名解析成 (seq, frame) 元组再做集合求交一条脚本就能完成。如果真的有重叠说明当前切分不干净需要按第 4 章的方法重新划一遍。这一步做不做直接影响后面所有实验结论的可信度。3. 可视化脚本实战随机抽图、GT 蒙版叠加、一次跑出十张体检图3.1 运行方式与输出资源附带的可视化脚本用途是随机抽一张训练图把原图、GT、以及 GT 半透明叠加在原图上的效果拼成一张三格图保存到当前目录。这个动作看似简单却是数据体检的第一步跑一遍你就能直观看到标签贴得准不准、类别边界干不干净、有没有明显漏标。运行方式# 在数据集根目录执行脚本默认读取 train/images 和 train/masks python visualize.py脚本没有命令行参数路径写在源码里。如果你的目录结构不是标准的 train/images、train/masks打开脚本改头部几个路径常量就行通常两三行。输出文件名一般是 visual_check.png保存在当前目录。多跑几次每次随机抽到的图都不同因为脚本内部用的是 random.choice。3.2 核心逻辑拆解与参数含义脚本完整逻辑可以浓缩成下面这段等价代码参数含义我逐个标注import os import random import numpy as np import matplotlib matplotlib.use(Agg) # 无界面环境也能存图 import matplotlib.pyplot as plt from PIL import Image image_dir train/images mask_dir train/masks files [f for f in os.listdir(image_dir) if f.endswith(.png)] # 随机抽一张保证每次体检看到的样本不同 pick random.choice(files) image np.array(Image.open(os.path.join(image_dir, pick))) mask np.array(Image.open(os.path.join(mask_dir, pick))) # 半透明叠加GT 区域混入 50% 红色 overlay image.copy() if mask.ndim 3: # 彩色 GT 先压成单通道 mask mask[:, :, 0] # 示例降维严谨做法看 4.1 overlay[mask 0] (overlay[mask 0].astype(np.float32) * 0.5 np.array([255, 0, 0]) * 0.5).astype(np.uint8) fig, axes plt.subplots(1, 3, figsize(15, 5)) axes[0].imshow(image) # 第一格原图 axes[1].imshow(mask, cmaptab20, vmin0, vmax7) # 第二格GT axes[2].imshow(overlay) # 第三格叠加 plt.tight_layout() plt.savefig(visual_check.png, dpi150)几个参数说明overlay 里的 0.5 是原图和红色的混合权重想看得更透就把原图权重压到 0.3cmaptab20 把 8 个类别映射成不同颜色vmin 和 vmax 锁死 0~7 的范围避免类别没打满时 matplotlib 自动拉伸色标导致相邻类别颜色接近dpi150 保证保存图放大后边缘依然清楚方便检查标签边界是否对齐。这里有个容易忽略的点如果 mask 是彩色三通道直接 imshow 会得到一整片彩色而不是分块分色。所以叠加前必须先判断 ndim这也是脚本里最值得抄的防御性写法。我见过不少人的可视化脚本栽在这一步GT 一显示就是花花绿绿的噪点还以为是数据坏了。3.3 我一般怎么拿这个脚本做标签体检推荐一个实用的习惯把脚本连续跑 10 遍每次随机抽图然后把 10 张 visual_check.png 拼到一张大图上集中过目。重点看三类问题第一建筑轮廓的边缘是否贴齐屋顶真实边界。无人机视角下屋顶和地面的分界线错位是最常见的标注瑕疵尤其在斜顶建筑上蒙版会明显偏移一眼就能看出来。第二道路是否连续。断头路通常意味着漏标或者路段被树冠遮挡后标注员直接放弃。对后续做无人机路径规划类应用来说不连续的道路标签会让模型永远学不会完整路面。第三有没有整片区域被标成大类别、小目标被吞掉的情况。车辆、路灯、井盖这类像素占比极小的对象在人眼抽查时最容易暴露而在 mIOU 数字里几乎看不出来。这轮体检做完你对这份数据适合什么任务、边界在哪心里基本有底了比直接丢进模型训练省时间得多。顺便说一句想自制语义分割数据集的话这套“随机抽图 半透明蒙版”的检查流程可以直接用作质检工具标注一批查一批效率很高。4. 避坑指南无人机城市分割数据集最常翻车的 5 个坑4.1 mask 读出来是彩色图loss 直接异常现象训练时 CrossEntropyLoss 报错或者 loss 从第一个 epoch 起就是 nan打印 GT 数组shape 是 (H, W, 3) 而不是 (H, W)。原因GT 保存成了 RGB 调色板 PNG不是单通道索引图。这类数据集在搬运过程中读图脚本和保存脚本不一致很容易留下这种隐性炸弹。有些模型能跑通是因为数据加载代码里无意间只取了第一通道但不同脚本各写一套迟早出事。解决统一在读图环节做降维。如果颜色是逐类纯色用颜色查找表映射如果带调色板用 PIL 转成 P 模式再取索引。建议封装一个 to_index() 函数在 DataLoader 里强制走一遍并在每次启动训练时自动打印 GT 的 shape 和 unique values 做校验。这套校验逻辑值得写进你自己的工具函数库所有分割数据集通用。4.2 验证集 mIOU 虚高换场景立刻崩现象在 val 上 mIOU 做到 0.8 以上自己拿无人机新拍一组城市画面测试指标掉到 0.5 以下模型像失忆了一样。原因train 和 val 是随机切帧的没有按 seq 序列隔离。同一航带相邻帧的视角、光照、地物几乎完全相同模型等于背下了画面而不是学到了语义。这是航拍数据集最大的数据泄漏源比一般数据集里“同场景不同帧”的泄漏还要严重。解决按 seq 编号重新切分保证同一个 seq 的帧只落在 train 或 val 的一侧。做法是先解析所有文件名为 (seq, frame) 元组按 seq 分组后再切分而不是一张一张随机抽。切完之后再跑一遍第 2.3 节的集合求交确认两侧没有同 seq 帧。4.3 classes 文件被转述错类别名对不上现象文档说 8 类但 classes 文件只有 7 行或者类别名里出现“书”这种明显不属于城市地物的词。原因数据集在二次分发时说明文档被反复改写tree 被转述成“书”也出现过整行类别在复制粘贴时丢失的情况。摘要只点到了建筑、公路、树三个类别剩下的必须看包内文件。解决永远以包内 classes 文件为准而不是网上的转述文字。解压后第一件事就是打开 classes.txt 数行数。如果确实少了一类用第 3 章的可视化脚本逐张看 GT 的颜色分布确认实际标注了几类再决定是补类别还是裁剪类别不要硬按 8 类训练。4.4 高分辨率原图直接进模型显存爆掉现象单张原图分辨率很高直接按原尺寸进 U-Netbatch 稍微大一显存就 OOM强行 resize 到 256 又发现小目标细节全丢。原因无人机影像分辨率普遍很高直接等比缩放损失小目标细节直接原尺寸输入显存又扛不住。这是高分辨率分割的老矛盾不是这份数据独有但在这类航拍数据上特别明显。解决训练时先等比缩小到长边 2048 以内再随机裁剪到 512 或 640验证阶段用滑窗推理再拼接。缩放 mask 时必须用 INTER_NEAREST 最近邻插值线性插值会在类别边界生成不存在的中间值等于给标签掺了噪声。具体参数和代码在第 5.1 节。4.5 小目标类别学不到逐类指标暴露真相现象整体 mIOU 看着不错但逐类看时车辆、路灯这类小目标类别 IoU 接近 0实际应用里漏检严重。原因类别极不平衡。建筑和道路占据了大部分像素损失被高频类别主导小目标类别的梯度被淹没模型直接摆烂不学。解决统计每类像素占比用中位数频率平衡法给每个类别算权重传给 CrossEntropyLoss 的 weight 参数或者对小目标类别在采样阶段做针对性重采样。权重计算代码在第 5.2 节。另外评估时一定要逐类打印 IoU只看平均 mIOU 会掩盖这个小目标问题。5. 从数据集到模型U-Net/SwinUNet 训练前先完成三件事5.1 尺寸策略等比缩放 随机裁剪别让高分辨率拖垮训练270 张高分辨率无人机图直接整图训练不现实显存占用有时候很玄学同样的尺寸换个 batch 就爆。我常用的策略是先等比缩放再随机裁剪兼顾全局上下文和显存上限代码import cv2 import numpy as np import random def load_and_crop(image_path, mask_path, crop_size(512, 512)): # 读原图和 GTGT 用 IMREAD_UNCHANGED 保留原始通道 image cv2.imread(image_path) image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) mask cv2.imread(mask_path, cv2.IMREAD_UNCHANGED) # 长边缩到 2048 以内保持宽高比 h, w image.shape[:2] scale min(1.0, 2048 / max(h, w)) if scale 1.0: image cv2.resize(image, (int(w * scale), int(h * scale))) mask cv2.resize(mask, (int(w * scale), int(h * scale)), interpolationcv2.INTER_NEAREST) # 随机裁剪固定尺寸GT 不能做任何线性插值 h, w image.shape[:2] top random.randint(0, h - crop_size[0]) left random.randint(0, w - crop_size[1]) return (image[top:top crop_size[0], left:left crop_size[1]], mask[top:top crop_size[0], left:left crop_size[1]])两个参数最关键scale 的 2048 是长边上限显卡 8G 以下建议降到 1536crop_size 的 512 要和模型下采样倍数对齐U-Net 这类编码器下采样 4 次512 正好能被整除。缩小时 mask 必须用 INTER_NEAREST否则边界会出现不存在的插值类别。如果你的场景特别在意车辆这类小目标可以把缩放上限提高、crop 尺寸调小用更多裁剪块来弥补采样覆盖率。5.2 类别不均衡先算权重再选损失8 类数据里建筑和道路占大头几乎是一定的训练前先算一遍类别权重别等训练完再看逐类指标后悔。用中位数频率平衡from collections import Counter import numpy as np import os from PIL import Image def compute_class_weight(mask_dir, num_classes8): counter Counter() for name in os.listdir(mask_dir): mask np.array(Image.open(os.path.join(mask_dir, name))) if mask.ndim 3: mask mask[:, :, 0] # 彩色 GT 按需降维 counter.update(np.unique(mask).tolist()) total sum(counter.values()) freq np.array([counter.get(i, 0) / total for i in range(num_classes)]) median np.median(freq[freq 0]) # 只看有像素的类别 weights np.where(freq 0, median / freq, 0.0) return weights.astype(np.float32)用法是把 weights 数组直接传给 CrossEntropyLoss 的 weight 参数。两个细节统计时 mask 如果是三通道必须先降维否则 unique 会带出 (R,G,B) 组合值Counter 全乱掉freq 为 0 的类别权重置 0避免给不存在的类别分配梯度。原资源说明里附带了一份医学图像分割网络介绍专栏和 U-Net/SwinUNet 改进专栏的参考地址训练前翻一翻里面的改进点挑个合适的解码器结构能少走不少弯路。5.3 验证指标逐类 mIOU 比 pixel accuracy 诚实得多语义分割里 pixel accuracy 极易被建筑、道路这类大面积类别刷高正确做法是逐类算 IoU 再取平均def per_class_iou(pred, gt, num_classes8): ious [] for c in range(num_classes): p (pred c) g (gt c) inter (p g).sum() union (p | g).sum() ious.append(inter / union if union 0 else 1.0) return np.array(ious)空类别记 1.0 是常见约定避免某个类别在验证集里恰好没出现时把平均分拉低。把 8 个类别的 IoU 全部打印出来哪个类别学不动一目了然。如果某个类别长期是 0优先检查是不是标签编码错了而不是急着调模型——很多“模型问题”最后都定位到数据加载上尤其是 4.1 那种三通道 GT 的坑。6. 一个容易被忽略的验证动作训练完反查可视化比 mIOU 更早发现坏样本模型训练完大家习惯只看 mIOU。我的习惯是额外做一次预测可视化反查从验证集抽几张图把预测 mask 和 GT mask 各自叠加到原图上并排保存人眼过一遍。这个动作成本极低验证集 70 张抽 5 张就够输出 5 张对比图但发现问题的速度比盯指标快得多。import numpy as np import matplotlib matplotlib.use(Agg) import matplotlib.pyplot as plt from PIL import Image # pred_mask 是模型 softmax 后 argmax 得到的索引图 # gt_mask 是与原图同名的 GT def overlay_compare(image, pred, gt, save_path): fig, axes plt.subplots(1, 3, figsize(15, 5)) axes[0].imshow(image) axes[1].imshow(image, alpha0.6) axes[1].imshow(pred, alpha0.4, cmaptab20) axes[2].imshow(image, alpha0.6) axes[2].imshow(gt, alpha0.4, cmaptab20) axes[0].set_title(original) axes[1].set_title(pred) axes[2].set_title(GT) plt.tight_layout() plt.savefig(save_path, dpi150)反查时重点看三类现象建筑边缘是否出现锯齿状误判阴影区域是否被整片吞成地面玻璃幕墙是否被标成建筑以外的类别。这三类问题在 mIOU 数字上可能只差零点几个点但人眼扫一遍马上有结论。我还会顺手统计每张图里 pred 和 GT 的类别像素差哪些图差异最大就优先看哪些等于给可视化排序不用盲抽。这个习惯帮我省下过至少两个“看起来成功”的版本——mIOU 都在 0.7 以上反查却发现模型把阴影里的车辆全漏了而这恰恰是实际项目最在意的对象。从那以后我每次交付任何分割实验都强制自己先跑一遍可视化反查再谈 mIOU。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

考虑特性分布的储能电站接入与多时间尺度源储荷协调调度Matlab实现 2026/10/1 18:18:30

考虑特性分布的储能电站接入与多时间尺度源储荷协调调度Matlab实现

风电场侧加了一个储能电站之后,并网调度从“源随荷动”变成了“源储荷协同”,这句话说起来轻巧,真正在Matlab里把“考虑特性分布的储能电站接入”和“多时间尺度源储荷协调调度”整成一套能跑的代码,我前前后后折腾了小半年。最早…

阅读更多 →
期货量化策略绩效分析实战:从回测收益到风险指标的深度拆解 2026/10/1 18:18:29

期货量化策略绩效分析实战:从回测收益到风险指标的深度拆解

做量化这几年,我见过太多人跑完回测第一件事就是看总收益率。翻了一倍,开心得不行;亏了20%,立马开始怀疑人生。说句实在话,只盯着收益率的账户,就像只看体重不看体脂率的人——你可能瘦了,但掉的…

阅读更多 →
AI合同审查工具在消费纠纷中的落地配置 2026/10/1 18:18:23

AI合同审查工具在消费纠纷中的落地配置

我无法根据您提供的输入内容生成符合要求的博文。原因如下:输入中缺少关键必要字段:按照您设定的严格输入格式,必须包含:项目标题: [标题]项目正文: [原始描述]关键词: [关键词1, 关键词2, ...]摘要描述: [一句话简介]而当前输入仅…

阅读更多 →
BP神经网络信贷信用评估实战:从预处理到违约概率预测 2026/10/1 18:18:23

BP神经网络信贷信用评估实战:从预处理到违约概率预测

简介:基于BP神经网络的个人信贷信用评估,是一份面向金融风控入门者与机器学习初学者的MATLAB实现方案。资源围绕信用评估场景,利用BP神经网络对个人信贷数据进行分类识别,包含完整可运行的main.m主脚本,以及配套的germ…

阅读更多 →
DMS渠道数据采集分析管理系统选型:从报表工具到数字化管理中枢 2026/10/1 18:18:23

DMS渠道数据采集分析管理系统选型:从报表工具到数字化管理中枢

DMS渠道数据采集、分析、管理系统这行干久了,你会发现一个奇怪的现象:很多企业花了大几百万上DMS,最后用得最频繁的功能却是“查报表”。不是大家不想用,而是大多数DMS服务商只给你一套录入界面和一堆图表,没有真正把渠…

阅读更多 →
拆解敏感肌修护真相:从皮肤屏障重建到避开智商税 2026/10/1 18:18:23

拆解敏感肌修护真相:从皮肤屏障重建到避开智商税

“外油内干、敷片状面膜刺痛、一换季就两颊泛红发烫”——如果你也有这些症状,那你大概率已经被护肤品牌们盯上了,因为敏感肌修护是护肤品里最典型的“情绪税”重灾区。我当了快十年的护肤编辑,自己也是从烂脸期一步步爬过来的,不…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉