news 2026/9/10 11:25:57

遥感图像分类实战:kNN、SVM、CNN与LSTM四模型对比

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
遥感图像分类实战:kNN、SVM、CNN与LSTM四模型对比

简介:面向遥感图像识别任务的综合算法项目,覆盖kNN、SVM、CNN、LSTM四种经典机器学习与深度学习模型,适合计算机相关专业学生开展课设、毕设或算法对比实验。压缩包共33个文件,以Python脚本(6个py)、Jupyter Notebook(4个ipynb)、Markdown文档和说明文档(5个md与1个txt)为主,另含训练过程图表(png/jpg)与辅助C++代码(2个cpp),整体体积仅1.17MB。项目按0_kNN、1_SVM、2_CNN、3_LSTM等模块清晰组织,代码与文档均已通过测试,可直接运行实现图像分类、特征提取与模型效果对比,能够直观呈现各算法在遥感场景下的识别精度差异;丰富的可视化结果和详细说明也便于快速定位、复现和二次开发。当前已有56人学习下载,适合希望系统掌握机器学习建模流程、快速搭建实验环境的学习者。

1. 遥感图像分类为什么需要同时跑通 kNN、SVM、CNN 与 LSTM

遥感影像的地物判读,和普通 ImageNet 分类最大的区别在于:样本少、尺度跨度大、类间纹理相似。真到了答辩或者项目验收环节,评审几乎都会追问一句“你凭什么选这个模型”。最稳的回答方式,不是背概念,而是把 kNN、SVM、CNN、LSTM 四条路线全部跑一遍,用同一批数据、同一套评价口径给出对比结论。这个基于机器学习的遥感图像识别项目,就是用足球场 footballField_13.jpg、桥梁 bridge_17.jpg 这类人工地物影像作为输入,按 0_kNN、1_SVM、2_CNN、3_LSTM 四个模块组织代码,覆盖从传统特征分类到深度特征提取的完整链路。它不一定把准确率做到 99%,但能把每种模型的适用边界、调参敏感点和训练成本摊开给你看。适合做毕业设计、课程设计的学生,也适合想快速建立图像分类基线对比的工程师。

2. 数据预处理与标签工程:从 footballField_13.jpg 到可训练的特征集

2.1 目录约定决定后续实验的复用成本

解压资源后,第一眼看到的是code/data_preprocessing0_kNN1_SVM2_CNN3_LSTM这种按算法拆分的一级结构,这个约定对实验管理非常关键。常见做法是每个模型目录里放独立训练脚本,而data_preprocessing只负责把原始 jpg 转成统一的 NumPy 数组,避免模型脚本里到处出现硬编码路径。

读取图像的第一步是统一尺寸。原始数据里footballField_13.jpgbridge_17.jpg分辨率不一致,直接进入模型会导致特征维度无法对齐。一般会把图像缩放到 64×64 或 128×128,再以 RGB 三通道存储。需要注意的是 OpenCV 默认读入的是 BGR 格式,用来做特征提取问题不大,但送进 PyTorch 或 TensorFlow 之前要转回 RGB,否则颜色特征会整体偏移。

import cv2 import numpy as np import os def load_images(base_dir, image_size=(64, 64)): images = [] names = [] for root, _, files in os.walk(base_dir): for f in files: if not f.lower().endswith(".jpg"): continue path = os.path.join(root, f) img = cv2.imread(path) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = cv2.resize(img, image_size) images.append(img) names.append(f) return np.array(images), names X, fnames = load_images("dataset") print(X.shape, fnames[:3])

逻辑说明:cv2.imread读入的 numpy 数组形状是(H, W, 3),但通道序为 BGR;cvtColor转成 RGB 后再resize,保证所有样本形状一致。返回的X形状为(样本数, 64, 64, 3),这是后面 CNN 和 LSTM 都承认的标准输入格式。参数说明:image_size控制下采样分辨率;64×64 在传统特征阶段能够明显降低计算量,而在 CNN 阶段也保留足够的局部纹理信息;如果遥感影像中目标只占几十个像素,建议上调到 128。

2.2 传统模型的特征工程分岔点

kNN 和 SVM 不能直接吃三维像素矩阵,必须降维或提取统计特征。常见选择有三种:颜色直方图、方向梯度直方图 HOG、灰度共生矩阵 GLCM。颜色直方图对光照变化敏感度低,适合区分绿色的足球场和灰白色的桥梁;HOG 对边缘轮廓敏感,但对颜色信息完全丢弃;GLCM 提取对比度、能量、熵等纹理参数,适合区分大片均质区域。

三种特征在遥感小样本场景下的表现差异可以简单用表格对比:

特征类型维度判别重心小样本稳定性提取成本
RGB 直方图32×3颜色统计一般极低
HOG1764边缘梯度较好
GLCM 纹理24灰度共生关系较好

从项目自带截图knn1.pngsvm1.png看,SVM 在直方图特征上已经能拿到不错的精度,说明在这个场景里颜色分布是强判别信息。常见做法是把三类特征横向拼接,再用StandardScaler标准化,因为 kNN 的距离计算和 SVM 的核函数都依赖特征尺度。

from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split X_flat = X.reshape(X.shape[0], -1) X_train, X_test, y_train, y_test = train_test_split( X_flat, y, test_size=0.3, stratify=y, random_state=42 ) scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_test = scaler.transform(X_test)

逻辑说明:把 64×64×3 的图像直接拉平为 12288 维向量,交给 kNN 和 SVM,这是最简单但也能跑通的基线。stratifity=y保证训练集和测试集中足球场、桥梁类别比例一致,避免某类样本全落到测试集导致指标失真。参数说明:test_size=0.3适合几十到几百张量级的小数据集;random_state固定后多次运行结果可复现,这是答辩展示时非常重要的点。

2.3 数据增强与标签编码

CNN 和 LSTM 对样本数量更敏感,原始遥感图如果只有每类几十张,支撑不了深层网络。建议在预处理阶段做离线增强:水平翻转、垂直翻转、小角度旋转、裁剪缩放。翻转不会改变“足球场还是桥梁”的语义标签,成本也低。标签编码上,keras 的sparse_categorical_crossentropy可以直接接收整数标签,不需要 one-hot 编码;而传统 sklearn 分类器也天然支持整数标签。所以预处理阶段只做LabelEncoder的序号映射即可。

3. kNN 与 SVM 基线:scikit-learn 实现与超参数边界

3.1 kNN 的惰性学习陷阱

kNN 在遥感图像分类里通常作为“下限基线”,因为它没有显式训练过程,预测时要计算测试样本与全部训练样本的距离。项目里0_kNN模块放到最前面,意图就是先拿到一个朴素准确率,比如 0.82,后面 SVM、CNN 再和它比较,证明“模型复杂度提升带来收益”。但 kNN 的k值非常敏感:k=1 时决策边界完全跟随训练点,有噪声时直接过拟合;k 取样本数的平方根附近时较稳定,但类间距离太近时精度会显著下降。

from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score param_grid = {"n_neighbors": [3, 5, 7, 9], "weights": ["uniform", "distance"]} for k in param_grid["n_neighbors"]: for w in param_grid["weights"]: knn = KNeighborsClassifier(n_neighbors=k, weights=w, p=2, n_jobs=-1) knn.fit(X_train, y_train) y_pred = knn.predict(X_test) print(f"k={k}, weights={w}, acc={accuracy_score(y_test, y_pred):.4f}")

逻辑说明:p=2表示使用欧氏距离,weights='distance'会让邻近样本按距离倒数加权投票,能缓解 k 偏大时的边界模糊问题。参数说明:n_jobs=-1使用全部 CPU 核心,因为 kNN 的预测阶段是一个计算密集型操作。遥感图像拉平后的特征维度很高,欧氏距离会趋于均匀化,这就是为什么特征标准化比原始像素值更关键。

3.2 SVM 核函数与 C、gamma 的配合

SVM 模块是本项目最容易被问到的部分。遥感图像样本量小但维度高,这只对线性 SVM 有利,而实际里数据往往线性不可分。项目中1_SVM直接上 RBF 核,这一步思路是对的。RBF 核需要关注两个参数:C控制误分类惩罚,gamma控制单个样本的影响半径。gamma过大时每个样本都变成一个小山包,边界极不规则,过拟合;过小则所有样本的影响糊成一片,欠拟合。

from sklearn.svm import SVC svm = SVC(kernel="rbf", C=10.0, gamma="scale", class_weight="balanced", probability=True) svm.fit(X_train, y_train) train_acc = svm.score(X_train, y_train) test_acc = svm.score(X_test, y_test) print(f"SVM train acc: {train_acc:.4f}, test acc: {test_acc:.4f}")

逻辑说明:gamma='scale'表示自动取1 / (特征维度 × X.var()),这是 sklearn 在不知道数据分布时相对安全的起点,避免手动调出一个灾难级数值。class_weight='balanced'在遥感地物类别不平衡时非常有用,比如桥梁样本只有足球场的一半,它会给少数类更高惩罚权重。参数说明:probability=True开启 Platt 缩放,允许输出类别概率,但这会增加训练耗时,如果只用predict打分可以关掉;在最后一章做置信度筛选时会用到这里。

以我自己的经验,SVM 在颜色直方图和原始像素拉平特征上表现差异不大,但在 GLCM 特征上优势明显,因为它对特征尺度更敏感。一个可复现的基准做法是:先跑默认参数,记录结果,再在C ∈ [0.1, 1, 10, 100]gamma ∈ ['scale', 0.01, 0.001]上做网格搜索。

3.3 用 classification_report 评估每个类别的精确率与召回率

验收项目时,准确率不是唯一指标,尤其是遥感图像里“桥梁”和“足球场”可能存在易混淆子区域。需要输出精确率、召回率和 F1,简单做法是:

from sklearn.metrics import classification_report print(classification_report(y_test, svm.predict(X_test), target_names=["footballField", "bridge"], digits=4))

classification_report的每个类别行里,precision反映误检多少,recall反映漏检多少。如果 footballField 的 precision 是 0.85、recall 是 0.70,说明有大量足球场被判成桥梁但桥梁很少被判成足球场,这类细节在答辩时能展示你真正排查过问题。

4. CNN 遥感识别:从图像输入到卷积核的参数图景

4.1 网络结构怎么选才不算过度设计

遥感小数据集的 CNN 结构有个原则:优先小卷积核浅网络,不要上来就套 ResNet。一个 64×64 的输入,用三层卷积就能覆盖足够感受野。项目里2_CNN模块的模型截图显示训练过程正常收敛,说明结构设计是匹配数据量的。常见的做法是卷积核数量按 16 → 32 → 64 翻倍,每层后接 MaxPooling 缩小空间尺寸,最后用全局平均池化或 Flatten 接全连接分类层。

from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, BatchNormalization def build_cnn(num_classes=2): model = Sequential([ Conv2D(16, (3, 3), activation="relu", padding="same", input_shape=(64, 64, 3)), MaxPooling2D((2, 2)), Conv2D(32, (3, 3), activation="relu", padding="same"), MaxPooling2D((2, 2)), Conv2D(64, (3, 3), activation="relu", padding="same"), MaxPooling2D((2, 2)), Flatten(), Dense(64, activation="relu"), Dropout(0.5), Dense(num_classes, activation="softmax") ]) return model

逻辑说明:padding="same"保证卷积后特征图尺寸与输入一致,保留边缘信息,这在遥感地物边界识别里比valid更能稳住边界连续性。MaxPooling2D(pool_size=(2,2))将每个 2×2 区域取最大值,同时完成空间降维和微小偏移容忍。参数说明:第一个 Conv2D 的16表示学习 16 种基础边缘/纹理滤波器;最后一个 Dense 的num_classes对应类别数;Dropout(0.5)在训练时随机丢弃一半神经元,是防止全连接层过拟合的最有效手段。

4.2 训练配置与早停策略

CNN 训练最怕的不是收敛慢,而是资源里本来就没有预留验证集。推荐直接用validation_split=0.2从训练集里割 20% 做验证,同时开启 EarlyStopping。遥感样本少时,训练轮次太多必然过拟合,验证集损失会在某个 epoch 后掉头向上,EarlyStopping 能在拐点出现后及时回滚权重。

from tensorflow.keras.callbacks import EarlyStopping model = build_cnn(num_classes=2) model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"]) callbacks = [EarlyStopping(monitor="val_loss", patience=8, restore_best_weights=True)] history = model.fit( X_train, y_train, batch_size=16, epochs=80, validation_split=0.2, callbacks=callbacks, verbose=1 )

逻辑说明:restore_best_weights=True会在早停时恢复验证损失最小的那组权重,而不是停在最后一个 epoch,这对答辩时展示模型泛化性能非常关键。batch_size=16在几十到几百张图像的数据集里是比较合理的起点,过大会导致梯度更新次数不足,过小则训练震荡。参数说明:patience=8表示连续 8 轮验证损失不下降就停止,给模型足够时间跨过局部平台。如果训练到第 10 轮验证损失仍不下降,应优先考虑加大数据增强而不是加深网络。

4.3 从损失曲线判断欠拟合还是过拟合

训练完成后建议绘制两条曲线:训练 loss 和验证 loss。如果训练 loss 持续下降、验证 loss 在第 12 轮回升,说明模型开始记住训练集的噪声。如果两条曲线都高位平滑,就是模型容量不够。项目附带的cnn1.png ~ cnn5.png显示了这种过程,属于典型的小数据集曲线形态。处理过拟合优先加 Dropout 和数据扩充,处理欠拟合则增加卷积核数量或卷积层深度。

5. LSTM 序列化建模:把遥感像素序列转化为时序特征

5.1 遥感图像用 LSTM 的合理性在哪

LSTM 本来为序列建模设计,直接拿二维图像输入并不自然。但遥感图像有一个隐藏特性:地物在空间上有方向连续性和结构重复性。比如足球场的草地纹理沿扫描行方向会呈现近似周期性的像素波动,桥梁的直线边缘在逐行扫描时表现为突变的交界点。把图像按行拆成序列喂给 LSTM,相当于让网络学习“行与行之间的上下文依赖”,这在少样本场景下有时会获得与 CNN 互补的特征表达。

5.2 图像到序列的 reshape 细节

要喂给 LSTM,需要把(样本数, 64, 64, 3)变成(样本数, 时间步, 每步特征维度)。常见做法有两种:一种是按行扫描,64 行作为 64 个时间步,每步输入 64×3=192 维的 RGB 拼接向量;另一种是把整张图拉平成 4096 个像素点序列,每个时间步只输入一个像素。实验下来,按行扫描保留了更多空间局部性,前 64 个特征描述同一行的颜色信息,更利于 LSTM 捕获“下一行与上一行的关系”。

在利用 LSTM 建模之前,需要做维度转换:

X_seq_train = X_train.reshape(X_train.shape[0], 64, 64 * 3) X_seq_test = X_test.reshape(X_test.shape[0], 64, 64 * 3)

逻辑说明:reshape后得到的三维张量中,第二维64是时间步数,第三维192是每一时间步的特征向量。LSTM 内部会按时间步顺序逐一处理,并在每个时间步之间传递隐状态。参数说明:这里要求输入数据的内存布局严格是(batch, time_steps, features),任何一个维度顺序错了,LSTM 都会把同一行的不同列当作不同时间步,导致模型学到的规律完全颠倒。

5.3 LSTM 层配置与 Dropout 位置

from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout def build_lstm(num_classes=2): model = Sequential([ LSTM(64, input_shape=(64, 192), return_sequences=False), Dropout(0.3), Dense(32, activation="relu"), Dropout(0.3), Dense(num_classes, activation="softmax") ]) return model model = build_lstm() model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"]) model.summary()

逻辑说明:LSTM(64)表示隐单元数为 64,return_sequences=False丢弃所有时间步的中间输出,只保留最后一个时间步的隐状态作为整张图的编码向量,再接全连接层分类。如果设成 True,输出维度会变成(batch, 64, 64),不适合直接接 Dense。参数说明:第一个 Dropout(0.3) 作用在 LSTM 输出上,抑制时序特征中的共适应;第二个 Dropout 在全连接层之间,工程上 0.3 比 0.5 更适合小数据,保留更多信息。

LSTM 训练时要特别注意梯度不稳定问题,建议使用 clipnorm 或 clipvalue。遥感图像序列长度只有 64,梯度爆炸概率不如长序列高,但加一个约束没有成本:

from tensorflow.keras.optimizers import Adam opt = Adam(learning_rate=0.001, clipnorm=1.0) model.compile(optimizer=opt, loss="sparse_categorical_crossentropy", metrics=["accuracy"])

clipnorm=1.0将梯度向量的 L2 范数限制为 1,防止某些离群样本产生巨大梯度把权重冲垮。learning_rate=0.001是 Adam 的保守默认值。

5.4 LSTM 结果出现什么信号时该放弃

如果 LSTM 验证精度明显低于 CNN,而且训练 loss 下降极慢,问题大概率出在特征表示上:纯 RGB 像素序列对 LSTM 来说过于底层,它需要大量数据才能抽象出纹理规律。这时可以把输入从原始像素改成 CNN 倒数第二层的特征图,再接一层 LSTM,构建 CNN-LSTM 串联结构。项目中3_LSTM放在 CNN 后面,也隐含了这个思路:先让 CNN 提取空间特征,再让 LSTM 建模特征间的依赖关系,而不是让 LSTM 裸着处理像素。

6. 结果对比与模型挑选:从训练曲线到阈值设定

6.1 四模型横向评审表

项目答辩时,会把四个模型的实验数据汇总成一张参数与指标对照表,最核心的是这四列:

模型输入特征关键参数测试准确率量级训练耗时
kNN像素拉平+标准化k=5,欧氏距离0.78~0.85秒级
SVM直方图/HOGRBF,C=100.85~0.92秒级
CNN64×64×3 图像3层卷积+Dropout0.90~0.96分钟级
LSTM64×192 序列64 隐单元0.82~0.90分钟级

这个表不是固定结论,但它能直观说明一个趋势:CNN 在该数据集上通常拿最高分,SVM 以极低的训练成本紧随其后,kNN 和 LSTM 分别受维度灾难和序列归纳偏置限制,稳定排在后面。展示时把训练耗时和调参难度写进去,比只说准确率更有说服力。

6.2 用混淆矩阵定位真实错误来源

准确率之外,最值得画的一张图是混淆矩阵。在二分类下,它能直接看出模型把哪一类错判为另一类。建议在所有模型上统一输出,对比哪两个类别最容易混淆。

import numpy as np import matplotlib.pyplot as plt from sklearn.metrics import confusion_matrix def plot_cm(model, X, y_true, title): y_pred = model.predict(X) cm = confusion_matrix(y_true, y_pred) fig, ax = plt.subplots(figsize=(4, 4)) im = ax.imshow(cm, cmap="Blues") for i in range(cm.shape[0]): for j in range(cm.shape[1]): ax.text(j, i, str(cm[i, j]), ha="center", va="center") ax.set_xticks([0, 1]) ax.set_yticks([0, 1]) ax.set_xticklabels(["footballField", "bridge"]) ax.set_yticklabels(["footballField", "bridge"]) ax.set_title(title) plt.show()

逻辑说明:confusion_matrix返回的矩阵第 i 行是真实类别,第 j 列是预测类别,对角线上的数字是正确判定的样本数。如果 bridge 那一行里有几个样本落到 footballField 列,说明桥梁图像中混入了和足球场纹理相似的植被区域。参数说明:cmap="Blues"只用于可视化,不影响数值;annot在 seaborn 里更简洁,但这里用 matplotlib 原生的方式避免额外依赖。

6.3 利用 softmax 概率设定“拒绝判定”阈值

遥感图像里总有训练阶段没见过的地物,比如停车场、裸地。强行让模型输出“足球场”或“桥梁”会造成不可控误报。更稳妥的做法是给 softmax 概率加一个最小置信度阈值,低于阈值直接标记为“unknown”。这正是提前设置svm probability=True和 CNN 默认 softmax 输出的原因。

def predict_with_threshold(model, image, threshold=0.7): prob = model.predict(image)[0] idx = np.argmax(prob) if prob[idx] < threshold: return "unknown", prob return idx, prob score = model.predict(X_test[:1]) print(predict_with_threshold(model, X_test[:1], threshold=0.7))

逻辑说明:np.argmax(prob)取出概率最大的类别下标,如果最大概率都不超过threshold,说明模型内部对不同类别的证据都不足,输出 unknown 比强行分类更合理。参数说明:threshold=0.7是一个经验值;实际使用时,可以先跑一遍验证集,统计所有正确样本的 softmax 概率分布,再选取 5% 分位数作为阈值,这样可以避免阈值定得过高导致大量样本被拒判。这个方法同样适用于 kNN 的距离分数或 SVM 的 decision function 输出,思路是通用的。最终交付时,将predict_with_threshold封装成独立推理脚本,并用joblibmodel.save()导出最优模型权重,这样评审现场可以随机挑一张遥感图验证 known 和 unknown 两档输出,整个项目从训练到部署的链路才算真正闭环。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 11:23:54

如何把 BMAD-METHOD 从 v4 升级到 v6:清理旧目录并迁移规划产物

如何把 BMAD-METHOD 从 v4 升级到 v6&#xff1a;清理旧目录并迁移规划产物 【免费下载链接】BMAD-METHOD Breakthrough Method for Agile Ai Driven Development 项目地址: https://gitcode.com/gh_mirrors/bm/BMAD-METHOD 如果你的项目里还装着 BMad v4&#xff08;安…

作者头像 李华
网站建设 2026/9/10 11:22:58

论文免费大纲怎么用?工具按环节配齐

写论文最怕的不是文笔&#xff0c;而是写了一半发现结构立不住、推倒重来。不少同学接受了"先有大纲、再写正文"的做法&#xff0c;也用过免费大纲&#xff0c;但拿到一份大纲之后下一步该做什么、它在选题到成文的各个阶段怎么配合&#xff0c;多数人其实没理顺。这…

作者头像 李华
网站建设 2026/9/10 11:19:39

华为CANN/GE图引擎Tensor属性设置

EsSetInt64AttrForTensor 【免费下载链接】ge GE&#xff08;Graph Engine&#xff09;是面向昇腾的图编译器和执行器&#xff0c;提供了计算图优化、多流并行、内存复用和模型下沉等技术手段&#xff0c;加速模型执行效率&#xff0c;减少模型内存占用。 GE 提供对 PyTorch、T…

作者头像 李华
网站建设 2026/9/10 11:19:23

木材表面缺陷检测:YOLOv5数据集标注、训练调参与部署完整指南

简介&#xff1a;这份木材表面缺陷检测数据集面向计算机视觉研究与工业质检开发者&#xff0c;可用于训练木材表面裂纹、节疤、腐朽等缺陷识别模型。压缩包共1897个文件&#xff0c;主要包含948张jpg原始木材图像与948个txt YOLO格式标注文件&#xff0c;另附1个yaml类别配置文…

作者头像 李华