如何使用Python在卫星图像上训练SVM分类器

5
我正在使用 scikit-learn 库对卫星图像执行监督分类(支持向量机分类器)。我的主要问题是如何训练我的 SVM 分类器。我在 YouTube 上观看了许多视频,并阅读了一些关于如何在 scikit-learn 中训练 SVM 模型的教程。我所看到的所有教程都是使用著名的 Iris 数据集。为了在 scikit-learn 中执行监督式 SVM 分类,我们需要有标签。对于 Iris 数据集,我们有 Iris.target,它是我们试图预测的标签(“setosa”,“versicolor”,“virginica”)。通过阅读 scikit-learn 的文档,训练过程很简单。
在我的情况下,我必须训练一个在城区拍摄的 SAR 卫星图像,并且我需要对城市区域、道路、河流和植被(4 个类)进行分类。这张图片有两个波段,但我没有每个类别的标签数据,就像 Iris 数据一样。
那么,我的问题是,我是否必须手动创建矢量数据(用于 4 类)以便训练 SVM 模型?有没有比手动创建矢量数据更容易的训练模型的方法?在这种情况下,我们该怎么做?
说实话,我有点困惑。我会感激任何帮助。

1
我不确定我理解你的问题。如果您没有标记数据,就不能使用监督学习技术...但也许我对卫星图像数据的某些方面存在误解... - juanpa.arrivillaga
嗨juanpa.arrivillaga,感谢您的回答。所以,我想我必须手动创建卫星图像的训练数据。训练过程让我有点困扰。 - Johny
1
一个可能的方法是使用openstreetmaps.org生成测试数据来训练您的模型,因为您很可能拥有图像的坐标。困难在于将OSM数据解析成您需要的类别,但格式已经得到了很好的记录,并且有库可以帮助您。 - Yacine Filali
谢谢你的回答。 - Johny
2个回答

19
这是一个完整的示例,可以帮助您正确地进行操作。为了简单起见,假设您的目标是将下面这个三色波段图像中的像素分类为三种不同的类别,即建筑物、植被和水域。这些类别将分别显示为红色、绿色和蓝色。

New York

我们首先读取图像并定义一些稍后将使用的变量。

import numpy as np
from skimage import io

img = io.imread('https://istack.dev59.com/TFOv7.webp')

rows, cols, bands = img.shape
classes = {'building': 0, 'vegetation': 1, 'water': 2}
n_classes = len(classes)
palette = np.uint8([[255, 0, 0], [0, 255, 0], [0, 0, 255]])

无监督分类

如果您不希望手动标记一些像素,则需要检测数据的基本结构,即您需要将图像像素分成n_classes个分区,例如通过k-means聚类

from sklearn.cluster import KMeans

X = img.reshape(rows*cols, bands)
kmeans = KMeans(n_clusters=n_classes, random_state=3).fit(X)
unsupervised = kmeans.labels_.reshape(rows, cols)

io.imshow(palette[unsupervised])

监督分类

相反地,您可以为某些已知类别的像素分配标签(通常将标记化像素集称为“地面真实”)。在这个玩具示例中,地面真实由三个硬编码的20×20像素正方形区域组成,如下图所示:

ground truth

无监督分类

相比之下,无监督分类不需要预先标记数据,而是自动将像素分成不同的组或聚类。以下是一个简单的示例,展示了一张图像被分成了四个不同颜色的聚类:

unsupervised classification

supervised = n_classes*np.ones(shape=(rows, cols), dtype=np.int)

supervised[200:220, 150:170] = classes['building']
supervised[40:60, 40:60] = classes['vegetation']
supervised[100:120, 200:220] = classes['water']

使用地面真值(训练集)的像素来拟合支持向量机。

y = supervised.ravel()
train = np.flatnonzero(supervised < n_classes)
test = np.flatnonzero(supervised == n_classes)

from sklearn.svm import SVC

clf = SVC(gamma='auto')
clf.fit(X[train], y[train])
y[test] = clf.predict(X[test])
supervised = y.reshape(rows, cols)

io.imshow(palette[supervised])

在训练阶段之后,分类器会将类标签分配给其余像素(测试集)。分类结果如下所示:

监督分类

最后的评论

结果表明,无监督分类比监督分类更准确。然而,监督分类通常优于无监督分类。需要注意的是,在分析的例子中,通过调整SVM分类器的参数可以大大提高准确性。进一步的改进可以通过扩大和完善地面真实数据来实现,因为训练/测试比率非常小,而红色和绿色补丁实际上包含不同类别的像素。最后,可以合理地期望利用从强度级别计算出的比率或指数等更复杂的特征(例如NDVI)来提高性能。


2
这是一个非常完整和有趣的回答,解决了我的问题。你让我找到了正确的方向。谢谢你的回答,我很感激。 - Johny
非常直接和完整的示例,适用于在网络上迷失了成千上万个参考资料的新手。 - GCGM

1

我的解决方案:

手动处理:

如果您的数据集很小,您可以手动创建矢量数据(也可靠,当您自己创建时)。如果不是,将图像应用SVM进行分类会更加困难。

自动处理:

步骤1:

您可以使用“无监督图像聚类”技术将图像分成这4个类别,然后在聚类完成后标记这些图像为1到4。(例如K-Means聚类算法)

步骤2:

目前,您拥有一个标记图像的数据集。将它们分成训练-测试数据。

步骤3:

现在将SVM应用于对测试图像进行分类,并找出模型的准确性。


我不明白通过k-means聚类对像素进行分类,然后在标记的像素上应用SVM分类器的意义所在。结合监督和无监督学习可能有益处(有关详细信息,请参见此线程),但是 - 在我看来 - 您建议的“自动处理”方法没有意义。 - Tonechas
谢谢你指出这个问题。但我只是举了k-means作为一个例子。真正的情况是,我们可以使用任何更好的无监督学习算法来分组不同的图像,然后可以根据图像所聚类的组对它们进行标记。经过这个过程,每个单独的图像都有自己的类别标签,因此我们可以应用监督学习算法进行分类处理。如果您仍有任何疑问,请查看本回复旁边的帖子。 - Karthik Sekaran
如果您能够通过任何无监督学习算法正确标记像素,则不需要通过监督式学习重新分类像素。这样做,受监督分类的结果可能比其无监督对应物更不准确。顺便说一下,我是您提到的那篇文章的作者 :-) - Tonechas
哈哈..我从来没有看过作者的名字。你说的一切都是正确的,毫无疑问。但问题所问的方式是要“分类”图像。正如你所说,对于这种情况,无监督学习是完全适合的。我的意图不是为问题提供完美的解决方案,但如果可能的话,我会尽力而为。这就是为什么我给出了这样的答案。如果你觉得答案很差,你可以点击下投票按钮。 - Karthik Sekaran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接