OpenCV中的K-均值聚类

目标

  • 学习使用 OpenCV 中的 cv.kmeans() 函数进行数据聚类

了解参数

输入参数

  1. samples : 应为 np.float32 数据类型,每个特征应放在一列中。
  2. nclusters(K) : 最后所需的簇数
  3. criteria : 这是迭代终止标准。当满足该标准时,算法迭代停止。实际上,它应该是由 3 个参数组成的元组。它们是 ( type, max_iter, epsilon )
    终止条件的类型。
    a. 它有 3 个标志,如下所示:
    cv.TERM_CRITERIA_EPS - 如果达到指定精度 epsilon,则停止算法迭代。
    cv.TERM_CRITERIA_MAX_ITER - 在达到指定的迭代次数(max_iter)后停止算法迭代。
    cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER - 满足上述任何条件时停止迭代。
    b. max_iter - 指定最大迭代次数的整数。
    c. epsilon - 要求的精度
  4. attempts : 用于指定使用不同初始标签执行算法的次数。算法会返回产生最佳紧凑性的标签。该紧凑性将作为输出返回。
  5. 标志(flags): 该标志用于指定初始中心的取值方式。通常使用两个标志:cv.KMEANS_PP_CENTERScv.KMEANS_RANDOM_CENTERS

输出参数

  1. 紧凑性(compactness):这是每个点到相应中心的距离平方和。
  2. labels:这是标签数组(与前一篇文章中的 "代码 "相同),其中每个元素都标有 “0”、“1”…
  3. centers : 这是聚类中心数组。
    现在,我们将通过三个例子来了解如何应用 K-Means 算法。

1. 只有一个特征的数据

假设你有一组只有一个特征的数据,即一维数据。例如,我们可以以 T 恤问题为例,只用人们的身高来决定 T 恤的尺寸。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
x = np.random.randint(25,100,25)
y = np.random.randint(175,255,25)
z = np.hstack((x,y))
z = z.reshape((50,1))
z = np.float32(z)
plt.hist(z,256,[0,256]),plt.show()

因此,我们有一个大小为 50 的数组 “z”,其值范围为 0 至 255。我将 "z "重塑为列向量。当出现多个特征时,它将更加有用。然后,我创建了 np.float32 类型的数据。

我们得到如下图像

在这里插入图片描述
现在我们应用 KMeans 函数。在此之前,我们需要指定标准。我的标准是,每当算法迭代 10 次,或精度达到ε = 1.0 时,停止算法并返回答案。

# 定义 criteria = ( type, max_iter = 10 , epsilon = 1.0 )
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0)
# 设置标志(只是为了避免代码断行)
flags = cv.KMEANS_RANDOM_CENTERS
# 应用 KMeans
compactness,labels,centers = cv.kmeans(z,2,None,criteria,10,flags)

这样就得到了紧凑度、标签和中心点。在本例中,我得到的中心点分别为 60 和 207。标签的大小与测试数据的大小相同,每个数据将根据其中心点被标记为 “0”、“1”、"2 "等。现在,我们根据标签将数据分成不同的簇。

A = z[labels==0]
B = z[labels==1]

现在我们用红色绘制 A,用蓝色绘制 B,用黄色绘制它们的中心点。

# 现在用红色绘制 "A",蓝色绘制 "B",黄色绘制 "中心"。
plt.hist(A,256,[0,256],color = 'r')
plt.hist(B,256,[0,256],color = 'b')
plt.hist(centers,32,[0,256],color = 'y')
plt.show()

下面是我们得到的输出结果:
在这里插入图片描述

2. 具有多种特征的数据

在前面的例子中,我们只使用了身高来解决 T 恤问题。在这里,我们将同时使用身高和体重,即两个特征。

请记住,在之前的例子中,我们将数据转化为单列向量。每个特征排列在一列中,而每一行对应一个输入测试样本。

例如,在本例中,我们设置了大小为 50x2 的测试数据,即 50 个人的身高和体重。第一列对应所有 50 人的身高,第二列对应他们的体重。第一行包含两个元素,第一个是第一个人的身高,第二个是他的体重。同样,其余各行对应的是其他人的身高和体重。查看下图:
在这里插入图片描述
现在,我直接转到代码:

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
X = np.random.randint(25,50,(25,2))
Y = np.random.randint(60,85,(25,2))
Z = np.vstack((X,Y))
# 转换为 np.float32
Z = np.float32(Z)
# 定义标准并应用 kmeans()
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0)
ret,label,center=cv.kmeans(Z,2,None,criteria,10,cv.KMEANS_RANDOM_CENTERS)
# 现在分离数据,注意 flatten()
A = Z[label.ravel()==0]
B = Z[label.ravel()==1]
# 绘制数据
plt.scatter(A[:,0],A[:,1])
plt.scatter(B[:,0],B[:,1],c = 'r')
plt.scatter(center[:,0],center[:,1],s = 80,c = 'y', marker = 's')
plt.xlabel('Height'),plt.ylabel('Weight')
plt.show()

下面是我们得到的输出结果:
在这里插入图片描述

3. 色彩量化

色彩量化是减少图像中色彩数量的过程。这样做的原因之一是为了减少内存。有时,某些设备可能会受到限制,只能生成有限的颜色。在这种情况下,也要进行颜色量化。在这里,我们使用 k-means 聚类来进行颜色量化。

这里没有什么新东西需要解释。有 3 个特征,例如 R、G、B。因此,我们需要将图像重塑为 Mx3 大小的数组(M 为图像中的像素数)。聚类后,我们对所有像素应用中心点值(也是 R、G、B),这样得到的图像将具有指定数量的颜色。我们还需要将其重塑为原始图像的形状。代码如下:

import numpy as np
import cv2 as cv
img = cv.imread('home.jpg')
Z = img.reshape((-1,3))
# 转换为 np.float32
Z = np.float32(Z)
# 定义标准、簇数(K)并应用 kmeans()
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 8
ret,label,center=cv.kmeans(Z,K,None,criteria,10,cv.KMEANS_RANDOM_CENTERS)
# 现在转换回 uint8,并生成原始图像
center = np.uint8(center)
res = center[label.flatten()] 
res2 = res.reshape((img.shape))
cv.imshow('res2',res2)
cv.waitKey(0)
cv.destroyAllWindows()

请看下面 K=8 的结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值