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

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)+'\n')
except:
print "This file format is not support"
fp.close()

处理前的图片:

  

  处理后的图片:

  

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

最新文章

  1. 数百个 HTML5 例子学习 HT 图形组件 – 拓扑图篇
  2. VB CreateObject转C#
  3. Linux系统中Xampp+Bugfree安装
  4. Sublime Text 3 插件安装及Vim 模式设置
  5. tarjan算法求桥双连通分量 POJ 3177 Redundant Paths
  6. SQL - 分页存储过程
  7. ED/EP系列2《文件结构》
  8. 在centOS中加入本地ISO yum源
  9. Top Android App使用的组件 3
  10. MFC菜单、工具栏和状态栏
  11. maven 启动忽略test
  12. Thinkphp join 连接查询
  13. MySQL MVCC机制
  14. [poj2152]fire_树形dp
  15. 记录:C++类内存分布(虚继承与虚函数)
  16. Python和Java分别实现冒泡排序
  17. PHP MySql增删改查
  18. WPF 各种绑定写法以及用法
  19. 教你如何制作饼干icon教程
  20. Jenkins的参数化构建

热门文章

  1. Kibana 基础入门
  2. windows下使用vscode编写运行以及调试Python
  3. CSS Grid布局入门
  4. vs2017 编译JRTPLIB
  5. 获取 user-agents
  6. Parquet列式存储格式
  7. javascript创建对象之原型模式(三)
  8. C# webbrowser实现百度知道团队邀请助手!
  9. 可怕的SCN!(转载)
  10. ElasticSearch Document API