10.6. OpenCV中的K-均值聚类

10.6.1. 目标

  • 学会使用 cv2.kmeans() OpenCV中的数据聚类功能

10.6.2. 了解参数

输入参数

  1. 样品 :应该是 np.float32 数据类型,每个特性都应该放在一个列中。

  2. N类(K) :结束时所需的群集数

  3. 标准 :这是迭代终止条件。当满足此条件时,算法迭代停止。实际上,它应该是由3个参数组成的元组。他们是 ( type, max_iter, epsilon )

    • 3.a-终止条件的类型:它有3个标志,如下所示:
      cv2.TERM_CRITERIA_EPS -如果指定精度,则停止算法迭代, ε ,已到达。 cv2.TERM_CRITERIA_MAX_ITER -在指定的迭代次数后停止算法, max_iter . cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER -满足上述任一条件时停止迭代。
    • 3.b-max_iter-指定最大迭代次数的整数。

    • 3.c-epsilon-所需精度

  4. 尝试 :标志,指定使用不同初始标记执行算法的次数。算法返回产生最佳紧性的标签。这种紧凑性作为输出返回。

  5. 旗帜 :此标志用于指定初始中心的获取方式。通常使用两个标志: cv2.KMEANS_PP_CENTERScv2.KMEANS_RANDOM_CENTERS .

输出参数

  1. 致密性 :这是从每个点到其对应中心的平方距离之和。

  2. 标签 :这是标签数组(与上一篇文章中的“code”相同),其中每个元素都标记为“0”、“1”…。。

  3. 中心 :这是群集中心的数组。

现在我们将通过三个例子来看看如何应用K-均值算法。

10.6.3. 一。只有一个特征的数据

考虑一下,你有一组只有一个特征的数据,即一维。例如,我们可以解决我们的t恤问题,你只需要用人的身高来决定t恤的尺寸。

所以我们首先创建数据并将其绘制在Matplotlib中

>>> %matplotlib inline
>>>
>>> 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()
../_images/sec06-kmeans-opencv_1_0.png
((array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 3., 1., 0., 1., 0.,
         1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.,
         1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 1., 0., 3., 0., 0.,
         0., 2., 0., 1., 1., 0., 0., 1., 0., 0., 0., 0., 0., 1., 1., 1., 0.,
         0., 1., 1., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 1., 0., 0., 1., 0., 0., 0., 0., 0., 0., 1.,
         0., 1., 1., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 1., 0., 0., 1.,
         0., 0., 0., 0., 0., 0., 1., 1., 1., 2., 0., 1., 1., 1., 1., 2., 0.,
         0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 1., 0.,
         0.]),
  array([  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,
          11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.,  20.,  21.,
          22.,  23.,  24.,  25.,  26.,  27.,  28.,  29.,  30.,  31.,  32.,
          33.,  34.,  35.,  36.,  37.,  38.,  39.,  40.,  41.,  42.,  43.,
          44.,  45.,  46.,  47.,  48.,  49.,  50.,  51.,  52.,  53.,  54.,
          55.,  56.,  57.,  58.,  59.,  60.,  61.,  62.,  63.,  64.,  65.,
          66.,  67.,  68.,  69.,  70.,  71.,  72.,  73.,  74.,  75.,  76.,
          77.,  78.,  79.,  80.,  81.,  82.,  83.,  84.,  85.,  86.,  87.,
          88.,  89.,  90.,  91.,  92.,  93.,  94.,  95.,  96.,  97.,  98.,
          99., 100., 101., 102., 103., 104., 105., 106., 107., 108., 109.,
         110., 111., 112., 113., 114., 115., 116., 117., 118., 119., 120.,
         121., 122., 123., 124., 125., 126., 127., 128., 129., 130., 131.,
         132., 133., 134., 135., 136., 137., 138., 139., 140., 141., 142.,
         143., 144., 145., 146., 147., 148., 149., 150., 151., 152., 153.,
         154., 155., 156., 157., 158., 159., 160., 161., 162., 163., 164.,
         165., 166., 167., 168., 169., 170., 171., 172., 173., 174., 175.,
         176., 177., 178., 179., 180., 181., 182., 183., 184., 185., 186.,
         187., 188., 189., 190., 191., 192., 193., 194., 195., 196., 197.,
         198., 199., 200., 201., 202., 203., 204., 205., 206., 207., 208.,
         209., 210., 211., 212., 213., 214., 215., 216., 217., 218., 219.,
         220., 221., 222., 223., 224., 225., 226., 227., 228., 229., 230.,
         231., 232., 233., 234., 235., 236., 237., 238., 239., 240., 241.,
         242., 243., 244., 245., 246., 247., 248., 249., 250., 251., 252.,
         253., 254., 255., 256.], dtype=float32),
  <a list of 256 Patch objects>),
 None)

所以我们有一个大小为50的数组'z',值从0到255。我把“z”改成了列向量。当存在多个功能时,它将更加有用。然后我制作了np.float32类型的数据。

我们得到以下图像:

现在我们应用KMeans函数。在此之前,我们需要指定 \(criteria\) . 我的标准是,只要运行10次算法迭代,或者 epsilon = 1.0 到达时,停止算法并返回答案。

>>> # Define criteria = ( type, max_iter = 10 , epsilon = 1.0 )
>>> criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0)
>>> # Set flags (Just to avoid line break in the code)
>>> flags = cv.KMEANS_RANDOM_CENTERS
>>> # Apply 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,用黄色绘制质心。

>>> # Now plot 'A' in red, 'B' in blue, 'centers' in yellow
>>> 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()
../_images/sec06-kmeans-opencv_7_0.png

下面是我们得到的输出:

10.6.4. 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))
>>> # convert to np.float32
>>> Z = np.float32(Z)
>>> # define criteria and apply 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)
>>> # Now separate the data, Note the flatten()
>>> A = Z[label.ravel()==0]
>>> B = Z[label.ravel()==1]
>>> # Plot the data
>>> 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()
../_images/sec06-kmeans-opencv_9_0.png

下面是我们得到的输出:

10.6.5. 三。色彩量化

颜色量化是减少图像中颜色数量的过程。这样做的一个原因是减少内存。有时,某些设备可能有限制,因此只能产生有限数量的颜色。在这些情况下,还执行颜色量化。这里我们使用k-均值聚类进行颜色量化。

这里没有什么新的解释。有3个特性,比如R,G,B。所以我们需要将图像重塑为Mx3大小的数组(M是图像中的像素数)。在聚类之后,我们将质心值(也就是R,G,B)应用于所有像素,这样得到的图像将具有指定数量的颜色。再次,我们需要重塑它回到原始图像的形状。下面是代码:

>>> import numpy as np
>>> import cv2 as cv
>>> img = cv.imread('/cvdata/home.jpg')
>>> Z = img.reshape((-1,3))
>>> # convert to np.float32
>>> Z = np.float32(Z)
>>> # define criteria, number of clusters(K) and apply 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)
>>> # Now convert back into uint8, and make original image
>>> center = np.uint8(center)
>>> res = center[label.flatten()]
>>> res2 = res.reshape((img.shape))
>>>
>>> plt.imshow(res2)
>>>
>>> # cv.imshow('res2',res2)
>>> # cv.waitKey(0)
>>> # cv.destroyAllWindows()
<matplotlib.image.AxesImage at 0x7f224a830128>
../_images/sec06-kmeans-opencv_11_1.png

K=8见下表:

10.6.6. 额外资源

10.6.7. 练习