• k-means处理图片


    问题描述:把给定图片,用图片中最主要的三种颜色来表示该图片

    k-means思想:

      1、选择k个点作为初始中心

      2、将每个点指派到最近的中心,形成k个簇cluster

      3、重新计算每个簇的中心

      4、如果簇中心发生明显变化或未达到最大迭代次数,则回到step2

      问题:初始点不对的时候,容易收敛到局部最优值

      解决办法:

        1、选择k个点作为初始中心——canopy,模拟退火,贝叶斯准则

        2、将每个点指派到最近的中心,形成k个簇cluster

        3、重新计算每个簇的中心

        4、如果簇中心发生了明显的变化或未达到最大迭代次数,则回到step2

     

      例子:给你一幅图像,找出其中最主要的三种颜色,并将图片用三种最主要的颜色表示出来

    # -*- coding: utf-8 -*-
    # https://github.com/ZeevG/python-dominant-image-colour
    # commented by heibanke
    
    from PIL import Image
    import random
    import numpy
    
    class Cluster(object):
        """
        pixels: 主要颜色所依据的像素点
        centroid: 主要颜色的RGB值
        """
        def __init__(self):
            self.pixels = []
            self.centroid = None
    #cluster有两个属性,centroid表示聚类中心,pixels表示依附于该聚类中心的那些像素点
    #每个聚类中心都是一个单独的Cluster对象
        def addPoint(self, pixel):
            self.pixels.append(pixel)
    
        def setNewCentroid(self):
            """
            通过pixels均值重新计算主要颜色
            """
            R = [colour[0] for colour in self.pixels]
            G = [colour[1] for colour in self.pixels]
            B = [colour[2] for colour in self.pixels]
    
            R = sum(R) / len(R)
            G = sum(G) / len(G)
            B = sum(B) / len(B)
    
            self.centroid = (R, G, B)
            self.pixels = []
    
            return self.centroid
    
    
    class Kmeans(object):
    
        def __init__(self, k=3, max_iterations=5, min_distance=5.0, size=400):
            """
            k: 主要颜色的分类个数
            max_iterations: 最大迭代次数
            min_distance: 当新的颜色和老颜色的距离小于该最小距离时,提前终止迭代
            size: 用于计算的图像大小
            """
            self.k = k
            self.max_iterations = max_iterations
            self.min_distance = min_distance
            self.size = (size, size)
    
        def run(self, image):
            self.image = image
            #生成缩略图,节省运算量
            self.image.thumbnail(self.size)
            self.pixels = numpy.array(image.getdata(), dtype=numpy.uint8)
            self.clusters = [None]*self.k
            self.oldClusters = None
            #在图像中随机选择k个像素作为初始主要颜色
            randomPixels = random.sample(self.pixels, self.k)
    
            for idx in range(self.k):
                self.clusters[idx] = Cluster()#生成idx个Cluster的对象
                self.clusters[idx].centroid = randomPixels[idx]#每个centroid是随机采样得到的
    
            iterations = 0
    
            #开始迭代
            while self.shouldExit(iterations) is False:
                self.oldClusters= [cluster.centroid for cluster in self.clusters]
                print iterations
    
                #对pixel和self.clusters中的主要颜色分别计算距离,将pixel加入到离它最近的主要颜色所在的cluster中
                for pixel in self.pixels:
                    self.assignClusters(pixel)
                #对每个cluster中的pixels,重新计算新的主要颜色
                for cluster in self.clusters:
                    cluster.setNewCentroid()
    
                iterations += 1
    
            return [cluster.centroid for cluster in self.clusters]
    
        def assignClusters(self, pixel):
            shortest = float('Inf')
            for cluster in self.clusters:
                distance = self.calcDistance(cluster.centroid, pixel)
                if distance < shortest:
                    shortest = distance
                    nearest = cluster#nearest实际上是cluster的引用,不是复制
            nearest.addPoint(pixel)
    
        def calcDistance(self, a, b):
            result = numpy.sqrt(sum((a - b) ** 2))
            return result
    
        def shouldExit(self, iterations):
    
            if self.oldClusters is None:
                return False
            #计算新的中心和老的中心之间的距离
            for idx in range(self.k):
                dist = self.calcDistance(
                    numpy.array(self.clusters[idx].centroid),
                    numpy.array(self.oldClusters[idx])
                )
                if dist < self.min_distance:
                    return True
    
            if iterations <= self.max_iterations:
                return False
    
            return True
    
        # The remaining methods are used for debugging
        def showImage(self):
            """
            显示原始图像
            """
            self.image.show()
    
        def showCentroidColours(self):
            """
            显示主要颜色
            """
            for cluster in self.clusters:
                image = Image.new("RGB", (200, 200), cluster.centroid)
                image.show()
    
        def showClustering(self):
            """
            将原始图像的像素完全替换为主要颜色后的效果
            """
            localPixels = [None] * len(self.image.getdata())
    
            #enumerate用于既需要遍历元素下边也需要得到元素值的情况,用for循环比较麻烦
            for idx, pixel in enumerate(self.pixels):
                    shortest = float('Inf') #正无穷
                    for cluster in self.clusters:
                        distance = self.calcDistance(
                            cluster.centroid,
                            pixel
                        )
                        if distance < shortest:
                            shortest = distance
                            nearest = cluster
    
                    localPixels[idx] = nearest.centroid
    
            w, h = self.image.size
            localPixels = numpy.asarray(localPixels)
                .astype('uint8')
                .reshape((h, w, 3))
    
            colourMap = Image.fromarray(localPixels)
            return colourMap
        
    if __name__=="__main__":
        from PIL import Image
        import os
        
        k_image=Kmeans(k=3) #默认参数
        path = './pics/'
        fp = open('file_color.txt','w')
        for filename in os.listdir(path):
            print path+filename
            try:
                color = k_image.run(Image.open(path+filename))
             #   w_image = k_image.showClustering()
                w_image = k_image.showCentroidColours()
                w_image.save(path+'mean_'+filename,'jpeg')
                fp.write('The color of '+filename+' is '+str(color)+'
    ')
            except:
                print "This file format is not support"
        fp.close()

    处理前的图片:

      

     

      处理后的图片:

      

     

    参考:http://blog.zeevgilovitz.com/detecting-dominant-colours-in-python/

  • 相关阅读:
    RSS简易阅读器vb.net源代码
    [建议]有关图片地址的建议
    [音乐欣赏]wind flowers
    有个叫计算机的比我笨
    一个朋友画的建筑设计手绘图与其想到的
    [推荐]华建小翻--QQ里的一个不错的服务商
    爆强的广告
    [学习日记]重构简易RSSREADER的UML类图
    [音乐欣赏]红颜
    [音乐欣赏]花与琴的流星
  • 原文地址:https://www.cnblogs.com/shixisheng/p/7116045.html
Copyright © 2020-2023  润新知