完整项目代码在:https://github.com/liuhuang31/simple_mainColor

本人新手一枚,所编写的代码基本尽量没调用库类,所以感觉代码会很臃肿,连三级代码都称不上哈,这个主色调也是看了一天python后,现学现用的。可以微博关注@劉煌煌爱喝冬瓜茶     一起交流学习!

python写的(python2.7 和python3.+)都可以使用,需要安装 PIL matplotlib numpy等环境。

一、识别主色调步骤

非常具有参考价值的论文《一种新的MPEG-7主颜色提取算法》,我前面做的步骤基本是参考这篇文章的。

1、获取图像RGB

2、RGB转化成HSV空间值

3、HSV空间下k均值迭代(初始点是根据图像的像素范围来random选择初始点的数值)

4、显示图片(把聚类的hsv值转化为RGB显示出来)

具体详细的步骤看下上面的论文哈

二、代码实现

1、hsvTRGB.py  参考:http://outofmemory.cn/code-snippet/1002/Python-RGB-HSV-color-together-switch

import mathdef Hsv2Rgb(H, S, V):H /= 60.0  # sector 0 to 5i = math.floor(H)f = H - i  # factorial part of hp = V * (1 - S)q = V * (1 - S * f)t = V * (1 - S * (1 - f))if i == 0:R = VG = tB = pelif i == 1:R = qG = VB = pelif i == 2:R = pG = VB = telif i == 3:R = pG = qB = Velif i == 4:R = tG = pB = Velse:R = VG = pB = qreturn R*255, G*255, B*255

2、rgb2hsv.py

def rgb2hsv(r, g, b):r, g, b = r/255.0, g/255.0, b/255.0mx = max(r, g, b)mn = min(r, g, b)df = mx-mnif mx == mn:h = 0elif mx == r and g >= b:h = 60 * ((g - b) / df) + 0elif mx == r and g < b:h = 60 * ((g-b)/df) + 360elif mx == g:h = 60 * ((b-r)/df) + 120elif mx == b:h = 60 * ((r-g)/df) + 240if mx == 0:s = 0else:s = df/mxv = mxreturn h, s, vdef rgb2hsv2(R, G, B):mx = max(R, G, B)mn = min(R, G, B)if R == mx:H = (G-B) / (mx-mn)elif G == mx:H = 2 + (B-R) / (mx-mn)elif B == mx:H = 4 + (R-G) / (mx-mn)H = H * 60if H < 0:H = H + 360V = mxS = (mx - mn) / mxreturn H, S, V

3、PrimaryColor.py

# coding=utf-8from PIL import Image
import rgb2hsv
import random as ran
import hsvTRGB
from pylab import *# 加载图片,返回数据
def loadImage(path):im = Image.open(path)  # Can be many different formats.pix = im.load()  # 获得图像的像素width = im.size[0]  # 获得图像的宽度height = im.size[1]  # 获得图像的高度data = width, height, pix, im  # 把这些width,height,pix,im这些值赋给data,后面KMeans方法里要用到这些值return data# hsv空间两点间欧氏距离,选出距离最小的类
def distEclud(hsv, centroids, k):h, s, v = hsv  # 获取当前像素的h,s,v值min = -1  # 用作判断centroids[i]是否为第一个中心点# 逐个计算当前hsv与各个类中心点的欧式距离,选出距离最小的类for i in range(k):h1, s1, v1 = centroids[i]minc = math.sqrt(math.pow(math.fabs(h - h1), 2) + math.pow(math.fabs(s - s1), 2) + math.pow(math.fabs(v - v1), 2))# minc = math.sqrt(math.pow(s*math.cos(h) - s1*math.cos(h1), 2) + math.pow(s*math.sin(h) - s1*math.sin(h1), 2) + \#     + math.pow(v - v1, 2))/math.sqrt(5)     # 欧氏距离计算公式# 用j表示当前hsv值属于第j个centroidsif (min == -1):min = mincj = 0continueif (minc < min):min = mincj = ireturn j# 随机生成初始的质心(ng的课说的初始方式是随机选K个点),选择图像中最小的值加上随机值来生成
def getCent(dataSet, k):centroids = zeros((k, 3))  # 种子,k表示生成几个初始中心点,3表示hsv三个分量width, height, n = dataSet.shape  # 获得数据的长宽# 循环获得dataSet所有数据里面最小和最大的h,s,v值for i in range(width):for j in range(height):h, s, v = dataSet[i][j]if i == 0 and j == 0:maxh, maxs, maxv = minh, mins, minv = h, s, velif h > maxh:maxh = helif s > maxs:maxs = selif v > maxv:maxv = velif h < minh:minh = helif s < mins:mins = selif v < minv:minv = vrangeh = maxh - minh  # 最大和最小h值之差ranges = maxs - minsrangev = maxv - minv# 生成k个初始点,hsv各个分量的最小值加上range的随机值for i in range(k):centroids[i] = minh + rangeh * ran.random(), mins + ranges * ran.random(), + \minv + rangev * ran.random()return centroids# 前一个centroids与当前centroids的根号平方差
def getDist(preC, centroids):k, n = preC.shape  # k表示centroids的k个中心点(类中心点),n表示例如centroid[0]当中的三个hsv分量sum = 0.0  # 总距离for i in range(k):h, s, v = preC[i]h1, s1, v1 = centroids[i]distance = math.pow(math.fabs(h - h1), 2) + math.pow(math.fabs(s - s1), 2) + math.pow(math.fabs(v - v1), 2)sum += distancereturn math.sqrt(sum)# 中心点k均值迭代
def KMeans(k, data):width, height, pix, im = data  # 获得要处理图像的各个数据dataSet = [[0 for col in range(height)] for row in range(width)]  # 图像数据转化为hsv后的数据及其数据格式for x in range(width):for y in range(height):r, g, b = pix[x, y]  # 获取图像rgb值hsv = h, s, v = rgb2hsv.rgb2hsv(r, g, b)  # 把rgb值转化为hsv值dataSet[x][y] = hsvdataSet = np.array(dataSet)  # 把dataSet数据转化为numpy的数组数据,以便待会获得初始点时,更好处理数据centroids = getCent(dataSet, k)  # 获得k个初始中心点# 循环迭代直到前一个centroids与当前centroids的根号距离满足一定条件while 1:count = [0 for i in range(k)]  # count用来统计各个中心类中的数据的个数myList = [[] for i in range(width * height)]  # mylist用来存放各个中心类中的数据preC = centroids  # preC保存前一个centroids的数据# 判断各个像素属于哪个中心类,然后把hsv值放到所属类for x in range(width):for y in range(height):r, g, b = pix[x, y]hsv = h, s, v = rgb2hsv.rgb2hsv(r, g, b)i = distEclud(hsv, centroids, k)  # 计算欧氏距离,获得该像素,也就是hsv所属中心类myList[i].append((h, s, v))  # 把hsv值加到所属中心类count[i] += 1  # 相应所属类的个数增加# 一次所有点类别划分后,重新计算中心点for i in range(k):size = len(myList[i])  # 各个类中的个数sumh = sums = sumv = 0.0if (size == 0):continueelse:for j in range(size):h, s, v = myList[i][j]sumh += hsums += ssumv += vcentroids[i] = sumh / size, sums / size, sumv / size  # 取该类hsv分量的平均值print (centroids[0:k])norm = getDist(preC, centroids)  # 获得前一个centroids与当前centroids的根号距离if norm < 0.1:  # 距离小于0.1,则跳出循环breakreturn count, centroids  # 返回count:各个中心点数据的个数;centroids:最终迭代后的中心点def show(im, count, centroids, k, imgpath):# 显示第一个子图:各个中心类的个数mpl.rcParams['font.family'] = "SimHei"  # 指定默认字体,才能显示中文字体ax1 = plt.subplot(221)  # 把figure分成2X2的4个子图,ax1为第一个子图index = np.arange(k)bar_width = 0.35opacity = 0.4plt.bar(index + bar_width / 2, count, bar_width, alpha=opacity, color='g', label='Num')plt.xlabel('Centroids')  # 设置横坐标plt.ylabel('Sum_Number')  # 设置纵坐标plt.title(u'points num of centroids')  # 设置标题plt.xticks(index + bar_width, ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'))  # 设置横坐标各个类plt.legend()  # 设置plt.tight_layout()ax2 = plt.subplot(222)img = Image.open(imgpath)x = k  # x坐标  通过对txt里的行数进行整数分解# 冒泡算法从大到小排序for i in range(k):max = count[i]m = ifor j in range(i, k):if count[j] > max:max = count[j]m = jif i != m:midcount = count[i]count[i] = count[m]count[m] = midcountmid = centroids[i]centroids[i] = centroids[m]centroids[m] = midimg = Image.new('RGBA', img.size, (255, 255, 255))print("\n============ the image size ===============")print (img.size)if x > 8:  # 取前8个中心类个数最大的颜色x = 8count_remove = 0  # 用语统计,剔除中心类中,类聚集的数据数小于5%的sum_count = float(sum(count))  # sum_count为总的数据数个数,也就是各个类聚集的总个数# 剔除中心类中,类聚集的数据数小于5%的for i in range(x):if count[x - i - 1] / sum_count < 0.05:count_remove += 1x = x - count_removeif x == 0:x = 1  # 确保有一个主颜色print("\n============ the points number of centroids ===============")print (count)# 图片显示的x y轴y = img.size[1]  # y坐标  x*y = 行数w = int(img.size[0] / x)# 显示前8个中心类个数最大的颜色for i in range(0, x):for j in range(i * w, (i + 1) * w):for k in range(0, y):rgb = centroids[i]img.putpixel((j, k), (int(rgb[0]), int(rgb[1]), int(rgb[2])))  # rgb转化为像素plt.xlabel(u'color')plt.title(u'main color sort')plt.yticks()plt.imshow(img)plt.tight_layout()# 显示原图,也就是要处理的图像plt.subplot(212)plt.title(u'origin image')plt.imshow(im)# 显示整个figureplt.show()def main():imgpath = '/Users/liuhuang31/Desktop/test2.jpg'data = loadImage(imgpath)  # Can be many different formats.选择这种方式导入图片k = 20  # 设置k均值初始点个数# 通过KMeans方法后返回的centroids,是k均值迭代后最终的中心点, count是这k个中心(类)的所包含的个数count, centroids = KMeans(k, data)print("\n================== the centroids RGB =================")for i in range(k):  # 因为有k个中心点h, s, v = centroids[i]r, g, b = hsvTRGB.Hsv2Rgb(h, s, v)centroids[i] = r, g, bprint (i, r, g, b)im = data[3]  # im = Image.open(path),就是得到图像对象show(im, count, centroids, k, imgpath)  # 显示图像if __name__ == '__main__':main()
 

三、前方高能,我要放图了!!也就是实验结果

由于k个初始中心点是根据图像的像素范围来random选择初始点的数值,所以每次运行的结果会有小差异!

1、对于传说中的粉红色(由于其特殊性,有些识别方法识别不出,可能原因是没根据图像的RGB来生成初始聚类中心,或者自己设定初始点)

2、

(1)初始点k=10

(2)初始点k=20 (可以看到和选择k=10还是有区别的哈)

3、这张图识别的稍微不准,白色RGB(255,255,255)识别出来为RGB(239,226,225),蓝色和黄色倒是识别得准确

四、再次强调哈,由于我python是现学现做,对于数据结构很多都不熟悉,所以转换来转换的,不过能自己写的,我都没调用库类,对自己更有锻炼,也挺适合我这样的新手,还有对一些图片识别稍微有误差,现在还在调试中QAQ。还有图像显示的第二个主颜色排序子图像代码不是很好。。

五、参考资料列表(良好的习惯^-^)
1、Python中的Numpy入门教程:http://www.jb51.net/article/49397.htm

2、颜色空间RGB与HSV(HSL)的转换:http://blog.csdn.net/jiangxinyu/article/details/8000999

3、python使用matplotlib绘解详解:http://www.pythontab.com/html/2013/pythonhexinbiancheng_0123/161.html

4、Matplotlib 画柱状图   (使用里面的方法来画图): http://blog.csdn.net/wishchin/article/details/24906175

5、RGB值转化图片(python PIL)   (使用里面的方法来画图)  http://www.tuicool.com/articles/mYBN7ju

python图像主色调(主颜色)提取,在hsv空间k均值迭代实现相关推荐

  1. python种颜色循环_python图像主色调(主颜色)提取,在hsv空间k均值迭代实现

    #!coding=utf-8fromPIL importImage importrgb2hsv importrandom asran importhsvTRGB frompylab import* # ...

  2. 基于K-Means聚类算法的主颜色提取

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 01.简介 本期我们将一起实现基于K-Means聚类算法的主色提取 ...

  3. 【主色提取】HSV 颜色空间与 RGB 颜色空间互相转化的公式和代码

    系列文章目录 第二章 主色提取之颜色空间转化 目录 系列文章目录 文章目录 前言 一.HSV 和 RGB 颜色空间 二.颜色转化 1. RGB to HSV 2. HSV to RGB 三. 完整代码 ...

  4. 基于图像的主颜色分析

    一般来说,直接分析RGB色彩域的颜色分布不是一个好的思路,我们一般转换到HSV域来分析.但是本文只要是应网友提问,实现最基本的RGB 色彩域的主颜色分析. 代码分为以下部分: 1.生成测试图片.为了测 ...

  5. 使用MFC实现将图像的RGB值转换到HSV空间,同时进行调节HSV,再将调节后的HSV值传进去转换到RGB空间实现图像在HSV空间中的色度、饱和度、亮度的调节

    工程上传到了github ,之前有一版忘记推送了,现在这个链接应该是没问题的了 工程的github链接 希望能帮到你. 文章内容: 1.回顾上文 2.实验步骤&要点提示&代码分析 3. ...

  6. python :图像细化、骨架提取

    (附上详细的解释及稍微修改的代码) 参考链接:http://www.cnblogs.com/xianglan/archive/2011/01/01/1923779.html 原博主的链接. 图像细化: ...

  7. python图像resize_Python图像resize前后颜色不一致问题

    今天帮师姐解决一个bug,测试了Python图像resize前后颜色不一致问题. 代码片段执行的功能:图像指定倍数超分辨率,输入为[0-1] float型数据,输出为格式不限的图像 bug:输入图像与 ...

  8. K均值 - 案例实现(python)

    K均值 K均值案例(python) 背景介绍 算法定义 K值的选取 案例实现(python) 数据集 代码实现 运行结果 总结 参考文献 K均值案例(python) k均值聚类算法(k-means c ...

  9. OpenCV打开摄像头,RGB转HSV空间

    文章目录 前言 一.使用OpenCV打开摄像头 二.使用OpenCV进行图像预处理 前言 有段时间没有更新了,最近主要在忙一个项目,用到了OpenCV,故想把一些常用代码在这里备份一下,一起学习. 环 ...

最新文章

  1. Python机器学习——Agglomerative层次聚类
  2. 开源依旧:再次分享一个进销存系统
  3. hystrix 配置 不生效_12、Feign整合断路器Hystrix
  4. 【深度学习】preprint版本 | 何凯明大神新作MAE | CVPR2022最佳论文候选
  5. Scrapy框架的学习(9.Scrapy中的CrawlSpider类的作用以及使用,实现优化的翻页爬虫)
  6. loading加载和layer.js
  7. python os.path.exists判断文件或文件夹是否存在
  8. android 自定义spnner弹出框,PopupWindow,ListView实现自定义Spinner
  9. Linux 网桥设置固定MAC
  10. 面试:用 Java 实现一个 Singleton 模式
  11. 初识THINKPHP--关于路径的问题(xampp下的htdocs为根目录)
  12. 关于Opencv出现的错误“ 0x000007fefdf6a06d (KernelBase.dll) Microsoft C++ 异常的几种尝试解决方式
  13. 使用echarts生成海友网企业全国分布地图
  14. ftp连接21端口出现的问题的解决方案
  15. 深入理解IGP-ISIS——ISIS邻居建立过程,影响ISIS邻居建立因素,ISIS报文
  16. C++ 统计n个学生三门课的平均成绩,统计各学生三门课的平均成绩。
  17. ESLint语法检查--semi(分号)规则
  18. SSM+基于Vue框架的在线投票系统的设计与实现 毕业设计-附源码221604
  19. arcgis中去除图层白底,并导出透明底tif
  20. 【Hive】窗口函数详解

热门文章

  1. python评价指标_详解分类评价指标和回归评价指标以及Python代码实现
  2. 同一计算机打印机无法连接,打印机无法连接到计算机怎么处理呢?
  3. elasticsearch部分常用操作
  4. UI仿应用宝app下载页面源码
  5. 【SSR】287- 从头开始,彻底理解服务端渲染原理
  6. artisan命令大全
  7. uniapp接入友盟(全网唯一 很全!!!)
  8. 计算机集成显卡和独立显卡,集成显卡和独立显卡的区别_哪个好
  9. 火车头php post提取内容,【火车头采集教程】轻而易举学会火车头采集(附带采集案例)...
  10. 筒仓计算表格_筒仓世界中的开源极客