告别手动标注!用Labelme+Python高效制作遥感变化检测数据集(附完整代码)

张开发
2026/4/23 14:13:43 15 分钟阅读

分享文章

告别手动标注!用Labelme+Python高效制作遥感变化检测数据集(附完整代码)
遥感变化检测数据集自动化生产实战从标注到模型训练的完整Pipeline当我在处理第一个遥感变化检测项目时花了整整三天时间手动标注了2000多张图像。手指因为长时间点击鼠标而酸痛眼睛也因为盯着屏幕太久而干涩。直到发现了Labelme和Python自动化工具链我才意识到原来数据集制作可以如此高效。本文将分享一套经过实战检验的全自动化遥感变化检测数据集生产流程涵盖从标注策略到数据增强的完整闭环。1. 重新定义遥感变化检测数据标准传统的数据集制作往往只关注有没有标注而忽略了数据质量对模型性能的乘数效应。我们需要的不仅是标注工具的使用技巧更是一套完整的质量评估体系。1.1 多时相数据对齐的黄金法则时间基线选择城市变化检测建议时间间隔1-3年农林变化建议间隔不超过1年辐射校正使用ENVI或QGIS进行直方图匹配确保不同时相影像的光照条件一致几何配准控制RMS误差在0.5个像素以内可采用以下OpenCV配准代码import cv2 def align_images(img1, img2): # 转换为灰度图 gray1 cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) gray2 cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) # 使用ORB特征检测器 orb cv2.ORB_create(1000) kp1, des1 orb.detectAndCompute(gray1, None) kp2, des2 orb.detectAndCompute(gray2, None) # 特征匹配 bf cv2.BFMatcher(cv2.NORM_HAMMING, crossCheckTrue) matches bf.match(des1, des2) matches sorted(matches, keylambda x: x.distance) # 提取匹配点坐标 src_pts np.float32([kp1[m.queryIdx].pt for m in matches]).reshape(-1,1,2) dst_pts np.float32([kp2[m.trainIdx].pt for m in matches]).reshape(-1,1,2) # 计算单应性矩阵 M, mask cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) # 应用变换 aligned cv2.warpPerspective(img1, M, (img2.shape[1], img2.shape[0])) return aligned提示对于高分辨率遥感影像建议先降采样到1024x1024进行粗配准再在原图上进行精配准1.2 标注质量控制的三个维度质量指标达标要求检查方法边界精度误差≤3个像素放大至400%目视检查类别一致性同类别标注标准统一多人交叉验证变化真实性排除季节变化等伪变化参考中间时相影像标注完整性漏检率5%随机抽样检查标签匹配度与多时相变化区域高度吻合双时相叠加显示2. Labelme高级标注技巧实战大多数教程只教了Labelme的基础用法却忽略了这些能提升3倍效率的专业技巧。2.1 批量标注的工程化方案预处理脚本自动化# 批量转换TIFF为PNG并统一尺寸 for f in *.tif; do convert $f -resize 1024x1024 ${f%.*}.png done标注模板复用对同类地物建立预设多边形模板使用CtrlC/V快速复制相似形状保存常用标签组合为预设配置快捷键组合拳Ctrl鼠标滚轮快速缩放空格拖动平移视图Esc完成当前多边形2.2 标注质量实时检查工具开发了这个实时检查脚本能在标注过程中自动发现问题from labelme import utils import numpy as np def check_annotation(json_file): data json.load(open(json_file)) img utils.img_b64_to_arr(data[imageData]) label utils.shapes_to_label( img.shape, data[shapes], data[labels] ) # 检查标注覆盖率 coverage np.sum(label0) / (label.size) if coverage 0.01: print(f警告标注覆盖率不足1% ({coverage:.2%})) # 检查小面积多边形 for shape in data[shapes]: points shape[points] area 0.5 * abs(sum( x0*y1 - x1*y0 for (x0,y0), (x1,y1) in zip( points, points[1:] [points[0]] ) )) if area 10: print(f发现极小多边形{shape[label]} (面积{area:.1f}像素))3. 智能裁剪与样本平衡算法原始随机裁剪方法会带来严重的样本失衡问题这是我们改进后的自适应裁剪方案。3.1 基于注意力机制的裁剪策略def smart_crop(img, label, size256): 基于变化区域热力图生成裁剪坐标 # 生成变化区域热力图 kernel cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(15,15)) heatmap cv2.dilate(label.astype(np.uint8), kernel) # 计算候选区域 contours, _ cv2.findContours( heatmap, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE ) boxes [] for cnt in contours: x,y,w,h cv2.boundingRect(cnt) for _ in range(int(w*h/size**2)*2): # 按面积比例采样 i np.random.randint(x, xw-size) j np.random.randint(y, yh-size) boxes.append((i,j)) # 确保正负样本平衡 if len(boxes) 0: for _ in range(min(len(boxes), 10)): # 每个变化区域最多采10个 i,j boxes.pop(np.random.randint(0, len(boxes))) yield img[j:jsize, i:isize], label[j:jsize, i:isize] # 补充背景样本 bg_num len(boxes) while bg_num 0: i np.random.randint(0, img.shape[1]-size) j np.random.randint(0, img.shape[0]-size) if np.all(label[j:jsize, i:isize] 0): yield img[j:jsize, i:isize], label[j:jsize, i:isize] bg_num - 13.2 数据增强的进阶技巧常规的旋转翻转已经不够用了试试这些针对遥感特性的增强方法辐射扰动模拟不同季节的光照变化def radiometric_augment(img): # HSV空间扰动 hsv cv2.cvtColor(img, cv2.COLOR_BGR2HSV) hsv[...,1] hsv[...,1] * np.random.uniform(0.8, 1.2) hsv[...,2] hsv[...,2] * np.random.uniform(0.9, 1.1) return cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)云雾模拟添加随机噪声模拟云层覆盖分辨率抖动模拟不同传感器的分辨率差异4. 数据集版本管理与质量监控在团队协作中我们使用这套数据版本控制系统来保证数据集迭代质量4.1 数据集目录结构规范ChangeDet_Dataset/ ├── v1.0/ # 版本目录 │ ├── raw/ # 原始数据 │ │ ├── 2020_Shanghai/ │ │ └── 2022_Shanghai/ │ ├── annotations/ # Labelme JSON文件 │ ├── crops/ # 裁剪后的样本 │ │ ├── train/ │ │ └── val/ │ └── stats.json # 数据集统计信息 └── v1.1/ # 新版本4.2 自动化质量检查流水线import pandas as pd from sklearn.model_selection import train_test_split class DatasetValidator: def __init__(self, data_dir): self.df self._build_metadata(data_dir) def _build_metadata(self, path): 构建包含所有样本元数据的DataFrame records [] for label_file in Path(path).rglob(*.json): img_file label_file.with_suffix(.png) stats self._get_image_stats(img_file) records.append({ **stats, path: str(img_file.relative_to(path)), size_MB: os.path.getsize(img_file)/1024/1024 }) return pd.DataFrame(records) def check_balance(self): 检查类别分布平衡性 class_dist self.df[class].value_counts() return class_dist / class_dist.sum() def split_dataset(self, test_size0.2): 确保训练/验证集分布一致 train, val train_test_split( self.df, test_sizetest_size, stratifyself.df[class] ) return train, val注意每次数据更新时运行完整检查流程确保不会引入分布偏移在最后一个项目中这套流程帮助我们将标注效率提升了8倍同时将模型准确率提高了15%。最让我意外的是合理的数据增强策略甚至比更换更复杂的模型架构带来的提升更大。

更多文章