从零构建卫星图像分割系统KerasUNet实战指南当第一次看到卫星图像中密密麻麻的建筑群时你可能好奇如何让计算机自动识别这些建筑物的轮廓。传统方法需要人工勾画每个屋顶的边缘费时费力。现在借助深度学习技术我们可以训练一个智能系统来自动完成这项任务。本文将手把手带你用UNet架构实现卫星图像建筑物分割从数据准备到模型部署全流程实战。1. 项目准备与环境搭建工欲善其事必先利其器。在开始编码前我们需要准备好开发环境和数据集。推荐使用Python 3.8和TensorFlow 2.x环境它们对深度学习新手最为友好。基础环境配置conda create -n satellite_seg python3.8 conda activate satellite_seg pip install tensorflow-gpu2.6.0 keras opencv-python matplotlib对于硬件配置即使没有高端GPU也能完成本实验。Massachusetts Buildings Dataset中的图像尺寸适中1500x1500像素裁剪为256x256 patches在RTX 3060显卡上每个epoch约需2分钟。数据集获取与预处理官方数据集包含151张波士顿地区航拍图TIFF格式每张图像配套有二进制掩码黑色背景白色建筑物轮廓建议按8:1:1比例分割训练/验证/测试集import numpy as np from skimage import io def load_data(img_path, mask_path, target_size(256,256)): img io.imread(img_path) mask io.imread(mask_path) img cv2.resize(img, target_size) mask cv2.resize(mask, target_size) return img, mask.astype(np.float32)/255.0注意卫星图像通常有多个波段RGB红外等本实验先用RGB三通道数据入门后续可扩展为多光谱分析2. UNet架构深度解析UNet之所以成为图像分割领域的标杆模型源于其独特的编码器-解码器结构。与普通CNN不同UNet通过跳跃连接(skip connections)保留空间细节信息。UNet核心组件对比表组件类型作用典型参数卫星图像适配建议编码器卷积块特征提取3x3卷积ReLU增加通道数至64-256最大池化下采样2x2窗口保持默认步长2上采样恢复分辨率转置卷积/插值推荐转置卷积跳跃连接融合高低级特征通道拼接确保尺寸对齐输出层生成掩码1x1卷积sigmoid单通道二分类输出针对卫星图像特点我们对原始UNet做出以下改进输入层接受3通道RGB图像原版为1通道医学图像输出层使用sigmoid激活而非softmax二分类问题添加BatchNormalization加速收敛在跳跃连接处引入注意力机制可选from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, Conv2DTranspose, concatenate def conv_block(inputs, filters): x Conv2D(filters, 3, paddingsame, activationrelu)(inputs) x Conv2D(filters, 3, paddingsame, activationrelu)(x) return x def build_unet(input_shape(256,256,3)): # 编码器 inputs Input(input_shape) conv1 conv_block(inputs, 64) pool1 MaxPooling2D()(conv1) conv2 conv_block(pool1, 128) pool2 MaxPooling2D()(conv2) # 瓶颈层 conv3 conv_block(pool2, 256) # 解码器 up4 Conv2DTranspose(128, (2,2), strides(2,2), paddingsame)(conv3) merge4 concatenate([up4, conv2]) conv4 conv_block(merge4, 128) up5 Conv2DTranspose(64, (2,2), strides(2,2), paddingsame)(conv4) merge5 concatenate([up5, conv1]) conv5 conv_block(merge5, 64) # 输出 outputs Conv2D(1, (1,1), activationsigmoid)(conv5) return tf.keras.Model(inputs, outputs)3. 模型训练与调优技巧有了数据和模型架构接下来进入关键的训练阶段。卫星图像分割面临两个主要挑战类别不平衡建筑物像素占比小和细节保持需求。损失函数选择对比二元交叉熵基础选择但对不平衡数据敏感Dice系数直接优化分割区域重叠度Tversky损失调整假阳/假阴权重Focal损失降低易分类样本的权重推荐使用Dice损失BCE的复合损失def dice_coef(y_true, y_pred, smooth1): intersection tf.reduce_sum(y_true * y_pred) return (2. * intersection smooth) / (tf.reduce_sum(y_true) tf.reduce_sum(y_pred) smooth) def dice_loss(y_true, y_pred): return 1 - dice_coef(y_true, y_pred) def bce_dice_loss(y_true, y_pred): return tf.keras.losses.binary_crossentropy(y_true, y_pred) dice_loss(y_true, y_pred)训练配置建议model.compile(optimizertf.keras.optimizers.Adam(learning_rate1e-4), lossbce_dice_loss, metrics[accuracy, dice_coef]) callbacks [ tf.keras.callbacks.EarlyStopping(patience10), tf.keras.callbacks.ModelCheckpoint(best_model.h5, save_best_onlyTrue), tf.keras.callbacks.ReduceLROnPlateau(factor0.1, patience3) ] history model.fit(train_dataset, epochs50, validation_dataval_dataset, callbackscallbacks)数据增强策略from tensorflow.keras.preprocessing.image import ImageDataGenerator train_datagen ImageDataGenerator( rotation_range15, width_shift_range0.1, height_shift_range0.1, shear_range0.1, zoom_range0.1, horizontal_flipTrue, fill_modereflect )4. 结果评估与可视化分析训练完成后我们需要定量和定性评估模型性能。常用的评估指标包括IoU交并比预测与真实掩码的重叠区域占比Precision/Recall针对建筑物像素的精确率与召回率F1-Score精确率与召回率的调和平均def evaluate_model(model, test_dataset): results [] for img, mask in test_dataset: pred model.predict(img[np.newaxis,...]) pred_bin (pred 0.5).astype(np.uint8) # 计算IoU intersection np.logical_and(mask, pred_bin) union np.logical_or(mask, pred_bin) iou np.sum(intersection) / np.sum(union) results.append(iou) return np.mean(results)可视化对比结果import matplotlib.pyplot as plt def plot_results(img, true_mask, pred_mask): plt.figure(figsize(15,5)) plt.subplot(1,3,1) plt.imshow(img) plt.title(原始图像) plt.subplot(1,3,2) plt.imshow(true_mask, cmapgray) plt.title(真实掩码) plt.subplot(1,3,3) plt.imshow(pred_mask 0.5, cmapgray) plt.title(预测结果) plt.show()典型问题与解决方案边缘模糊增加解码器通道数或添加注意力机制小建筑漏检使用多尺度训练或FPN结构阴影误识别引入HSV颜色空间特征过拟合添加Dropout层或正则化项5. 模型部署与生产优化当模型达到满意效果后可以考虑部署到实际应用中。针对不同场景部署方案也有所差异部署方案对比表场景推荐方案优势注意事项本地分析TensorFlow SavedModel保留完整模型信息需安装TF环境Web服务FlaskTensorFlow Serving支持并发请求注意内存管理移动端TFLite量化模型体积小效率高精度略有下降云端APIAWS SageMaker弹性扩展成本较高模型优化技巧# 转换为TFLite格 converter tf.lite.TFLiteConverter.from_keras_model(model) converter.optimizations [tf.lite.Optimize.DEFAULT] tflite_model converter.convert() # 模型量化8位整型 converter.target_spec.supported_ops [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] converter.inference_input_type tf.uint8 converter.inference_output_type tf.uint8 quantized_model converter.convert()性能优化建议使用ONNX Runtime加速推理实现滑动窗口预测大尺寸图像添加后处理如CRF细化边缘采用多线程数据加载# 滑动窗口预测示例 def predict_large_image(model, large_img, window_size256, stride128): h, w large_img.shape[:2] mask np.zeros((h,w)) for y in range(0, h-window_size, stride): for x in range(0, w-window_size, stride): patch large_img[y:ywindow_size, x:xwindow_size] pred model.predict(patch[np.newaxis,...])[0,:,:,0] mask[y:ywindow_size, x:xwindow_size] np.maximum( mask[y:ywindow_size, x:xwindow_size], pred) return mask在实际项目中我们发现将预测结果转为GeoJSON格式可方便与GIS系统集成import geopandas as gpd from skimage.measure import find_contours def mask_to_geojson(pred_mask, threshold0.5, simplify_tolerance1.0): contours find_contours(pred_mask, threshold) polygons [] for contour in contours: if len(contour) 2: # 至少3个点才能构成面 poly Polygon(contour) poly poly.simplify(simplify_tolerance) polygons.append(poly) gdf gpd.GeoDataFrame(geometrypolygons) return gdf.to_json()
你的第一个图像分割项目:用Keras+UNet搞定卫星图像建筑物提取(附完整数据集和代码)
从零构建卫星图像分割系统KerasUNet实战指南当第一次看到卫星图像中密密麻麻的建筑群时你可能好奇如何让计算机自动识别这些建筑物的轮廓。传统方法需要人工勾画每个屋顶的边缘费时费力。现在借助深度学习技术我们可以训练一个智能系统来自动完成这项任务。本文将手把手带你用UNet架构实现卫星图像建筑物分割从数据准备到模型部署全流程实战。1. 项目准备与环境搭建工欲善其事必先利其器。在开始编码前我们需要准备好开发环境和数据集。推荐使用Python 3.8和TensorFlow 2.x环境它们对深度学习新手最为友好。基础环境配置conda create -n satellite_seg python3.8 conda activate satellite_seg pip install tensorflow-gpu2.6.0 keras opencv-python matplotlib对于硬件配置即使没有高端GPU也能完成本实验。Massachusetts Buildings Dataset中的图像尺寸适中1500x1500像素裁剪为256x256 patches在RTX 3060显卡上每个epoch约需2分钟。数据集获取与预处理官方数据集包含151张波士顿地区航拍图TIFF格式每张图像配套有二进制掩码黑色背景白色建筑物轮廓建议按8:1:1比例分割训练/验证/测试集import numpy as np from skimage import io def load_data(img_path, mask_path, target_size(256,256)): img io.imread(img_path) mask io.imread(mask_path) img cv2.resize(img, target_size) mask cv2.resize(mask, target_size) return img, mask.astype(np.float32)/255.0注意卫星图像通常有多个波段RGB红外等本实验先用RGB三通道数据入门后续可扩展为多光谱分析2. UNet架构深度解析UNet之所以成为图像分割领域的标杆模型源于其独特的编码器-解码器结构。与普通CNN不同UNet通过跳跃连接(skip connections)保留空间细节信息。UNet核心组件对比表组件类型作用典型参数卫星图像适配建议编码器卷积块特征提取3x3卷积ReLU增加通道数至64-256最大池化下采样2x2窗口保持默认步长2上采样恢复分辨率转置卷积/插值推荐转置卷积跳跃连接融合高低级特征通道拼接确保尺寸对齐输出层生成掩码1x1卷积sigmoid单通道二分类输出针对卫星图像特点我们对原始UNet做出以下改进输入层接受3通道RGB图像原版为1通道医学图像输出层使用sigmoid激活而非softmax二分类问题添加BatchNormalization加速收敛在跳跃连接处引入注意力机制可选from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, Conv2DTranspose, concatenate def conv_block(inputs, filters): x Conv2D(filters, 3, paddingsame, activationrelu)(inputs) x Conv2D(filters, 3, paddingsame, activationrelu)(x) return x def build_unet(input_shape(256,256,3)): # 编码器 inputs Input(input_shape) conv1 conv_block(inputs, 64) pool1 MaxPooling2D()(conv1) conv2 conv_block(pool1, 128) pool2 MaxPooling2D()(conv2) # 瓶颈层 conv3 conv_block(pool2, 256) # 解码器 up4 Conv2DTranspose(128, (2,2), strides(2,2), paddingsame)(conv3) merge4 concatenate([up4, conv2]) conv4 conv_block(merge4, 128) up5 Conv2DTranspose(64, (2,2), strides(2,2), paddingsame)(conv4) merge5 concatenate([up5, conv1]) conv5 conv_block(merge5, 64) # 输出 outputs Conv2D(1, (1,1), activationsigmoid)(conv5) return tf.keras.Model(inputs, outputs)3. 模型训练与调优技巧有了数据和模型架构接下来进入关键的训练阶段。卫星图像分割面临两个主要挑战类别不平衡建筑物像素占比小和细节保持需求。损失函数选择对比二元交叉熵基础选择但对不平衡数据敏感Dice系数直接优化分割区域重叠度Tversky损失调整假阳/假阴权重Focal损失降低易分类样本的权重推荐使用Dice损失BCE的复合损失def dice_coef(y_true, y_pred, smooth1): intersection tf.reduce_sum(y_true * y_pred) return (2. * intersection smooth) / (tf.reduce_sum(y_true) tf.reduce_sum(y_pred) smooth) def dice_loss(y_true, y_pred): return 1 - dice_coef(y_true, y_pred) def bce_dice_loss(y_true, y_pred): return tf.keras.losses.binary_crossentropy(y_true, y_pred) dice_loss(y_true, y_pred)训练配置建议model.compile(optimizertf.keras.optimizers.Adam(learning_rate1e-4), lossbce_dice_loss, metrics[accuracy, dice_coef]) callbacks [ tf.keras.callbacks.EarlyStopping(patience10), tf.keras.callbacks.ModelCheckpoint(best_model.h5, save_best_onlyTrue), tf.keras.callbacks.ReduceLROnPlateau(factor0.1, patience3) ] history model.fit(train_dataset, epochs50, validation_dataval_dataset, callbackscallbacks)数据增强策略from tensorflow.keras.preprocessing.image import ImageDataGenerator train_datagen ImageDataGenerator( rotation_range15, width_shift_range0.1, height_shift_range0.1, shear_range0.1, zoom_range0.1, horizontal_flipTrue, fill_modereflect )4. 结果评估与可视化分析训练完成后我们需要定量和定性评估模型性能。常用的评估指标包括IoU交并比预测与真实掩码的重叠区域占比Precision/Recall针对建筑物像素的精确率与召回率F1-Score精确率与召回率的调和平均def evaluate_model(model, test_dataset): results [] for img, mask in test_dataset: pred model.predict(img[np.newaxis,...]) pred_bin (pred 0.5).astype(np.uint8) # 计算IoU intersection np.logical_and(mask, pred_bin) union np.logical_or(mask, pred_bin) iou np.sum(intersection) / np.sum(union) results.append(iou) return np.mean(results)可视化对比结果import matplotlib.pyplot as plt def plot_results(img, true_mask, pred_mask): plt.figure(figsize(15,5)) plt.subplot(1,3,1) plt.imshow(img) plt.title(原始图像) plt.subplot(1,3,2) plt.imshow(true_mask, cmapgray) plt.title(真实掩码) plt.subplot(1,3,3) plt.imshow(pred_mask 0.5, cmapgray) plt.title(预测结果) plt.show()典型问题与解决方案边缘模糊增加解码器通道数或添加注意力机制小建筑漏检使用多尺度训练或FPN结构阴影误识别引入HSV颜色空间特征过拟合添加Dropout层或正则化项5. 模型部署与生产优化当模型达到满意效果后可以考虑部署到实际应用中。针对不同场景部署方案也有所差异部署方案对比表场景推荐方案优势注意事项本地分析TensorFlow SavedModel保留完整模型信息需安装TF环境Web服务FlaskTensorFlow Serving支持并发请求注意内存管理移动端TFLite量化模型体积小效率高精度略有下降云端APIAWS SageMaker弹性扩展成本较高模型优化技巧# 转换为TFLite格 converter tf.lite.TFLiteConverter.from_keras_model(model) converter.optimizations [tf.lite.Optimize.DEFAULT] tflite_model converter.convert() # 模型量化8位整型 converter.target_spec.supported_ops [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] converter.inference_input_type tf.uint8 converter.inference_output_type tf.uint8 quantized_model converter.convert()性能优化建议使用ONNX Runtime加速推理实现滑动窗口预测大尺寸图像添加后处理如CRF细化边缘采用多线程数据加载# 滑动窗口预测示例 def predict_large_image(model, large_img, window_size256, stride128): h, w large_img.shape[:2] mask np.zeros((h,w)) for y in range(0, h-window_size, stride): for x in range(0, w-window_size, stride): patch large_img[y:ywindow_size, x:xwindow_size] pred model.predict(patch[np.newaxis,...])[0,:,:,0] mask[y:ywindow_size, x:xwindow_size] np.maximum( mask[y:ywindow_size, x:xwindow_size], pred) return mask在实际项目中我们发现将预测结果转为GeoJSON格式可方便与GIS系统集成import geopandas as gpd from skimage.measure import find_contours def mask_to_geojson(pred_mask, threshold0.5, simplify_tolerance1.0): contours find_contours(pred_mask, threshold) polygons [] for contour in contours: if len(contour) 2: # 至少3个点才能构成面 poly Polygon(contour) poly poly.simplify(simplify_tolerance) polygons.append(poly) gdf gpd.GeoDataFrame(geometrypolygons) return gdf.to_json()