图像分类-----K-聚类算法

K-means 是一种将输入数据划分成 k 个簇的简单的聚类算法。K-means 反复提炼初
始评估的类中心,步骤如下:
(1) 以随机或猜测的方式初始化类中心 u i ,i=1…k;
(2) 将每个数据点归并到离它距离最近的类中心所属的类 c i ;
(3) 对所有属于该类的数据点求平均,将平均值作为新的类中心;
(4) 重复步骤(2)和步骤(3)直到收敛。

聚类是无监督算法,优势是不要给数据打标签。

缺点 K不好确定,要预先设定,因此效果不稳定。

 

默认导入:
from PIL import Image
from numpy import *
from pylab import *
import os

代码实现:

步骤一:聚类方法所要用到的类与方法,以及画聚类树的函数方法。

from itertools import combinations
from PIL import Image
from numpy import *
from pylab import *
from PIL import Image,ImageDraw

class ClusterNode(object):
    def __init__(self,vec,left,right,distance=0.0,count=1):
        self.left = left
        self.right = right
        self.vec = vec
        self.distance = distance
        self.count = count # 只用于加权平均
    def extract_clusters(self,dist): 
        if self.distance < dist:
            return [self]
        return self.left.extract_clusters(dist) + self.right.extract_clusters(dist)
    def get_cluster_elements(self):  
        return self.left.get_cluster_elements() + self.right.get_cluster_elements()
    def get_height(self):    
        return self.left.get_height() + self.right.get_height()
    def get_depth(self):
        return max(self.left.get_depth(), self.right.get_depth()) + self.distance
    
    def draw(self,draw,x,y,s,imlist,im):
        """ 用图像缩略图递归地画出叶节点 """
        h1 = int(self.left.get_height()*20 / 2)
        h2 = int(self.right.get_height()*20 /2)
        top = y-(h1+h2)
        bottom = y+(h1+h2)
# 子节点垂直线
        draw.line((x,top+h1,x,bottom-h2),fill=(0,0,0))
    # 水平线
        ll = self.distance*s
        draw.line((x,top+h1,x+ll,top+h1),fill=(0,0,0))
        draw.line((x,bottom-h2,x+ll,bottom-h2),fill=(0,0,0))
    # 递归地画左边和右边的子节点
        self.left.draw(draw,x+ll,top+h1,s,imlist,im)
        self.right.draw(draw,x+ll,bottom-h2,s,imlist,im)

class ClusterLeafNode(object):
    
    def __init__(self,vec,id):
        self.vec = vec
        self.id = id
    def extract_clusters(self,dist):
        return [self]
    def get_cluster_elements(self):
        return [self.id]
    def draw(self,draw,x,y,s,imlist,im):
        nodeim = Image.open(imlist[self.id])
        nodeim.thumbnail([20,20])
        ns = nodeim.size
        im.paste(nodeim,[int(x),int(y-ns[1]//2),int(x+ns[0]),int(y+ns[1]-ns[1]//2)])

    def get_height(self):
        return 1
    def get_depth(self):
        return 0
    
def L2dist(v1,v2):
    return sqrt(sum((v1-v2)**2))
def L1dist(v1,v2):
    return sum(abs(v1-v2))
    
def hcluster(features,distfcn=L2dist):
    """ 用层次聚类对行特征进行聚类 """
    # 用于保存计算出的距离
    distances = {}
    # 每行初始化为一个簇
    node = [ClusterLeafNode(array(f),id=i) for i,f in enumerate(features)]
    while len(node)>1:
        closest = float('Inf')
# 遍历每对,寻找最小距离
        for ni,nj in combinations(node,2):
            if (ni,nj) not in distances:
                distances[ni,nj] = distfcn(ni.vec,nj.vec)
            d = distances[ni,nj]
            if d<closest:
                closest = d
                lowestpair = (ni,nj)
        ni,nj = lowestpair
    #  对两个簇求平均
        new_vec = (ni.vec + nj.vec) / 2.0
    #  创建新的节点
        new_node = ClusterNode(new_vec,left=ni,right=nj,distance=closest)
        node.remove(ni)
        node.remove(nj)
        node.append(new_node)
    return node[0]
    
    
def draw_dendrogram(node,imlist,filename='clusters.jpg'):
    rows = node.get_height()*20
    cols = 1200
# 距离缩放因子,以便适应图像宽度
    s = float(cols-150)/node.get_depth()
# 创建图像,并绘制对象
    im = Image.new('RGB',(cols,rows),(255,255,255))
    draw = ImageDraw.Draw(im)
# 初始化树开始的线条
    draw.line((0,rows/2,20,rows/2),fill=(0,0,0))
# 递归地画出节点
    node.draw(draw,20,(rows/2),s,imlist,im)
    im.save(filename)
    im.show()

步骤二:读取图片路径,然后开始运行。

path = './train'
imlist = [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.jpg')]

# 提取特征向量,每个颜色通道量化成 8 个小区间
features = zeros([len(imlist), 512])
for i,f in enumerate(imlist):
    im = array(Image.open(f))
# 多维直方图
    h,edges = histogramdd(im.reshape(-1,3),8,normed=True,range=[(0,255),(0,255),(0,255)])
    features[i] = h.flatten()
tree = hcluster.hcluster(features)


hcluster.draw_dendrogram(tree,imlist,filename='sunset.pdf')

参考文献:《python 计算机视觉编程》--Jan Erik solem

《Getting started with Machine Learning》--Jim Liang

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
运用K-means算法进行像分割, K-means算法是很典型的基于距离的聚类算法,采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。该算法认为簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标。 k个初始类聚类中心点的选取对聚类结果具有较大的 公式 公式 影响,因为在该算法第一步中是随机的选取任意k个对象作为初始聚类的中心,初始地代表一个簇。该算法在每次迭代中对数据集中剩余的每个对象,根据其与各个簇中心的距离将每个对象重新赋给最近的簇。当考察完所有数据对象后,一次迭代运算完成,新的聚类中心被计算出来。如果在一次迭代前后,J的值没有发生变化,说明算法已经收敛。 算法过程如下: 1)从N个文档随机选取K个文档作为质心 2)对剩余的每个文档测量其到每个质心的距离,并把它归到最近的质心的类 3)重新计算已经得到的各个类的质心 4)迭代2~3步直至新的质心与原质心相等或小于指定阈值,算法结束 具体如下: 输入:k, data[n]; (1) 选择k个初始中心点,例如c[0]=data[0],…c[k-1]=data[k-1]; (2) 对于data[0]….data[n],分别与c[0]…c[k-1]比较,假定与c[i]差值最少,就标记为i; (3) 对于所有标记为i点,重新计算c[i]={ 所有标记为i的data[j]之和}/标记为i的个数; (4) 重复(2)(3),直到所有c[i]值的变化小于给定阈值。 折叠工作原理 K-MEANS算法的工作原理及流程 K-MEANS算法 输入:聚类个数k,以及包含 n个数据对象的数据库。 输出:满足方差最小标准的k个聚类。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值