共计 2269 个字符,预计需要花费 6 分钟才能阅读完成。
开篇:地理空间数据标注的痛点
做过遥感影像分析的朋友都知道,传统人工标注方法在地理空间数据上简直是噩梦。我最近在一个农田识别项目里深有体会:

- 坐标系对齐问题:无人机影像和卫星数据空间参考不统一,手动配准浪费了 3 天时间
- 样本分布不均:农田地块大小差异极大,小目标占比不到 5%,模型根本学不会
- 标注效率低下:在 ArcGIS 里逐个多边形点击,标注 100 张图鼠标都要按坏了
技术方案选型
ArcGIS Pro 原生工具 vs 自定义脚本
尝试过两种方案后,我的结论是:
- Labeling Tools 工具箱
- 优点:可视化操作友好,支持直接导出训练样本
-
缺点:批量处理能力弱,无法自定义数据增强
-
Python+arcpy 方案
- 优点:可集成 OpenCV 等第三方库,自由度极高
- 缺点:需要开发时间,对 Python 基础要求较高
标注格式选择(实测对比)
| 格式类型 | 支持通道数 | 坐标保留精度 | 文件体积 |
|---|---|---|---|
| COCO | 仅 RGB | 0.1 像素误差 | 较大 |
| YOLO | 多光谱 | 整数像素 | 较小 |
| ArcGIS 专用 | 全支持 | 地理坐标 | 最大 |
推荐方案:YOLO 格式 + 自定义元数据文件保存地理信息
核心实现步骤
1. 自动化栅格处理流水线
import arcpy
from pathlib import Path
# 配置环境
arcpy.env.overwriteOutput = True
workspace = Path('./output')
workspace.mkdir(exist_ok=True)
# 批量切片函数
def tile_raster(in_raster, tile_size=512):
try:
# 自动计算重叠像素(解决边缘目标截断)overlap = int(tile_size * 0.2) # 20% 重叠
# 关键步骤:保持地理坐标对齐
arcpy.management.SplitRaster(
in_raster,
str(workspace),
"tile_",
"SIZE_OF_TILE",
"TIFF",
"BILINEAR",
tile_size=tile_size,
overlap=overlap,
cellsize="",
origin="",
spatial_reference=arcpy.SpatialReference(4326)
)
arcpy.AddMessage(f"成功切片: {in_raster}")
except Exception as e:
arcpy.AddError(f"切片失败: {str(e)}")
2. 多光谱数据归一化
import numpy as np
# 处理 Sentinel- 2 数据的示例
def normalize_ms_bands(arr):
"""
对 10m/20m 分辨率波段分别归一化
arr: numpy 数组 (bands, height, width)
"""
# 各波段有效值范围(根据传感器调整)min_max = {0: (0, 3000), # B2
1: (0, 3000), # B3
2: (0, 3000), # B4
3: (0, 5000) # B8
}
normalized = np.zeros_like(arr, dtype=np.float32)
for b in range(arr.shape[0]):
band_min, band_max = min_max.get(b, (0, 1))
normalized[b] = (arr[b] - band_min) / (band_max - band_min)
return np.clip(normalized, 0, 1)
3. 小目标增强策略
针对农田地块检测的特殊处理:
- 旋转增强:90°、180°、270°三个角度
- 镜像翻转:左右 + 上下组合
- 色彩扰动:仅对 RGB 波段进行 HSV 空间微调
避坑指南
瓦片边缘处理
- 必须设置重叠像素(建议 15-20%)
- 测试阶段发现:无重叠时边缘地块召回率下降 37%
坐标转换精度
# 地理坐标转像素坐标的正确姿势
def geo_to_pixel(geo_x, geo_y, transform):
"""
transform: GDAL 格式的 GeoTransform
返回 (col, row) 像素坐标
"""
px = int((geo_x - transform[0]) / transform[1])
py = int((geo_y - transform[3]) / transform[5])
return (px, py)
大文件内存优化
- 使用
arcpy.RasterToNumPyArray时设置nodata_to_value - 分块读取示例:
for x in range(0, width, block_size):
for y in range(0, height, block_size):
window = arcpy.Array(arcpy.Point(x, y),
arcpy.Point(x+block_size, y+block_size)
)
block = arcpy.RasterToNumPyArray(
raster,
lower_left_corner=window[0],
ncols=block_size,
nrows=block_size
)
性能验证
在农田识别任务中的对比结果(U-Net 模型):
| 标注方案 | 训练时间 | mAP@0.5 | 小目标召回率 |
|---|---|---|---|
| 原生 ArcGIS 样本 | 4.2h | 0.68 | 0.12 |
| 本文方案 + 增强 | 3.5h | 0.82 | 0.47 |
| 纯手工标注 | 5.1h | 0.71 | 0.23 |
思考与展望
最近在尝试将训练好的模型部署到 ArcGIS Online,遇到几个有趣的问题:
- 如何将 PyTorch 模型转换为 Esri 支持的格式?
- 分布式推理时怎样处理不同区域的坐标系差异?
- 能否利用 Serverless 架构实现实时更新训练数据?
欢迎在评论区分享你的解决方案,下次我会整理出模型部署的完整教程。
正文完
发表至: 未分类
四天前
