Compare commits

3 Commits
Author SHA1 Message Date
admin e7ce9e3329 tiff可视化按照客户要求使用红黄蓝绿 2026-07-29 00:26:47 +08:00
admin d5cef768bf tiff可视化 2026-07-28 23:36:00 +08:00
admin bb8a871ab4 数据集扩充方法文档 2026-07-28 23:11:03 +08:00
3 changed files with 220 additions and 0 deletions
@@ -0,0 +1,136 @@
# RailFOD23 铁路异物检测数据集扩充思路总结
> 来源:[《数据稀缺?不存在的!手把手教你用 ChatGPT + Stable Diffusion 合成铁路异物检测数据集》](https://cloud.tencent.com/developer/article/2572047),腾讯云开发者社区,2025-09-28。本文是对原文的理解与结构化总结,不替代原始论文或数据集说明。
## 1. 问题与目标
铁路接触网/输电线路上的外来异物可能造成短路、停电和行车延误。常见类别包括:
- 塑料袋;
- 飘动物(风筝、帆布、织物等);
- 鸟巢;
- 气球。
该任务的真实数据通常不足,且采集、标注和跨单位共享成本较高。数据扩充的目标不是单纯增加图片数量,而是覆盖更多**背景、天气、视角、尺寸、遮挡和异物形态**,以提高检测模型对真实现场的泛化能力。
## 2. 数据集概况
文章介绍的 RailFOD23 是铁路输电线路外来物检测数据集,包含:
- 14,615 张高分辨率图像;
- 40,541 个目标标注;
- 4 类异物;
- COCO 标注格式。
其关键做法是组合三条数据生产路径:人工合成(PS-based)、AIGC 生成(AIGC-based)以及自动图像融合与增强(AUG-based)。三者分别弥补真实性、规模化和合成一致性方面的不足。
## 3. 三类扩充方法
### 3.1 人工合成:PS-based
**方法**:收集高质量铁路输电线路背景图,再用 Photoshop 等工具将异物贴入背景,制作含异常的图像。
原文示例中,团队用 Python 从图片库抓取约 400 张高质量线路场景,并人工合成了 412 张异常图像。
**优点**
- 能针对稀少、高风险或难以捕获的异物类别定向补样;
- 人工可精确控制异物位置、尺寸、姿态和线路关系;
- 可快速建立首批可用训练样本。
**局限**
- 制作慢、依赖人工经验;
- 前景与背景的光照、颜色、边缘、透视不一致时,容易出现“贴图感”;
- 合成结果仍需要标注,维护成本随规模增加。
**适用定位**:小规模、高价值、难例和长尾类别的精细补充,而非唯一的数据生产手段。
### 3.2 AIGC 生成:ChatGPT + Stable Diffusion
**方法**:先用大语言模型批量生成多样化的图像描述,再通过 Stable Diffusion 生成图像,随后进行图像超分辨率处理。原文将这一流程概括为“文本生成 → 图像生成 → 图像超分辨率”。
**可系统变化的条件**
- 场景:桥梁、站场、区间、隧道口、不同支柱和接触网结构;
- 环境:晴天、阴天、雨雪、逆光、夜间或低照度;
- 视角:无人机俯视、斜视、不同拍摄距离和焦段;
- 异物:类别、数量、形态、颜色、缠绕位置、遮挡程度和目标大小。
**优点**
- 可低成本、批量地产生长尾组合;
- 便于按类别不平衡情况定向生成;
- 可以在真实数据不足时提前扩展场景覆盖面。
**风险与控制**
- 生成图可能出现不符合接触网结构或物理规律的内容;
- 文字描述并不天然对应准确边界框,标注质量需单独验证;
- 不应只用生成图训练,需保留足够真实采集数据用于验证和测试。
建议为提示词建立参数模板与版本记录,并在入库前实施“结构合理性、类别正确性、视觉真实性、标注可用性”四项质检。
### 3.3 自动融合增强:AUG-based
**方法**:基于 Railsem19 等背景数据集,把异物前景自动加入背景,使用 CDTNet 等图像融合/协调方法处理前景背景差异,并自动生成对应标注文件。
**解决的问题**
- 将人工抠图、粘贴、调色和标注等重复工作自动化;
- 降低前景与背景在颜色、亮度、纹理方面的不协调;
- 前景位置已知,因此可同步输出检测框,扩大数据量时成本更可控。
**关键实施点**
1. 准备已分割或可提取的异物前景素材,并明确类别;
2. 准备覆盖多线路结构与环境的无异物背景库;
3. 依据线路区域、透视和真实尺寸分布决定投放位置及缩放比例;
4. 融合后进行颜色/光照协调,必要时增加模糊、噪声、压缩和天气扰动;
5. 从前景掩码自动导出 COCO/YOLO 标注;
6. 对图像和标注执行抽检,剔除遮挡不合理、边界框错误或不真实样本。
**适用定位**:适合主力规模化扩充,尤其适用于目标类别明确、可获取前景素材、且需要自动标注的检测任务。
## 4. 推荐的数据生产策略
三种方法应按“真实数据为锚、自动合成为主、人工与 AIGC 定向补齐”的方式组合:
| 数据来源 | 主要价值 | 建议用途 |
| --- | --- | --- |
| 真实采集 | 保证分布真实性 | 验证集、测试集及训练集核心样本 |
| PS 人工合成 | 精细控制、构造难例 | 少数类、典型风险位置、专家定义的极端场景 |
| AIGC 图像 | 扩展长尾场景组合 | 提升背景/天气/视角多样性,生成后须严格筛选 |
| 自动融合 | 高效率、可自动标注 | 大规模补齐类别、尺度、位置与环境分布 |
数据划分时应避免同一背景、同一视频片段或同一合成素材同时出现在训练集与验证/测试集中,以免产生数据泄漏、夸大指标。
## 5. 模型训练与实验启示
文章采用 COCO 预训练权重进行微调,在单张 Tesla P100 上使用 mmdetection 训练;设置为 batch size 8、40 个 epoch、学习率 0.001。
文中结果显示:
- YOLOv8-l 的 mAP 为 82.9%YOLOv8-s 为 82.2%
- YOLOv7 系列表现相对较弱;
- Faster R-CNN 等两阶段模型在该任务上不如 YOLO 系列;
- “飘扬物”与“塑料袋”易混淆,反映二者视觉形态相近;
- 气球样本较少,存在漏检或误检,说明类别均衡仍是关键。
可得出的工程结论是:扩充数据时应优先针对**少样本类别**和**易混淆类别对**设计样本,而不是平均地增加每一类数量。对于小目标和复杂背景,也应将尺度分布与背景干扰纳入数据设计。
## 6. 落地检查清单
- [ ] 明确异物类别、类别定义和标注规范;
- [ ] 统计真实数据的类别、目标尺寸、场景、天气和视角分布;
- [ ] 为稀少类及易混淆类设定定向扩充目标;
- [ ] 建立背景库与前景素材库,并管理来源与许可;
- [ ] 采用融合协调、透视缩放和位置约束降低合成痕迹;
- [ ] 自动生成标注后抽检图像与标注一致性;
- [ ] 训练、验证、测试按场景或采集批次隔离,测试集优先使用真实数据;
- [ ] 分类别评估 AP、漏检率和混淆矩阵,回流改进数据配比;
- [ ] 保存提示词、合成参数、素材版本和样本来源,确保可追溯。
## 7. 总结
RailFOD23 的核心价值不在于某一种生成工具,而在于以多源数据协同解决铁路视觉数据稀缺:人工合成负责精细可控,AIGC 负责场景多样化,自动融合负责规模和标注效率,真实数据则负责锚定真实性与可信评估。实际项目应把合成数据当作对真实数据分布的补充,并以质量控制、数据隔离和按类别误差分析来闭环迭代。
View File
+84
View File
@@ -0,0 +1,84 @@
"""以适合 DEM / DSM 的方式查看单波段 TIFF。
直接 ``imshow(img)`` 会把异常值或 NoData 一起纳入色阶,导致大部分高程
像素显示成相近的颜色。这里默认使用有效像素的百分位拉伸,并叠加 hillshade。
"""
from pathlib import Path
from typing import Optional, Union
import matplotlib.pyplot as plt
import numpy as np
import tifffile
from matplotlib.colors import LightSource, LinearSegmentedColormap
# 项目模型约定的高程色带:低值为蓝色,高值依次经过绿、黄,最终为红色。
# 从高值向低值看即客户所述的“红、黄、绿、蓝”。
PROJECT_CMAP = LinearSegmentedColormap.from_list(
"project_red_yellow_green_blue",
["#0000ff", "#00ff00", "#ffff00", "#ff0000"],
N=256,
)
def _first_band(image: np.ndarray) -> np.ndarray:
"""返回单波段数组;多波段 TIFF 默认显示第一个波段。"""
image = np.squeeze(image)
if image.ndim == 3:
# tifffile 常见布局为 (bands, height, width)
return image[0] if image.shape[0] <= 4 else image[..., 0]
if image.ndim != 2:
raise ValueError(f"只支持二维或单波段 TIFF,当前形状为 {image.shape}")
return image
def read_elevation(path: Union[str, Path], nodata: Optional[float] = 0) -> np.ma.MaskedArray:
"""读取 TIFF 并掩盖 NaN、Inf、默认 NoData(0) 和指定 NoData。"""
data = _first_band(tifffile.imread(path)).astype(np.float64)
invalid = ~np.isfinite(data)
# 本项目的 DSM/DEM 背景为 0;若 0 是有效海拔,请传入 nodata=None。
if nodata is not None:
invalid |= data == nodata
return np.ma.masked_array(data, mask=invalid)
def show_elevation(path: Union[str, Path], nodata: Optional[float] = 0,
low: float = 2, high: float = 98) -> None:
"""用百分位拉伸和彩色阴影显示 DEM/DSM。"""
elevation = read_elevation(path, nodata)
valid = elevation.compressed()
if valid.size == 0:
raise ValueError("没有可显示的有效像素,请检查 nodata 参数。")
vmin, vmax = np.percentile(valid, (low, high))
if vmin == vmax:
vmin, vmax = valid.min(), valid.max()
# 使用项目约定的红、黄、绿、蓝色带;hillshade 保留坡向、沟谷和建筑纹理。
cmap = PROJECT_CMAP.copy()
cmap.set_bad("#202020")
shaded = LightSource(azdeg=315, altdeg=45).shade(
elevation.filled(vmin), cmap=cmap, vmin=vmin, vmax=vmax,
blend_mode="overlay", vert_exag=2.5,
)
shaded[elevation.mask] = (0.12, 0.12, 0.12, 1.0)
fig, ax = plt.subplots(figsize=(10, 8), constrained_layout=True)
ax.imshow(shaded, interpolation="nearest")
ax.set_title(f"{Path(path).name} | contrast: P{low:g}P{high:g} ({vmin:.2f}{vmax:.2f})")
ax.set_axis_off()
fig.colorbar(
plt.cm.ScalarMappable(norm=plt.Normalize(vmin=vmin, vmax=vmax), cmap=cmap),
ax=ax, label="Elevation",
)
plt.show()
if __name__ == "__main__":
# show_elevation("dsm_final.tif")
# dem_final.tif 的 NoData 是 -9999;不掩盖它会让色阶被严重拉低。
# show_elevation("dsm_final.tif", nodata=-9999, low=1, high=99)
# show_elevation("DEM1.tif", nodata=-9999, low=1, high=99)
show_elevation("DEM2.tif", nodata=-9999, low=1, high=99)