尧图精选

遥感图像SVM分类实战:从光谱特征工程到模型部署

🕒 发布时间:2026/9/13 5:06:07 📁 来源:尧图网络
简介本资源是一套基于机器学习的遥感图像分类模型完整实现源码面向计算机、人工智能、遥感科学与地理信息等相关专业学生及技术学习者适用于课程设计、期末大作业与毕业设计等实践场景帮助读者掌握遥感影像预处理、特征提取、SVM等经典分类器建模及结果可视化全流程。压缩包共13个文件含6个核心Python脚本如rs_mod_1.py训练模块、rs_plot_2.py绘图模块、2个编译缓存pyc文件、2个配置与结果存储用JSON/Pickle文件、1个VS Code工作区配置及1份README说明文档结构清晰、模块职责分明总大小仅14KB轻量易部署。已有305人学习下载代码经严格调试下载解压后可直接运行配套注释与目录组织便于理解算法逻辑与工程结构特别适合具备Python与机器学习基础的学习者开展遥感图像分类实战与代码级复现。1. 遥感图像分类不是调个 sklearn 就完事这个 SVM 模型源码包里藏着真实数据预处理链路遥感图像分类常被误认为“加载数据 → fit() → predict()”的三步流程但实际项目中80% 的时间花在光谱特征对齐、空间分辨率归一化、云掩膜剔除和样本不平衡校正上。这个名为RS_SVM-1.pickle的模型并非黑盒封装而是完整暴露了从 Landsat 8 多光谱波段B2–B7到最终土地覆盖类型水体/林地/农田/建筑/裸地的端到端机器学习流水线。它不依赖深度学习框架纯用 scikit-learn numpy matplotlib 实现适合想搞懂“为什么遥感分类不能直接套用 MNIST 流程”的学生——比如你刚跑通sklearn.svm.SVC()却发现测试集准确率只有 63%而本项目在相同数据集上达到 89.2%见result.json中test_accuracy字段。代码结构清晰分层rs_mod_*.py负责建模逻辑rs_plot_*.py提供可复现的可视化验证data_plot.py内置波段响应曲线对比图。如果你正在做课程设计或毕设且导师要求“必须体现遥感特性处理”这个包就是你跳过文献综述、直奔核心实现的脚手架。2. 从原始遥感影像到 SVM 输入向量特征工程才是分类成败的关键遥感图像分类的难点不在模型本身而在如何把像素级多维光谱信息转化为 SVM 可理解的数值向量。本项目没有使用 PCA 降维或预训练 CNN 提取特征而是采用一套针对光学遥感数据定制的特征构造策略其核心逻辑藏在rs_mod_1.py和rs_mod_2.py中。2.1 波段组合与指数计算超越原始 DN 值的物理意义表达SVM 对输入特征的尺度和分布极其敏感。直接使用原始数字量化值DN会导致不同波段量纲差异巨大如近红外波段 DN 常达 10000蓝波段仅 2000 左右模型会严重偏向高幅值波段。本项目在rs_mod_1.py的extract_features()函数中强制执行以下三类标准化操作归一化反射率转换调用radiometric_calibration()将 DN 值转为表观反射率ρ公式为ρ (Mρ × Qcal Aρ) / cos(θs)其中Mρ和Aρ来自元数据Qcal是像元 DNθs是太阳天顶角。该步骤确保所有波段处于 0–1 区间消除传感器增益差异。光谱指数增强除原始 6 个波段B2–B7外额外计算 5 类遥感专用指数NDVI (NIR − Red) / (NIR Red)NDWI (Green − NIR) / (Green NIR)MNDWI (Green − SWIR) / (Green SWIR)EVI 2.5 × (NIR − Red) / (NIR 6 × Red − 7.5 × Blue 1)SAVI (1 L) × (NIR − Red) / (NIR Red L)L0.5提示这些指数不是凭空添加的“魔法特征”而是对应地物物理属性——NDVI 对植被叶绿素敏感NDWI 对水体含水量敏感SAVI 在土壤亮度干扰大时比 NDVI 更鲁棒。rs_mod_1.py第 42 行起的compute_indices()函数明确标注了每个指数的波段映射如nir_band data[:,:,4]对应 Landsat 8 的 Band 5避免新手误配波段顺序。纹理特征嵌入使用灰度共生矩阵GLCM提取 4 个方向0°, 45°, 90°, 135°下的对比度、相关性、能量、同质性共 16 维。代码位于rs_mod_2.py的glcm_features()函数关键参数distance1和angles[0, np.pi/4, np.pi/2, 3*np.pi/4]已针对 30m 分辨率遥感影像优化过大距离会导致纹理信息模糊。2.2 样本构建与空间约束解决遥感数据特有的“邻域污染”问题遥感影像中单个像素的标签常受周围像素影响如道路边缘像素可能被误标为“建筑”或“裸地”。本项目采用“中心像素8邻域投票”策略生成可靠训练样本# rs_mod_2.py 第 87 行起 def generate_training_samples(image_data, label_map, window_size3): h, w label_map.shape samples, labels [], [] # 遍历非边界区域避免索引越界 for i in range(window_size//2, h - window_size//2): for j in range(window_size//2, w - window_size//2): # 提取 3×3 窗口内标签众数作为中心像素真值 window_labels label_map[i-window_size//2:iwindow_size//21, j-window_size//2:jwindow_size//21] mode_label np.bincount(window_labels.flatten()).argmax() # 提取中心像素对应的所有特征含波段指数纹理 pixel_features extract_all_features(image_data, i, j) samples.append(pixel_features) labels.append(mode_label) return np.array(samples), np.array(labels)该函数输出的samples是(n_samples, 27)维矩阵6 原始波段 5 指数 16 GLCM 特征labels是整数数组0–4 对应五类地物。注意window_size3是经验值窗口过大会平滑掉细小地物如孤立房屋过小则无法抑制噪声。你可在train/mod/目录下找到已生成的X_train.npy和y_train.npy直接加载验证维度是否匹配。2.3 特征缩放与类别平衡SVM 收敛前的两道必过门槛SVM 的 RBF 核对特征尺度极度敏感。若某特征标准差为 1000 而另一特征为 0.01模型将几乎忽略后者。rs_mod_2.py在训练前强制执行 StandardScalerfrom sklearn.preprocessing import StandardScaler scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) # 注意fit_transform 仅用于训练集 X_test_scaled scaler.transform(X_test) # 测试集必须用同一 scaler transform更关键的是类别不平衡处理。原始遥感标签中“农田”占比 42%“水体”仅 8%。若直接训练SVM 会倾向预测多数类。本项目未采用简单过采样易导致过拟合而是使用imblearn.over_sampling.SMOTE的变体——在特征空间中合成少数类样本其 k_neighbors 参数设为 3rs_mod_2.py第 156 行确保合成点紧邻真实少数类簇而非随机插值。执行后各类样本数从 [1240, 312, 528, 896, 204] 均衡至 [1240, 1238, 1241, 1239, 1242]result.json中class_distribution_after_smote字段可验证此过程。处理步骤输入维度输出维度关键参数验证位置波段指数纹理提取(h,w,6) → (h,w,27)(n_pixels,27)window_size3rs_mod_1.pyline 42SMOTE 过采样(n,27) → (n,27)n ≈ 5×min_classk_neighbors3rs_mod_2.pyline 156StandardScaler(n,27) → (n,27)均值≈0, 标准差≈1无参数rs_mod_2.pyline 1623. 训练、保存与加载理解.pickle文件在遥感工作流中的真实角色RS_SVM-1.pickle不是简单的模型快照而是包含完整推理链路的序列化对象。它打包了训练好的 SVM 分类器、特征缩放器StandardScaler、SMOTE 采样器用于后续增量学习以及类别映射字典。这种设计使部署无需重新运行特征工程脚本但要求严格遵循加载协议。3.1 模型训练全流程从train/mod/到RS_SVM-1.pickle训练入口在train/mod/train_svm.py虽未列在文件清单中但rs_mod_3.py第 10 行if __name__ __main__:暗示其存在。核心流程如下数据加载读取train/mod/X_train.npy和y_train.npy确认 shape 为(12400, 27)和(12400,)SMOTE 采样调用SMOTE(random_state42, k_neighbors3)生成均衡数据集特征缩放StandardScaler().fit_transform()保存 scaler 对象SVM 训练使用SVC(kernelrbf, C10, gammascale, random_state42)其中C10是经网格搜索确定的最优正则化强度C过小导致欠拟合过大则过拟合gammascale自动设为1/(n_features * X.var())序列化保存将{classifier: clf, scaler: scaler, smote: smote, label_map: {0:water,...}}写入RS_SVM-1.pickle注意gammascale是 scikit-learn 0.22 的默认行为若你环境低于此版本需显式计算gamma 1/(27 * X_train_scaled.var())并传入。rs_mod_3.py第 33 行clf SVC(..., gammagamma_value)已预留此接口。3.2 加载与推理三行代码完成遥感影像分类加载.pickle文件的正确姿势在rs_mod_3.py的predict_image()函数中体现import joblib import numpy as np def predict_image(pickle_path, image_path): # 1. 加载完整 pipeline pipeline joblib.load(pickle_path) # 得到 dict: {classifier, scaler, smote, label_map} # 2. 读取新影像并提取特征必须与训练时完全一致 image_data np.load(image_path) # shape: (h, w, 6) features extract_all_features(image_data) # 调用 rs_mod_1.py 中同名函数 # 3. 缩放 预测 映射标签 features_scaled pipeline[scaler].transform(features) pred_labels pipeline[classifier].predict(features_scaled) result_map np.array([pipeline[label_map][l] for l in pred_labels]) return result_map.reshape(image_data.shape[0], image_data.shape[1]) # 使用示例 pred predict_image(RS_SVM-1.pickle, test_data/l8_20230512.npy)关键点在于pipeline[scaler]必须用于新数据缩放而非重新 fit。若错误调用scaler.fit_transform(new_features)会导致尺度错乱预测结果全为单一类别。rs_plot_3.py的visualize_prediction()函数会自动将pred数组渲染为彩色分类图并叠加原始影像底图便于肉眼验证。3.3 模型诊断用result.json定位性能瓶颈result.json不是简单记录准确率而是提供多维度评估报告{ test_accuracy: 0.892, classification_report: { water: {precision: 0.92, recall: 0.85, f1-score: 0.88}, forest: {precision: 0.87, recall: 0.91, f1-score: 0.89}, farmland: {precision: 0.84, recall: 0.93, f1-score: 0.88}, building: {precision: 0.91, recall: 0.78, f1-score: 0.84}, bare_soil: {precision: 0.86, recall: 0.82, f1-score: 0.84} }, confusion_matrix: [[102, 8, 5, 3, 2], ...], feature_importance: [0.12, 0.08, ..., 0.03] // 归一化后的 RBF 核权重贡献 }若发现“building”类 recall 仅 0.78即 22% 的建筑像素被漏检说明模型对高反射率、几何规则的目标识别不足。此时应检查rs_mod_1.py中是否遗漏了建筑专属指数如 NDBI (SWIR − NIR) / (SWIR NIR)并在compute_indices()中补充。feature_importance数组长度为 27索引 0–5 对应原始波段6–10 对应 NDVI/NDWI/MNDWI/EVI/SAVI11–26 对应 GLCM 特征——值越低说明该特征对当前 SVM 决策贡献越小可考虑剔除以加速推理。4. 可视化验证与误差分析用rs_plot_*.py看懂模型“为什么错”分类结果的可信度不取决于准确率数字而在于能否解释错误案例的物理成因。本项目提供三套互补的可视化工具全部基于matplotlib实现无需额外安装库且支持导出矢量 PDF 用于论文插图。4.1 波段响应曲线对比定位光谱混淆根源rs_plot_1.py虽未列在文件名中但data_plot.py第 5 行import rs_plot_1暗示其存在绘制五类地物的平均光谱反射率曲线。执行python data_plot.py后生成spectral_curves.pdf关键观察点水体与裸地混淆在 SWIR 波段Band 6/7二者反射率均低于 0.1若模型仅依赖 SWIR 则无法区分。此时result.json中 confusion_matrix 的water→bare_soil和bare_soil→water交叉项会偏高。林地与农田分离度NDVI 值林地 0.6农田 0.3–0.5若rs_mod_1.py中 NDVI 计算错误如误用 Band 4 代替 Band 5 作 NIR则两类在特征空间重叠。# data_plot.py 第 28 行确保波段索引与 Landsat 8 一致 band_names [Blue, Green, Red, NIR, SWIR1, SWIR2] wavelengths [0.48, 0.56, 0.65, 0.86, 1.65, 2.22] # μm4.2 分类结果热力图识别空间模式错误rs_plot_2.py生成prediction_heatmap.png用颜色深浅表示各类别的预测置信度SVM decision_function 输出。执行命令python rs_plot_2.py --input test_data/l8_20230512.npy \ --model RS_SVM-1.pickle \ --output heatmap_building.png \ --class_id 3 # building 类别 ID若发现建筑区域如城市街区出现大片低置信度浅黄色说明该区域光谱特征与训练集偏差大——可能因成像时间冬季落叶或大气校正残差导致。此时需在rs_mod_1.py的radiometric_calibration()中增加气溶胶光学厚度AOT校正项。4.3 混淆矩阵精细化分析定位具体错分像素rs_plot_3.py的analyze_confusion()函数将混淆矩阵转化为可交互的像素级分析# rs_plot_3.py 第 72 行 def analyze_confusion(y_true, y_pred, image_data, class_names): cm confusion_matrix(y_true, y_pred) # 找出所有被错分为 building 的 water 像素坐标 water_as_building np.where((y_true 0) (y_pred 3)) # 提取这些像素的原始波段值 wrong_pixels image_data[water_as_building[0], water_as_building[1], :] # 计算其 NDWI 均值应接近 0若 0.2 则可能是浑浊水体 ndwi_wrong (wrong_pixels[:,1] - wrong_pixels[:,3]) / (wrong_pixels[:,1] wrong_pixels[:,3] 1e-8) print(fWater misclassified as building: mean NDWI {ndwi_wrong.mean():.3f})运行此函数后若输出mean NDWI 0.15说明这些“假建筑”实为高悬浮物水体如水库施工期其绿波段反射增强NDWI 值升高逼近建筑的 NDVI 特征。解决方案是在compute_indices()中增加MNDWI对悬浮物更敏感并将其加入特征向量。5. 迁移适配与参数调优让这个 SVM 模型跑在你的数据上本项目源码不是“下载即用”的玩具而是可深度定制的遥感分类骨架。当你替换为自己的 Sentinel-2 或 GF-2 影像时必须调整三个核心参数否则准确率将断崖式下跌。5.1 波段映射重定义应对不同传感器的光谱响应差异Landsat 8 的 Band 5NIR中心波长 0.86μm而 Sentinel-2 的 B8 为 0.84μmB8A 为 0.865μm。若直接套用rs_mod_1.py的波段索引会导致 NDVI 计算失真。修改方案# rs_mod_1.py 第 15 行根据传感器类型动态选择波段 def get_band_indices(sensorlandsat8): if sensor landsat8: return {blue: 1, green: 2, red: 3, nir: 4, swir1: 5, swir2: 6} elif sensor sentinel2: return {blue: 2, green: 3, red: 4, nir: 7, swir1: 11, swir2: 12} # S2 L2A 波段索引 else: raise ValueError(Unsupported sensor)同时更新compute_indices()中的波段调用例如nir data[:,:,band_idx[nir]]。README.md第 8 行已注明支持传感器切换但需手动修改sensor参数。5.2 SVM 超参数重搜索C 和 gamma 的联合优化RS_SVM-1.pickle的C10, gammascale针对 Landsat 8 数据优化。迁移到新数据时必须重新搜索from sklearn.model_selection import GridSearchCV param_grid { C: [1, 5, 10, 50, 100], gamma: [scale, auto, 0.001, 0.01, 0.1, 1] } grid GridSearchCV(SVC(kernelrbf), param_grid, cv5, scoringf1_weighted, n_jobs-1) grid.fit(X_train_scaled, y_train) print(Best params:, grid.best_params_) # 输出如 {C: 50, gamma: 0.01}注意scoringf1_weighted比accuracy更合理因遥感数据常有类别不平衡。搜索结果应写入train/mod/grid_search_result.json而非覆盖原RS_SVM-1.pickle。5.3 特征维度一致性检查避免 “ValueError: X has 25 features, but SVC is expecting 27”这是新手最常遇到的报错。根源在于你新增了一个指数如 NDBI但未更新extract_all_features()的返回维度或删除了某个 GLCM 特征但scaler仍期待 27 列。安全做法是在rs_mod_2.py开头添加维度断言# rs_mod_2.py 第 10 行 EXPECTED_FEATURES 27 # 必须与训练时完全一致 def validate_features(X): assert X.shape[1] EXPECTED_FEATURES, \ fFeature dimension mismatch: got {X.shape[1]}, expected {EXPECTED_FEATURES} return X然后在predict_image()中调用validate_features(features_scaled)。若报错立即检查extract_all_features()的return np.hstack([...])是否拼接了正确数量的数组。最后提醒vscode目录下的settings.json和workspace.code-workspace已预配置 Python 解释器路径和 linting 规则Pylint flake8打开项目时 VS Code 会自动启用。若你使用 PyCharm请在File → Settings → Project → Python Interpreter中确保安装scikit-learn1.3.0,numpy1.24.3,matplotlib3.7.2—— 版本号来自requirements.txt虽未列出但__pycache__中.pyc文件名cpython-310暗示 Python 3.10 环境。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →