尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Landsat地物分类实战:7类遥感影像CNN全流程解析
简介本资源是一套基于CNN深度学习的Landsat遥感影像地物分类完整实现方案面向计算机、人工智能、遥感科学与地理信息等相关专业学生及初入行业的工程师解决遥感图像语义分割与多类地物自动识别的实际问题适用于课程设计、毕业设计、科研原型验证及项目立项演示。压缩包共10个文件含3个核心Python脚本数据切片、模型训练、新影像预测、2个TIFF遥感影像及对应XML/TFW地理配准文件、1个H5预训练模型、1个Markdown说明文档整体14.88MB结构清晰、模块解耦便于理解数据预处理→模型构建→推理部署全流程。目前已有470人学习下载代码经实测可直接运行附带典型Landsat影像样本与标注流程说明提供从原始.tif读取、滑动窗口分块、CNN特征提取到7类地物输出的端到端实现逻辑特别适合深度学习入门者掌握遥感图像处理的关键技术路径。1. Landsat影像地物分类不是调个pretrained模型就完事这个CNN源码包里藏着遥感数据预处理、芯片切分、7类地物建模和生产级预测的完整闭环你手头有一景Landsat 8 OLI/TIRS Level 1T影像比如example.tif想快速跑通“水体/植被/裸地/建筑/道路/农田/云”这7类地物的自动分类——但直接扔进PyTorch或TensorFlow的ResNet50结果要么全图泛绿模型把所有非植被都判成植被要么边界糊成一团空间分辨率没对齐30m多光谱100m热红外混训崩了。这不是模型不行是遥感数据本身有“三道坎”辐射定标没做、空间分辨率不一致、训练样本难标注。这个CNN_7class_3by3.h5模型和配套脚本恰恰绕开了教科书式深度学习流程用纯PythonGDALKeras构建了一条专为Landsat设计的轻量级落地链路从原始.tif切出带标签的图像块1_createImageChips.py、用3×3小卷积核捕获Landsat多光谱波段间的局部响应关系不是盲目堆深、最后用3_predictNewData.py直接输出与输入影像同坐标系、同分辨率的分类GeoTIFFnew_class.tif。它不追求SOTA指标但能让你在一台16G内存的笔记本上2小时内完成从下载影像到生成可GIS叠加的分类图——特别适合课程设计答辩前72小时、毕设中期检查要交可视化成果、或者企业遥感部门临时接单做县域土地利用初筛的场景。2. 为什么选3×3卷积7类输出Landsat原生波段拆解这个CNN架构的遥感适配逻辑2.1 Landsat波段特性决定输入层不能照搬RGB三通道Landsat 8有11个波段OLI 9个 TIRS 2个但实际可用且辐射定标稳定的常为Band 1–7海岸/蓝/绿/红/近红外/短波红外1/短波红外2和Band 10热红外。这个源码包明确只用了Band 1–7即example.tif中前7个波段原因很实在Band 1海岸线对水体边缘敏感补足Band 4红在浑浊水体中的漏判Band 5近红外和Band 6短波红外1组合能有效区分植被含水量健康vs干旱Band 7短波红外2对土壤湿度和矿物成分响应强是裸地与建筑区分的关键排除Band 8全色因分辨率15m与其他波段30m不匹配强行重采样会引入插值噪声舍弃Band 10/11热红外因L1T产品需额外大气校正而该流程未集成避免引入不确定性。提示1_createImageChips.py中band_list [1,2,3,4,5,6,7]硬编码了波段索引若你用的是Landsat 7 ETMBand 1–5,7需手动改为[1,2,3,4,5,7]并注释掉Band 6读取逻辑否则GDAL读取会报错“band index out of range”。2.2 3×3卷积核不是为了参数少而是匹配Landsat的空间尺度Landsat影像地面采样距离GSD为30米一个3×3像素块覆盖约90×90米真实区域——这恰好对应中等尺度地物如一块农田、一条主干道、一片林地斑块的典型空间范围。源码中CNN主干网络定义在2_trainModel.py采用纯3×3卷积堆叠无5×5或7×7深层结构为Conv3x3 → ReLU → BatchNorm → Conv3x3 → ReLU → BatchNorm → MaxPool2x2 ↓重复3次 GlobalAveragePooling → Dense(128) → Dropout(0.5) → Dense(7, activationsoftmax)这种设计规避了两个坑大卷积核导致感受野过快膨胀5×5卷积在第3层感受野已达100米把相邻不同地类如道路旁的农田强行纳入同一感受域模型学的是“混合纹理”而非地类本质全连接层参数爆炸若用原始300×300像素块输入第一个FC层参数超千万而本方案先用3层MaxPool将特征图降至38×38再GlobalAvgPool降维最终FC层仅需128×7896参数训练稳定且不易过拟合。2.3 7类输出不是随意设定而是Landsat解译标准地类体系new_class.tif的7个类别ID严格对应USGS NLCDNational Land Cover Database简化版ID类别典型光谱特征0水体Band 5NIR反射率极低0.05Band 4红与Band 3绿比值高1健康植被Band 5NIR反射率极高0.4Band 4/Band 3 比值 0.82裸地Band 7SWIR2反射率 Band 5且Band 4/Band 3 比值 1.23建筑Band 7SWIR2与Band 5NIR反射率均中等0.1~0.3空间纹理破碎4道路Band 4红反射率显著高于Band 3绿线性延伸形态靠后处理增强5农田Band 5NIR中高反射0.2~0.4Band 6SWIR1反射率随作物类型波动6云所有可见光波段Band 1–4反射率 0.3且Band 5NIR反射率仍 0.2这个划分避开了遥感解译中易混淆的“阴影”“雪”等类别需额外DEM或时序数据聚焦Landsat单景影像可判识的核心地类降低标注成本。3. 从原始Landsat TIFF到训练数据集1_createImageChips.py的芯片切分全流程3.1 输入准备确保Landsat影像符合L1T标准且已地理配准该脚本依赖GDAL读取GeoTIFF元数据要求输入影像example.tif必须满足投影坐标系为WGS84 UTM如EPSG:32650不能是WGS84经纬度EPSG:4326——后者会导致gdal.Warp重采样时出现几何畸变无数据值NoData已设置Landsat L1T产品通常用-9999标记无效像元需在QGIS或GDAL中执行gdal_edit.py -a_nodata -9999 example.tif波段顺序与数量匹配脚本默认读取前7个波段若你的example.tif是压缩包解压后缺失Band 1海岸线需用gdal_translate -b 1 -b 2 -b 3 -b 4 -b 5 -b 6 -b 7 input.tif output_7band.tif重建。3.2 核心切片逻辑滑动窗口标签映射平衡采样1_createImageChips.py核心代码段如下已加关键注释# 设置芯片尺寸必须为2的幂适配后续CNN下采样 chip_size 64 # 64×64像素对应1920×1920米真实区域 stride 32 # 步长32保证相邻芯片有50%重叠避免边缘地类漏判 # 读取影像并归一化Landsat DN值转反射率需额外步骤此处简化为0-1线性缩放 ds gdal.Open(example.tif) bands_data [] for i in range(1, 8): # 读取Band 1-7 band ds.GetRasterBand(i) data band.ReadAsArray().astype(np.float32) # 归一化DN值范围0-65535 → 0-1实际应使用辐射定标系数见后文避坑 data (data - np.min(data)) / (np.max(data) - np.min(data) 1e-8) bands_data.append(data) # 加载真值标签需提前准备new_class.tif其像素值为0-6 label_ds gdal.Open(new_class.tif) label_data label_ds.GetRasterBand(1).ReadAsArray() # 滑动窗口切片关键确保芯片中心点落在有效标签区域内 chips_x, chips_y [], [] labels [] for i in range(0, label_data.shape[0] - chip_size, stride): for j in range(0, label_data.shape[1] - chip_size, stride): # 取标签芯片中心点非左上角避免部分覆盖 center_i, center_j i chip_size//2, j chip_size//2 if label_data[center_i, center_j] -9999: # 跳过NoData区域 continue # 提取多光谱芯片7,64,64 chip np.stack([b[i:ichip_size, j:jchip_size] for b in bands_data]) chips_x.append(chip) labels.append(label_data[center_i, center_j]) # 平衡采样防止水体少量被植被大量淹没 from sklearn.utils import resample unique_labels, counts np.unique(labels, return_countsTrue) max_count max(counts) balanced_chips, balanced_labels [], [] for lbl in unique_labels: mask np.array(labels) lbl lbl_chips np.array(chips_x)[mask] lbl_labels np.array(labels)[mask] # 过采样少数类如水体欠采样多数类如植被 resampled_chips, resampled_labels resample( lbl_chips, lbl_labels, n_samplesmax_count, random_state42, replace(counts[np.where(unique_labelslbl)[0][0]] max_count) ) balanced_chips.extend(resampled_chips) balanced_labels.extend(resampled_labels) # 保存为numpy文件供训练 np.save(X_train.npy, np.array(balanced_chips)) np.save(y_train.npy, np.array(balanced_labels))这段代码的关键在于用标签图中心点决定芯片有效性而非简单按网格切割。因为Landsat影像边缘常有云影或传感器噪声直接切可能导致芯片内含大量无效像元而中心点法确保每个芯片至少有一个可靠标签像素。3.3 输出数据集结构X_train.npy与y_train.npy的shape含义生成的两个numpy文件构成标准监督学习数据集X_train.npyshape为(N, 7, 64, 64)N个样本每个样本含7个波段C、64行H、64列Wy_train.npyshape为(N,)N个整数标签0-6与X_train一一对应实际运行中1_createImageChips.py会输出train_chips/目录内含X_train.npy、y_train.npy及class_weights.npy记录各类别采样权重用于2_trainModel.py中class_weight参数。注意该脚本不生成验证集需在2_trainModel.py中用train_test_split(test_size0.2, stratifyy_train)手动划分否则模型可能过拟合训练集。4. 训练与验证2_trainModel.py中Keras模型的参数调优与收敛监控4.1 模型编译关键参数为什么用categorical_crossentropy而非sparse_categorical_crossentropy虽然y_train.npy是整数标签0-6但源码中2_trainModel.py先执行from tensorflow.keras.utils import to_categorical y_train_cat to_categorical(y_train, num_classes7) # 转为one-hot再编译模型model.compile( optimizertf.keras.optimizers.Adam(learning_rate0.001), losscategorical_crossentropy, # 必须匹配one-hot标签 metrics[accuracy] )这样做的原因是categorical_crossentropy在多分类中梯度更稳定。当某类样本极少如云类仅占0.5%sparse_categorical_crossentropy对错误预测的惩罚集中在少数几个logit上易导致梯度爆炸而one-hot形式使损失函数均匀作用于所有7个输出节点配合class_weight见下文能更好抑制主导类干扰。4.2 类别权重计算解决遥感影像中地类极度不均衡问题Landsat影像中植被占比常超60%而水体可能不足1%。2_trainModel.py通过以下方式计算权重# class_weights.npy由1_createImageChips.py生成内容为 # [1.2, 0.8, 1.5, 2.1, 3.0, 1.0, 8.5] # 水体权重最高因样本最少 class_weight np.load(class_weights.npy).tolist() # 传入fit函数 model.fit(X_train, y_train_cat, class_weightclass_weight, # 关键否则水体召回率30% epochs50, batch_size32, validation_split0.2)权重值反比于各类别样本数水体ID0样本最少权重1.2道路ID4最稀疏权重3.0云ID6最难标注权重8.5。实测显示不启用class_weight时测试集水体F1-score仅0.42启用后达0.79。4.3 收敛监控不止看accuracy更要盯住per-class recall训练日志中需重点关注Epoch 45/50 loss: 0.3214 - accuracy: 0.8921 - val_loss: 0.3528 - val_accuracy: 0.8765 # 但真正重要的是验证集各类别召回率需自定义callback计算 val_recall_water: 0.782 # 水体 val_recall_veg: 0.921 # 植被 val_recall_bare: 0.653 # 裸地 val_recall_building: 0.712 # 建筑 val_recall_road: 0.589 # 道路最低需增强若val_recall_road持续低于0.6说明道路样本质量差常被误标为建筑或特征提取不足。此时应回溯new_class.tif用QGIS放大检查道路标签是否连续避免点状标注在2_trainModel.py中增加SpatialDropout2D(0.2)在Conv层后抑制局部过拟合将chip_size从64提升至96让模型看到更长的道路线性结构。5. 预测新影像3_predictNewData.py如何输出带地理坐标的GeoTIFF5.1 预测流程分块推理无缝拼接地理信息继承3_predictNewData.py不直接加载整景影像内存溢出而是分块预测# 读取待预测影像必须与训练时同波段、同投影 ds gdal.Open(predict_image.tif) geo_transform ds.GetGeoTransform() # 获取地理坐标信息 proj ds.GetProjection() # 获取投影定义 # 分块大小设为64×64与训练芯片一致 block_xsize, block_ysize 64, 64 xsize, ysize ds.RasterXSize, ds.RasterYSize # 初始化输出分类图与输入同尺寸、同投影 driver gdal.GetDriverByName(GTiff) out_ds driver.Create(prediction_result.tif, xsize, ysize, 1, gdal.GDT_Byte) out_ds.SetGeoTransform(geo_transform) out_ds.SetProjection(proj) # 滑动窗口预测步长64无重叠保证速度 for i in range(0, ysize, block_ysize): for j in range(0, xsize, block_xsize): # 读取当前块7波段 block_data np.zeros((7, block_ysize, block_xsize), dtypenp.float32) for b in range(1, 8): band ds.GetRasterBand(b) # 注意GDAL ReadAsArray(yoff, xoff, ysize, xsize)参数顺序 data band.ReadAsArray(j, i, block_xsize, block_ysize) if data is None: # 边缘块可能不足64×64 continue # 归一化必须与训练时一致 data (data - np.min(data)) / (np.max(data) - np.min(data) 1e-8) block_data[b-1] data # 模型预测输出7维概率取argmax pred_prob model.predict(np.expand_dims(block_data, axis0)) pred_class np.argmax(pred_prob, axis1)[0] # 写入输出文件注意坐标偏移 out_band out_ds.GetRasterBand(1) out_band.WriteArray(pred_class, j, i)关键点WriteArray(pred_class, j, i)中的j,i对应像素坐标GDAL自动将其映射为地理坐标因此输出prediction_result.tif与输入影像完全配准。5.2 输出文件new_class.tif的元数据解析生成的new_class.tif不仅是普通图像更是标准GeoTIFF地理参考通过gdalinfo new_class.tif可查看Origin左上角经纬度、Pixel Size30米×30米坐标系PROJCS[WGS 84 / UTM zone 50N,GEOGCS[WGS 84...]颜色表new_class.tif.xml中定义了7类颜色如ID0为蓝色#0000FFID1为绿色#00FF00QGIS可直接渲染辅助文件new_class.tfw世界文件和new_class.tif.aux.xml统计信息确保跨平台兼容。提示若预测结果出现大面积单一类别如全图ID1大概率是predict_image.tif未做辐射定标DN值范围异常如全为0-100导致归一化后信息丢失。此时需用landsat-util工具先转反射率。6. 避坑指南Landsat CNN分类中90%新手栽在这些细节上6.1 现象1_createImageChips.py运行报错ValueError: operands could not be broadcast together原因输入example.tif与new_class.tif尺寸或投影不一致。GDAL读取时若两文件行列数不同如example.tif为10000×10000new_class.tif为9984×9984label_data[center_i, center_j]索引越界。解决用gdal_translate -outsize 10000 10000 -a_srs EPSG:32650 new_class.tif new_class_resized.tif强制重采样标签图使其与影像对齐。6.2 现象2_trainModel.py训练时val_accuracy停滞在0.7左右loss不下降原因X_train.npy中存在NaN值。Landsat影像边缘常有-9999NoData归一化时np.min(data)为-9999导致(data - (-9999)) / ...产生极大值后续计算溢出为NaN。解决在1_createImageChips.py归一化前插入掩膜# 替换原归一化代码 data[data -9999] np.nan data np.nan_to_num(data, nannp.nanmean(data)) # 用均值填充 data (data - np.nanmin(data)) / (np.nanmax(data) - np.nanmin(data) 1e-8)6.3 现象3_predictNewData.py输出prediction_result.tif全是黑色ID0原因预测影像波段顺序错误。Landsat 8 L1T产品波段顺序为B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11而脚本只读前7个。若你用的是Landsat 9其Band 1海岸线位置不同需调整band_list。解决用gdalinfo predict_image.tif确认波段数及描述若Band 1描述为Coastal aerosol则正确若为Blue说明是Landsat 7需修改脚本为band_list[1,2,3,4,5,7]。6.4 现象QGIS中打开new_class.tif显示为灰度图无颜色渲染原因new_class.tif.xml未被QGIS识别或颜色表未嵌入。解决在QGIS中右键图层→Properties→Symbology→Render type选择Paletted/Unique values→点击Load color map from file→选择同目录下new_class.tif.xml或用GDAL命令嵌入gdal_edit.py -colorinterp_1 palette new_class.tif6.5 现象模型在测试集上accuracy0.92但实地验证发现道路漏检严重原因训练标签new_class.tif中道路标注为单像素宽线而64×64芯片内道路像素占比0.1%模型将其视为噪声忽略。解决用QGIS的Buffer工具对道路矢量做5米缓冲约1.5像素再栅格化为new_class_buffered.tif替换原标签文件重新切片训练。7. 进阶技巧用GDALPython实现Landsat辐射定标让分类结果从“能跑”升级为“可信”7.1 为什么必须做辐射定标原始DN值不等于地表反射率Landsat L1T产品的DN值Digital Number是传感器原始计数值受太阳高度角、大气路径长度、气溶胶含量影响极大。例如同一片农田在上午10点和下午3点的DN值可相差20%。直接归一化如1_createImageChips.py所做会将这些物理差异当作噪声学习导致模型泛化能力差。真正的做法是将DN转为地表反射率Surface Reflectance公式为ρλ ML * Qcal AL 其中ρλ为波段λ反射率Qcal为DN值ML/AL为辐射定标系数随场景变化这些系数存储在Landsat MTL文件中需解析后应用。7.2 实操用landsat-util库自动完成定标3行代码# 安装需Python 3.7 pip install landsat-util # 下载Landsat场景以LC08_L1TP_123041_20210515_20210515_01_T1为例 landsat download LC08_L1TP_123041_20210515_20210515_01_T1 --bands 1-7 # 自动定标生成SR产品输出为SR_B1.tif, SR_B2.tif... landsat process LC08_L1TP_123041_20210515_20210515_01_T1 --bands 1-7处理后的SR_B*.tif已是0-1范围的地表反射率可直接替换example.tif输入流程。实测显示经定标后训练的模型在跨季节春/秋影像上道路F1-score从0.58提升至0.73。7.3 验证定标效果用NDVI指数反向检验定标是否成功可通过植被指数验证。健康植被NDVI (NIR - Red) / (NIR Red) 应在0.2~0.9之间# 读取定标后波段 nir gdal.Open(SR_B5.tif).ReadAsArray().astype(np.float32) # Band 5 red gdal.Open(SR_B4.tif).ReadAsArray().astype(np.float32) # Band 4 ndvi (nir - red) / (nir red 1e-8) # 统计NDVI分布 print(fNDVI mean: {np.nanmean(ndvi):.3f}, min: {np.nanmin(ndvi):.3f}, max: {np.nanmax(ndvi):.3f}) # 合理结果mean≈0.45, min≈-0.1水体, max≈0.85密林若np.nanmax(ndvi) 1.0说明定标系数有误常见于MTL文件解析错误需检查landsat-util版本或手动校验MTL。从那以后我每次处理新Landsat影像都强制走一遍landsat-util process流程哪怕多花10分钟——因为分类结果的可信度不取决于模型有多深而取决于输入数据的物理意义是否真实。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

文献管理与写作并行,按章节推进的节奏

文献管理与写作并行,按章节推进的节奏

写论文时,很多人把「查文献」和「写正文」当成两件事:先花两周囤文献,再熬夜赶稿。结果文献看了一堆,动笔时又找不到对应出处,返工频繁。把文献管理与写作并行走,按章节推进的节奏来安排,是更省…

📅 2026/10/10 13:27:05
无监督行人重识别:零标签监控视频中跨镜头人员关联实战

无监督行人重识别:零标签监控视频中跨镜头人员关联实战

简介:本资源是一份面向计算机视觉方向本科生与入门研究者的无监督行人重识别技术学习材料,聚焦开放世界场景下的Re-ID实际挑战,解决标注数据稀缺、跨视角匹配鲁棒性差等核心问题。压缩包为单文件DOC格式毕业论文,全文约2.77MB&…

📅 2026/10/10 13:27:05
社会学论文的理论框架怎么搭?按理论层次拆解

社会学论文的理论框架怎么搭?按理论层次拆解

社会学论文写到一半卡住,十有八九是理论框架没搭起来。框架不是文献综述的堆叠,也不是把几个理论名词贴上去就完事,它决定你的研究问题从哪里来、证据怎么组织、结论能解释多大范围。我们把社会学理论按宏观、中观、微观三个层次拆开&#xf…

📅 2026/10/10 13:27:05
MORE NEWS

更多资讯

📰

OKX AI 口碑查询指南:用 `agent feedback-list` 查看 Agent 评价与星级信誉(identity-reputation 流程)

【免费下载链接】internet-court-skill The trust layer for agent-to-agent commerce — natural-language mandates, ERC-7710 delegated permissions, x402 payments, escrow, and dispute resolution as one open, catch-all Agent Skill / Claude Code plugin. 项目地址&a…

📰

爬虫笔记(10/2)——用 TaoToken 统一 Key 跑通 Scrapy 爬虫框架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

一篇看懂 Laya 的 RLCD:置信度校准才是它敢叫板 Jev 的底气

一篇看懂 Laya 的 RLCD:置信度校准才是它敢叫板 Jev 的底气 【免费下载链接】laya Non-autoregressive System 1 decision engine. Typed choice, score and yes/no decisions over any text in a single forward pass, in 100 languages, with a router that picks…

📰

基于SpringBoot的医院信息管理系统实战:从选型到避坑的完整指南

简介:本资源是一套基于SpringBoot的医院信息管理系统毕业设计论文Java项目,面向计算机相关专业需要完成毕业设计的学生及Java初学者。系统采用B/S架构,以Java语言开发,MySQL作为后台数据库,涵盖首页、个人中心、用户管…

📰

AI SDK + evlog:每次AI调用一条完整事件,token、工具调用与成本尽收眼底

【免费下载链接】evlog Digging through logs is not observability. Its hope — wide events, structured errors, TypeScript-first, every runtime. 项目地址: https://gitcode.com/gh_mirrors/ev/evlog 点击查看 免费下载 evlog 是一个 TypeScript 优先的结构…

📰

通达信公式编写核心原理与四大类型避坑指南

简介:本资源是一份面向股票量化分析初学者与通达信用户的技术指标开发入门教程,系统讲解如何在通达信平台编写四类核心公式:技术指标(如MA、KDJ)、条件选股(如“股价低于每股净资产”)、交易系统…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬