Python图像处理,聚类算法
分类:高并发

Python图像处理(11):k均值

 

 

K均值是一个经典的聚类算法,我们试试在python下使用它。

首先以(-1.5, -1.5)和(1.5, 1.5)为中心点各生成10个点的随机坐标值,我们希望用K均值算法将它们正确的分类。

 

 

# 创建测试的数据点,2类
# 以(-1.5, -1.5)为中心
rand1 = np.ones((10,2)) * (-2) + np.random.rand(10, 2)
print(rand1)

# 以(1.5, 1.5)为中心
rand2 = np.ones((10,2)) + np.random.rand(10, 2)
print(rand2)

# 合并随机点
data = np.vstack((rand1, rand2))

 

接下来kmeans出场。

这个函数的python原型为:

In [14]: help(cv2.kmeans)

Help on built-in function kmeans:

 

kmeans(...)

kmeans(data, K,bestLabels, criteria, attempts, flags[, centers]) -> retval, bestLabels,centers

 

在我们的脚本中调用它:

 

# kmeans
(ret, label, center) = cv2.kmeans(data, 2, None, (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_MAX_ITER, 10, 0.1), 10, cv2.KMEANS_RANDOM_CENTERS )

 

通过此函数我们得到了2个类别的中心点和每个点所属的类别。

最后按分类显示:

 

# 按label进行分类显示
idx = np.hstack((label, label))
for i in range(0, 2) :
    type_data = data[idx == i]
    type_data = np.reshape(type_data, (type_data.shape[0] / 2, 2))
    plt.plot(type_data[:,0], type_data[:,1], 'o')

plt.show()

 

很好的一个结果:

图片 1  

 

 

 

 

 

 

 

 

 

K均值是一个经典的聚类算法,我们试试在python下使用它。 首先以(-1.5, -1.5)和(1.5, 1.5)为中心点各生成10个点的随...

写在前面:之前想分类图像的时候有看过k-means算法,当时一知半解的去使用,不懂原理不懂使用规则。。。显然最后失败了,然后看了《机器学习》这本书对k-means算法有了理论的认识,现在通过贾志刚老师的视频有了实际应用的理解。

  基于划分方法聚类算法R包:

算法原理


  • K-均值聚类(K-means)                   stats::kmeans()、fpc::kmeansruns()
  • K-中心点聚类(K-Medoids)               cluster::pam() 、fpc::pamk()
  • 层次聚类                                stats::hclust()、BIRCH、CURE
  • 密度聚类                                fpc::DBSCAN(),OPTICS
  • 网格聚类                                optpart::clique
  • 模型聚类                                EM算法(期望最大化算法)  mclust::Mclust()  、RWeka::Cobweb() 
  • 模糊聚类                                FCM(Fuzzy C-Means)算法   cluster::fanny()  、e1071::cmeans()

 

K均值聚类

KMeans算法是典型的基于距离的聚类算法,采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。该算法认为簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标。
K个初始聚类中心点的选取对聚类结果具有较大的影响,因为在该算法第一步中是随机地选取任意k个对象作为初始聚类中心,初始地代表一个簇。该算法在每次迭代中对数据集中剩余的每个对象,根据其与各个簇中心的距离赋给最近的簇。当考查完所有数据对象后,一次迭代运算完成,新的聚类中心被计算出来。
算法过程如下:
(1)从N个数据文档(样本)随机选取K个数据文档作为质心(聚类中心)。
本文在聚类中心初始化实现过程中采取在样本空间范围内随机生成K个聚类中心。
(2)对每个数据文档测量其到每个质心的距离,并把它归到最近的质心的类。
(3)重新计算已经得到的各个类的质心。
(4)迭代(2)~(3步直至新的质心与原质心相等或小于指定阈值,算法结束。
本文采用所有样本所属的质心都不再变化时,算法收敛。

k-means算法原理


代码实现

    注:还是和之前一样,核心都是别人的,我只是知识的搬运工并且加上了自己的理解。弄完之后发现理论部分都是别人的~~没办法这算法太简单了。。。

  • stats::kmeans()
  • fpc::kmeansruns()

 

stats::kmeans()

本文在实现过程中采用数据集4k2_far.txt,聚类算法实现过程中默认的类别数量为4。

k-means含义:无监督的聚类算法。


(1)辅助函数myUtil.py

          无监督:就是不需要人干预,拿来一大批东西直接放进算法就可以进行分类。SVM和神经网络都是需要提前训练好然后再进行分类这样就是监督学习。而k-means和K近邻都是无监督学习。

  Usage:kmeans(x, centers, iter.max = 10, nstart = 1, algorithm = c("Hartigan-Wong", "Lloyd", "Forgy", "MacQueen"), trace=FALSE)

# -*- coding:utf-8 -*-
from numpy import *

# 数据文件转矩阵
# path: 数据文件路径
# delimiter: 行内字段分隔符
def file2matrix(path, delimiter):
    fp = open(path, "rb")   # 读取文件内容
    content = fp.read()
    fp.close()
    rowlist = content.splitlines()   # 按行转换为一维表
    # 逐行遍历,结果按分隔符分隔为行向量
    recordlist = [map(eval, row.split(delimiter)) for row in rowlist if row.strip()]
    # 返回转换后的矩阵形式
    return mat(recordlist)

# 随机生成聚类中心
def randCenters(dataSet, k):
    n = shape(dataSet)[1]   # 列数
    clustercents = mat(zeros((k, n)))   # 初始化聚类中心矩阵:k*n
    for col in xrange(n):
        mincol = min(dataSet[:, col])
        maxcol = max(dataSet[:, col])
        # random.rand(k, 1):产生一个0~1之间的随机数向量(k,1表示产生k行1列的随机数)
        clustercents[:, col] = mat(mincol + float(maxcol - mincol) * random.rand(k, 1))   # 按列赋值
    return clustercents

# 欧式距离计算公式
def distEclud(vecA, vecB):
    return linalg.norm(vecA-vecB)

# 绘制散点图
def drawScatter(plt, mydata, size=20, color='blue', mrkr='o'):
    plt.scatter(mydata.T[0], mydata.T[1], s=size, c=color, marker=mrkr)

# 以不同颜色绘制数据集里的点
def color_cluster(dataindx, dataSet, plt):
    datalen = len(dataindx)
    for indx in xrange(datalen):
        if int(dataindx[indx]) == 0:
            plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='blue', marker='o')
        elif int(dataindx[indx]) == 1:
            plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='green', marker='o')
        elif int(dataindx[indx]) == 2:
            plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='red', marker='o')
        elif int(dataindx[indx]) == 3:
            plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='cyan', marker='o')

          聚类:通过一个中心聚在一起的分类,比如给你一批数据让你分成三类,那就是三个中心,那这三个中心代表的意思就是三个类。

  • x:聚类对象
  • centers: 是聚类个数或者是聚类中心
  • iter.max:是允许的最大迭代次数,默认为10
  • nstart:是初始被随机选择的聚类中心

(2)KMeans实现核心函数kmeans.py

 

示例代码

from myUtil import *

def kMeans(dataSet, k):
    m = shape(dataSet)[0]  # 返回矩阵的行数

    # 本算法核心数据结构:行数与数据集相同
    # 列1:数据集对应的聚类中心,列2:数据集行向量到聚类中心的距离
    ClustDist = mat(zeros((m, 2)))

    # 随机生成一个数据集的聚类中心:本例为4*2的矩阵
    # 确保该聚类中心位于min(dataSet[:,j]),max(dataSet[:,j])之间
    clustercents = randCenters(dataSet, k)  # 随机生成聚类中心

    flag = True  # 初始化标志位,迭代开始
    counter = []  # 计数器

    # 循环迭代直至终止条件为False
    # 算法停止的条件:dataSet的所有向量都能找到某个聚类中心,到此中心的距离均小于其他k-1个中心的距离
    while flag:
        flag = False  # 预置标志位为False

        # ---- 1. 构建ClustDist: 遍历DataSet数据集,计算DataSet每行与聚类的最小欧式距离 ----#
        # 将此结果赋值ClustDist=[minIndex,minDist]
        for i in xrange(m):

            # 遍历k个聚类中心,获取最短距离
            distlist = [distEclud(clustercents[j, :], dataSet[i, :]) for j in range(k)]
            minDist = min(distlist)
            minIndex = distlist.index(minDist)

            if ClustDist[i, 0] != minIndex:  # 找到了一个新聚类中心
                flag = True  # 重置标志位为True,继续迭代

            # 将minIndex和minDist**2赋予ClustDist第i行
            # 含义是数据集i行对应的聚类中心为minIndex,最短距离为minDist
            ClustDist[i, :] = minIndex, minDist

        # ---- 2.如果执行到此处,说明还有需要更新clustercents值: 循环变量为cent(0~k-1)----#
        # 1.用聚类中心cent切分为ClustDist,返回dataSet的行索引
        # 并以此从dataSet中提取对应的行向量构成新的ptsInClust
        # 计算分隔后ptsInClust各列的均值,以此更新聚类中心clustercents的各项值
        for cent in xrange(k):
            # 从ClustDist的第一列中筛选出等于cent值的行下标
            dInx = nonzero(ClustDist[:, 0].A == cent)[0]
            # 从dataSet中提取行下标==dInx构成一个新数据集
            ptsInClust = dataSet[dInx]
            # 计算ptsInClust各列的均值: mean(ptsInClust, axis=0):axis=0 按列计算
            clustercents[cent, :] = mean(ptsInClust, axis=0)
    return clustercents, ClustDist

k-means步骤:

##数据集进行备份
newiris <- iris
newiris$Species <- NULL
library(stats)
kc <- kmeans(x=newiris, centers = 3)
##查看具体分类情况 
fitted(kc)
##在三个聚类中分别统计各种花出现的次数
table(iris$Species, kc$cluster)

(3)KMeans算法运行主函数kmeans_test.py

 

查看运行结果,产生了3个聚类,如下解释:

# -*- encoding:utf-8 -*-

from kmeans import *
import matplotlib.pyplot as plt

dataMat = file2matrix("testData/4k2_far.txt", "t")   # 从文件构建的数据集
dataSet = dataMat[:, 1:]   # 提取数据集中的特征列

k = 4   # 外部指定1,2,3...通过观察数据集有4个聚类中心
clustercents, ClustDist = kMeans(dataSet, k)

# 返回计算完成的聚类中心
print "clustercents:n", clustercents

# 输出生成的ClustDist:对应的聚类中心(列1),到聚类中心的距离(列2),行与dataSet一一对应
color_cluster(ClustDist[:, 0:1], dataSet, plt)
# 绘制聚类中心
drawScatter(plt, clustercents, size=60, color='red', mrkr='D')
plt.show()

这个算法其实很简单,如下图所示: (这里直接复制别人步骤,说的很明白了)

> kc
K-means clustering with 3 clusters of sizes 62, 50, 38  #K-means算法产生了3个聚类,大小分别为38,50,62.

Cluster means:  #每个聚类中各个列值生成的最终平均值
  Sepal.Length Sepal.Width Petal.Length Petal.Width
1     5.901613    2.748387     4.393548    1.433871
2     5.006000    3.428000     1.462000    0.246000
3     6.850000    3.073684     5.742105    2.071053

Clustering vector:  #每行记录所属的聚类(2代表属于第二个聚类,1代表属于第一个聚类,3代表属于第三个聚类)  [1] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 [71] 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 3 3 3 1 3 3 3 3 3 3 1 1 3 3 3 3 1 3 1 3 1 3 3 1 1 3 3 3 3 3 1 3 3 3 3 1 3
[141] 3 3 1 3 3 3 1 3 3 1

Within cluster sum of squares by cluster:  #每个聚类内部的距离平方和,说明第一类样本点差异最大,第二类差异最小
[1] 39.82097 15.15100 23.87947
 (between_SS / total_SS =  88.4 %)
#组间的距离平方和占了整体距离平方和的的88.4%,这个值越大表明组内差距越小,组间差距越大,即聚类效果越好该值可用于与类别数取不同值时的聚类结果进行比较。


Available components:

[1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss" "betweenss"    "size"         "iter"         "ifault"      
#"cluster"是一个整数向量,用于表示记录所属的聚类  
#"centers"是一个矩阵,表示每聚类中各个变量的中心点
#"totss"表示所生成聚类的总体距离平方和
#"withinss"表示各个聚类组内的距离平方和
#"tot.withinss"表示聚类组内的距离平方和总量
#"betweenss"表示聚类组间的聚类平方和总量
#"size"表示每个聚类组中成员的数量

评估分类结果

图片 2

 创建一个连续表,在三个聚类中分别统计各种花出现的次数 


从上图中,我们可以看到,A,B,C,D,E是五个在图中点。而灰色的点是我们的种子点,也就是我们用来找点群的点。有两个种子点,所以K=2。

> ##在三个聚类中分别统计各种花出现的次数
> table(iris$Species, kc$cluster)

              1  2  3
  setosa      0 50  0
  versicolor 48  0  2
  virginica  14  0 36

(1)正确的分类输出
KMeans聚类结果如图所示:

然后,K-Means的算法如下:

根据最后的聚类结果画出散点图,数据为结果集中的列"Sepal.Length"和"Sepal.Width",颜色为用1,2,3表示的缺省颜色

图片 3

    1. 随机在图中取K(这里K=2)个种子点。
    2. 然后对图中的所有点求到这K个种子点的距离,假如点Pi离种子点Si最近,那么Pi属于Si点群。(上图中,我们可以看到A,B属于上面的种子点,C,D,E属于下面中部的种子点)
    3. 接下来,我们要移动种子点到属于他的“点群”的中心。(见图上的第三步)
    4. 然后重复第2)和第3)步,直到,种子点没有移动(我们可以看到图中的第四步上面的种子点聚合了A,B,C,下面的种子点聚合了D,E)。
> plot(newiris[c("Sepal.Length", "Sepal.Width")], col = kc$cluster)

                                                                           Kmeans分类正确结果

这个算法很简单,但是有些细节我要提一下,求距离的公式我不说了,大家有初中毕业水平的人都应该知道怎么算的。我重点想说一下“求点群中心的算法”。

在图上标出每个聚类的中心点

输出的聚类中心结果如下:

求点群中心的算法

一般来说,求点群中心点的算法你可以很简的使用各个点的X/Y坐标的平均值。不过,我这里想告诉大家另三个求中心点的的公式:

1)Minkowski Distance公式——λ可以随意取值,可以是负数,也可以是正数,或是无穷大。

图片 4

2)Euclidean Distance公式——也就是第一个公式λ=2的情况

图片 5

3)CityBlock Distance公式——也就是第一个公式λ=1的情况

图片 6

k-means的缺点:

    ① 在 K-means 算法中 K 是事先给定的,这个 K 值的选定是非常难以估计的。很多时候,事先并不知道给定的数据集应该分成多少个类别才最合适。这也是 K-means 算法的一个不足。

    ② 在 K-means 算法中,首先需要根据初始聚类中心来确定一个初始划分,然后对初始划分进行优化。这个初始聚类中心的选择对聚类结果有较大的影响,一旦初始值选择的不好,可能无法得到有效的聚类结果,这也成为 K-means算法的一个主要问题。

   ③ 从 K-means 算法框架可以看出,该算法需要不断地进行样本分类调整,不断地计算调整后的新的聚类中心,因此当数据量非常大时,算法的时间开销是非常大的。

 

 


 

 opencv+K-means

 

 没什么好写的,因为这个k-means比较简单,主要说的就是函数参数的应用而已:

 

  void RNG::fill(InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange=false )

  这个函数是对矩阵mat填充随机数,随机数的产生方式有参数2来决定,如果为参数2的类型为RNG::UNIFORM,则表示产生均一分布的随机数,如果为RNG::NORMAL则表示产生高斯分布的随机数。对应的参数3和参数4为上面两种随机数产生模型的参数。比如说如果随机数产生模型为均匀分布,则参数a表示均匀分布的下限,参数b表示上限。如果随机数产生模型为高斯模型,则参数a表示均值,参数b表示方程。参数5只有当随机数产生方式为均匀分布时才有效,表示的是是否产生的数据要布满整个范围(没用过,所以也没仔细去研究)。另外,需要注意的是用来保存随机数的矩阵mat可以是多维的,也可以是多通道的,目前最多只能支持4个通道。

  void randShuffle(InputOutputArray dst, double iterFactor=1., RNG* rng=0 )

  该函数表示随机打乱1D数组dst里面的数据,随机打乱的方式由随机数发生器rng决定。iterFactor为随机打乱数据对数的因子,总共打乱的数据对数为:dst.rows*dst.cols*iterFactor,因此如果为0,表示没有打乱数据。

  Class TermCriteria

  类TermCriteria 一般表示迭代终止的条件,如果为CV_TERMCRIT_ITER,则用最大迭代次数作为终止条件,如果为CV_TERMCRIT_EPS 则用精度作为迭代条件,如果为CV_TERMCRIT_ITER+CV_TERMCRIT_EPS则用最大迭代次数或者精度作为迭代条件,看哪个条件先满足。

  double kmeans(InputArray data, int K, InputOutputArray bestLabels, TermCriteria criteria, int attempts, int flags, OutputArray centers=noArray() )

  该函数为kmeans聚类算法实现函数。参数data表示需要被聚类的原始数据集合,一行表示一个数据样本,每一个样本的每一列都是一个属性;参数k表示需要被聚类的个数;参数bestLabels表示每一个样本的类的标签,是一个整数,从0开始的索引整数;参数criteria表示的是算法迭代终止条件;参数attempts表示运行kmeans的次数,取结果最好的那次聚类为最终的聚类,要配合下一个参数flages来使用;参数flags表示的是聚类初始化的条件。其取值有3种情况,如果为KMEANS_RANDOM_CENTERS,则表示为随机选取初始化中心点,如果为KMEANS_PP_CENTERS则表示使用某一种算法来确定初始聚类的点;如果为KMEANS_USE_INITIAL_LABELS,则表示使用用户自定义的初始点,但是如果此时的attempts大于1,则后面的聚类初始点依旧使用随机的方式;参数centers表示的是聚类后的中心点存放矩阵。该函数返回的是聚类结果的紧凑性,其计算公式为:

  图片 7

 

 

 注意点一:

这是说个我自己不理解的地方:fill(InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange=false )

              这里的InputArray a, InputArray b------>>>分别用了Scalar(center.x, center.y, 0, 0), Scalar(img.cols*0.05, img.rows*0.05, 0, 0)去替换

              去查了一下手册:InputArray这个接口类可以是Mat、Mat_<T>、Mat_<T, m, n>、vector<T>、vector<vector<T>>、vector<Mat>。没有提到Scalar()可以使用

              特意定义了一个:InputArray test = Scalar(1,1);这个又是可以的,定义Mat不行,Vector也不行,这个真的不知道什么原因,有时间得去看源码a,b的使用。

 //----下面的定义都是错误的,运行的结果都不对,原因暂时不知道

 1      Mat a = (Mat_<uchar>(1, 2) << center.x, center.y);
 2         Mat b = (Mat_<uchar>(1, 2) << img.cols*0.05, img.rows*0.05);
 3         
 4         InputArray a1 = Scalar(center.x, center.y);
 5         InputArray b1 = Scalar(img.cols*0.05, img.rows*0.05);
 6         Mat a2 = a1.getMat();
 7         Mat b2 = b1.getMat();
 8         
 9         Mat c(1, 2, CV_8UC1);
10         c = Scalar(center.x, center.y);
11         Mat c1(1, 2, CV_8UC1);
12         c1 = Scalar(img.cols*0.05, img.rows*0.05);
13         
14         rng.fill(pointChunk, RNG::NORMAL, a, b, 0);

 

注意点二:

     

    kmeans()函数的输入只接受 data0.dims <= 2 && type == CV_32F && K > 0 ,

            第一个dims一般都不会越界(三维不行)

            第二个参数CV_32F == float,千万别带入CV_8U == uchar

            第三个参数不用说了,设置的种类肯定是大于0的

 

 

注意点三:

 

   opencv里面k-means函数的样本数据、标签、中心点的存储:

    图片 8

图片 9

 图片 10

 

 

 这是正确的代码:(聚类)

 1 #include <opencv2/opencv.hpp>
 2 #include <iostream>
 3 
 4 using namespace cv;
 5 using namespace std;
 6 
 7 int main(int argc, char** argv) {
 8     Mat img(500, 500, CV_8UC3);
 9     RNG rng(12345);
10     const int Max_nCluster = 5;
11     Scalar colorTab[] = {
12         Scalar(0, 0, 255),
13         Scalar(0, 255, 0),
14         Scalar(255, 0, 0),
15         Scalar(0, 255, 255),
16         Scalar(255, 0, 255)
17     };
18     //InputArray a = Scalar(1,1);
19     int numCluster  = rng.uniform(2, Max_nCluster + 1);//随机类数
20     int sampleCount = rng.uniform(5, 1000);//样本点数量
21     Mat matPoints(sampleCount, 1, CV_32FC2);//样本点矩阵:sampleCount X 2
22     Mat labels;
23     Mat centers;
24 
25     // 生成随机数
26     for (int k = 0; k < numCluster; k++) {
27         Point center;//随机产生中心点
28         center.x = rng.uniform(0, img.cols);
29         center.y = rng.uniform(0, img.rows);
30         Mat pointChunk = matPoints.rowRange( k*sampleCount / numCluster,
31             (k + 1)*sampleCount / numCluster);
32         //-----这句话的意思我不明白作用是什么,没意义啊!
33         /*Mat pointChunk = matPoints.rowRange(k*sampleCount / numCluster,
34             k == numCluster - 1 ? sampleCount : (k + 1)*sampleCount / numCluster);*/
35         //-----符合高斯分布的随机高斯
36         rng.fill(pointChunk, RNG::NORMAL, Scalar(center.x, center.y, 0, 0), Scalar(img.cols*0.05, img.rows*0.05, 0, 0));
37     }
38     randShuffle(matPoints, 1, &rng);//打乱高斯生成的数据点顺序
39 
40     // 使用KMeans
41     kmeans(matPoints, numCluster, labels, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1), 3, KMEANS_PP_CENTERS, centers);
42 
43     // 用不同颜色显示分类
44     img = Scalar::all(255);
45     for (int i = 0; i < sampleCount; i++) {
46         int index = labels.at<int>(i);
47         Point p = matPoints.at<Point2f>(i);
48         circle(img, p, 2, colorTab[index], -1, 8);
49     }
50 
51     // 每个聚类的中心来绘制圆
52     for (int i = 0; i < centers.rows; i++) {
53         int x = centers.at<float>(i, 0);
54         int y = centers.at<float>(i, 1);
55         printf("c.x= %d, c.y=%d", x, y);
56         circle(img, Point(x, y), 40, colorTab[i], 1, LINE_AA);
57     }
58 
59     imshow("KMeans-Data-Demo", img);
60     waitKey(0);
61     return 0;
62 }

 

 图片 11

图片 12

 

 

分类代码:

 

 

  1 #include <opencv2/opencv.hpp>
  2 #include <iostream>
  3 
  4 using namespace cv;
  5 using namespace std;
  6 
  7 RNG rng(12345);
  8 const int Max_nCluster = 5;
  9 
 10 int main(int argc, char** argv) {
 11     //Mat img(500, 500, CV_8UC3);
 12     Mat inputImage = imread("1.jpg");
 13     assert(!inputImage.data);
 14     Scalar colorTab[] = {
 15         Scalar(0, 0, 255),
 16         Scalar(0, 255, 0),
 17         Scalar(255, 0, 0),
 18         Scalar(0, 255, 255),
 19         Scalar(255, 0, 255)
 20     };
 78     Mat matData = Mat::zeros(Size(inputImage.channels(), inputImage.rows*inputImage.cols), CV_32FC1);
 79     int ncluster = 5; //rng.uniform(2, Max_nCluster + 1);//聚类数量
 80     Mat label;//聚类标签
 81     Mat centers(ncluster, 1, matData.type());
 82     for (size_t i = 0; i < inputImage.rows; i++)//把图像存储到样本容器
 83     {
 84         uchar* ptr = inputImage.ptr<uchar>(i);
 85         for (size_t j = 0; j < inputImage.cols; j++)
 86         {
 87             matData.at<float>(i*inputImage.cols + j, 0) = ptr[j*inputImage.channels()];
 88             matData.at<float>(i*inputImage.cols + j, 1) = ptr[j*inputImage.channels() +1];
 89             matData.at<float>(i*inputImage.cols + j, 2) = ptr[j*inputImage.channels() +2];
 90         }
 91     }
 92     Mat result = Mat::zeros(inputImage.size(), inputImage.type());
 93     TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 20, 0.1);
 94     kmeans(matData, ncluster, label, criteria, 3, KMEANS_PP_CENTERS, centers);
 95     for (size_t i = 0; i < inputImage.rows; i++)
 96     {
 97         for (size_t j = 0; j < inputImage.cols; j ++)
 98         {
 99             int index = label.at<int>(i*inputImage.cols + j,0);
100             result.at<Vec3b>(i, j)[0] = colorTab[index][0];
101             result.at<Vec3b>(i, j)[1] = colorTab[index][1];
102             result.at<Vec3b>(i, j)[2] = colorTab[index][2];
103         }
104     }
105     imshow("12", result);
106     waitKey(0);
107     return 0;
108 }

 

 图片 13

 

 图片 14

 

 

参考:  百度百科

     

     (讲的太好了)

     

     贾老师课程(如果一点不懂得可以看看)

 

> points(kc$centers[,c("Sepal.Length", "Sepal.Width")], col = 1:3, pch = 8, cex=2)
生成图例 如下:
clustercents:
[[ 6.99438039  5.05456275]
 [ 8.08169456  7.97506735]
 [ 3.02211698  6.00770189]
 [ 2.95832148  2.98598456]]

图片 15

(2)错误输出

小结:

因为聚类中心随机初始化的关心,KMeans并不是总能够找到正确的聚类,下面是不能找到正确分类的情况。

     在这个示例中, 首先将数据集中变量品种全部置为空, 然后重新指定3个聚类,比较一下kmeans算法生成的结果和原有的结果。

情况一,局部最优收敛:

     在kmean算法中针对变量 Sepal.Length Sepal.Width Petal.Length Petal.Width生成三组随机值作为中心点,然后计算每个样本中的4个变量到随机值的距离,根据最新的随机数值总合算出平均值重新计算中心点。然后不断的重复此步骤, 直到中心点的值不再变化。最后再将样本值和最终生成的中心值作比较,距离最近的归属于这个中心值所代表的聚类。最后使用plot函数画图的时候, 可以发现kmeans算法最后生成的分类并不是特别理想,各个聚类之间的距离并不是很大。需要多运行几次。

clustercents:
[[ 2.9750599   3.77881139]
 [ 7.311725    5.00685   ]
 [ 6.7122963   5.09697407]
 [ 8.08169456  7.97506735]]

 

图片 16

fpc::kmeansruns() 

                                                                                Kmeans错误分类结果一


情况二,只收敛到三个聚类中心:

 fpc包kmeansruns函数,相比于kmeans函数更加稳定,而且还可以估计聚为几类

clustercents:
[[ 6.99438039  5.05456275]
 [ 2.9750599   3.77881139]
 [ 8.08169456  7.97506735]
 [        nan         nan]]

Usage: kmeansruns(data,krange=2:10,criterion="ch",iter.max=100,runs=100,scaledata=FALSE,alpha=0.001, critout=FALSE,plot=FALSE,...);

图片 17

  • krange: 聚类个数范围
  • critout: logical. If TRUE, the criterion value is printed out for every number of clusters
  • iter.max:是允许的最大迭代次数,默认为100

                                                                               Kmeans错误分类结果二

需要安装包

KMeans算法适用场景及优缺点

install.packages("lme4")
install.packages("fpc")

示例代码

KMeans擅长处理球状分布的数据,当结果聚类是密集的,而且类和类之间的区别比较明显时,K均值的效果比较好。对于处理大数据集,这个算法是相对可伸缩的和高效的,它的复杂度是O(nkt),n是对象的个数,k是簇的数目,t是迭代的次数。相比其他的聚类算法,KMeans比较简单、容易掌握,这也是其得到广泛使用的原因之一。
但KMeans算法也存在一些问题。
(1)算法的初始中心点选择与算法的运行效率密切相关,而随机选取中心点有可能导致迭代次数很大或者限于某个局部最优状态;通常k<<n,且t<<n,所以算法经常以局部最优收敛。
(2)K均值的最大问题是要求用户必须事先给出k的个数,k的选择一般都基于一些经验值和多次试验的结果,对于不同的数据集,k的取值没有可借鉴性。
(3)对异常偏离的数据敏感——离群点;K均值对“噪声”和孤立点数据是敏感的,少量的这类数据就能对平均值造成极大的影响。

> newiris <- iris
> newiris$Species <- NULL
> library(fpc)
> 
> kc1 <- kmeansruns(data = newiris,krange = 1:5,critout = TRUE)
2  clusters  513.9245 
3  clusters  561.6278 
4  clusters  530.7658 
5  clusters  495.5415 
> ##kc1
> ##fitted(kc1)
> table(iris$Species, kc1$cluster)

              1  2  3
  setosa      0  0 50
  versicolor  2 48  0
  virginica  36 14  0
>

因此,提出了二分KMeans算法,用以改进KMeans算法局部最优的问题。

待验证: 

相关

   fpc::cluster.stats()


小结:

1、:Bisecting KMeans (二分K均值)算法讲解及实现。

    指定聚类个数范围为:1:5, 但估计聚类结果为3,与kmeans方法相比,不需初始确定聚类个数 

 

参考资料: 


本文由10bet手机官网发布于高并发,转载请注明出处:Python图像处理,聚类算法

上一篇:css如何实现未知宽高div中图片垂直水平居中效果,jQuery实现的div垂直水平居中实例代码 下一篇:没有了
猜你喜欢
热门排行
精彩图文