带有标签数据的 KMeans 聚类

Posted

技术标签:

【中文标题】带有标签数据的 KMeans 聚类【英文标题】:KMeans clustering with labels data 【发布时间】:2020-12-03 17:17:37 【问题描述】:

我有一个形状为 (587, 987, 3) 的 RGB 图像。 #height, width, num_channels

我还有 7 个类中的每一个的标签数据(像素的位置)。

我想应用 KMeans 聚类算法将给定的图像分割成 7 个类。 在应用 KMeans 聚类时,我想利用标签数据,即像素位置。

如何利用标签数据?

到目前为止我尝试过的如下。

img = np.random.randint(low=1,high=99, size=(587, 987, 3)) 

im = img.reshape(img.shape[0]*img.shape[1], img.shape[2])
im = StandardScaler().fit_transform(im)

clusters = KMeans(n_clusters=7,n_init= 100,max_iter=100,n_jobs=-1).fit(im)
kmeans_labels = clusters.labels_.reshape(img.shape[0], img.shape[1])

plt.imshow(kmeans_labels)
plt.show()
   

我正在寻找将一些注释传播到剩余片段(超像素)

【问题讨论】:

你要找的是一种半监督学习方法。在图像分割的上下文中,它们与交互式分割技术有关。如果您能提供有关您的问题以及您尝试过的方法的更多详细信息,那将是有益的,因为某些假设会提高您的算法的性能。 我已经更新了这个问题,以展示我到目前为止所做的尝试。我不知道如何在半监督学习的背景下使用标签。 好的,但你的最终目标是什么?您的问题只是为 k-means 集群分配标签吗?一种可能性是只为每个集群分配出现最多的标签,这不是最好的方法,因为它不是分类算法,但它回答了你的问题。但是,我认为您正在寻找将一些注释传播到图像中的其余部分(超像素?),如果是这种情况,您可以详细说明您的问题。 这可能是 XY 问题。 en.wikipedia.org/wiki/XY_problem “您将为...提供最少的代码”- 请注意,这种语言可能会被很多人所拒绝 【参考方案1】:

正如问题的 cmets 中所阐明的,您可以将集群视为超像素,并使用一些半监督分类器 [1] 将标签从几个样本传播到剩余数据。

创建图像以运行示例:

import numpy as np
from skimage.data import binary_blobs
import cv2 
from pyift.shortestpath import seed_competition
from scipy import sparse, spatial
import matplotlib.pyplot as plt 

# creating noisy image
size = 256 
image = np.empty((size, size, 3)) 
image[:, :, 0] = binary_blobs(size, seed=0)
image[:, :, 1] = binary_blobs(size, seed=0)
image[:, :, 2] = binary_blobs(size, seed=1)
image += np.random.randn(*image.shape) / 10
image -= image.min()
image /= image.max()

plt.axis(False)
plt.imshow(image)
plt.show()

计算超像素:

def grid_seeds(image, rows = 15, cols = 15):
    seeds = np.zeros(image.shape[:2], dtype=np.int)
    v_step, h_step = image.shape[0] // rows, image.shape[1] // cols
    count = 1
    for i in range(rows):
        y = v_step // 2 + i * v_step
        for j in range(cols):
            x = h_step // 2 + j * h_step
            seeds[y, x] = count
            count += 1
    return seeds
                                                                                                 
seeds = grid_seeds(image)
_, _, _, superpixels = seed_competition(seeds, image=image)
superpixels -= 1  # shifting labels to zero

contours, _ = cv2.findContours(superpixels, cv2.RETR_FLOODFILL, cv2.CHAIN_APPROX_SIMPLE)
im_w_contours = image.copy()
cv2.drawContours(im_w_contours, contours, -1, (255, 0, 0))

plt.axis(False)
plt.imshow(im_w_contours)
plt.show()

从 4 个任意节点传播标签,每个类(颜色)一个,并用预期颜色为结果标签着色。

def create_graph(image, labels):
    n_nodes = labels.max() + 1
    h, w, d = image.shape
    avg = np.zeros((n_nodes, d))
    for i in range(h):
        for j in range(w):
            avg[labels[i, j]] += image[i, j]
    avg[:] /= np.bincount(labels.flat)[:, np.newaxis]  # ignore label 0
    graph = spatial.distance_matrix(avg, avg)
    return sparse.csr_matrix(graph)

graph = create_graph(image, superpixels)

graph_seeds = np.zeros(graph.shape[0], dtype=np.int)
graph_seeds[1] = 1   # blue training sample
graph_seeds[3] = 2   # yellow training sample
graph_seeds[13] = 3  # white training sample
graph_seeds[14] = 4  # black training sample

label_colors = 1: (0, 0, 255),
                2: (255, 255, 0),
                3: (255, 255, 255),
                4: (0, 0, 0)

_, _, _, labels = seed_competition(graph_seeds, graph=graph)

result = np.empty_like(image)
for i, lb in enumerate(labels):
    result[superpixels == i] = label_colors[lb]

plt.axis(False)
plt.imshow(result)
plt.show()

对于这个例子,我使用每个超像素的平均颜色之间的差异作为它们的弧权重。但是,在实际问题中,需要一些更精细的特征向量。

此外,标记数据是图像超像素的子集,但这并不是绝对必要的,您可以在对图形进行建模时添加任何人工节点,尤其是作为种子节点。

此方法常用于遥感,本文可能相关[2]。

[1] Amorim, W. P., Falcão, A. X., Papa, J. P. 和 Carvalho, M. H. (2016)。通过最佳连接改进半监督学习。模式识别,60、72-85。

[2] 巴尔加斯、约翰 E. 等人。 “基于超像素的超高分辨率图像交互式分类。” 2014 第 27 届 SIBGRAPI 图形、模式和图像会议。 IEEE,2014 年。

【讨论】:

以上是关于带有标签数据的 KMeans 聚类的主要内容,如果未能解决你的问题,请参考以下文章

机器学习-kmeans/kmedoids/spectralcluster聚类算法

如何使用 KMeans 进行距离聚类

聊聊经典机器学习聚类算法Kmeans

R语言KMeans聚类模型示例

利用Kmeans聚类分析两类问题

Kmeans聚类算法及其 Python实现