有谁知道一个快速的算法来检测图像中的主要颜色?快速算法检测图像中的主要颜色?
我目前使用k-means与Python的PIL一起查找颜色,但速度很慢。一张200x200的图像需要10秒才能处理。我有几十万张图片。
有谁知道一个快速的算法来检测图像中的主要颜色?快速算法检测图像中的主要颜色?
我目前使用k-means与Python的PIL一起查找颜色,但速度很慢。一张200x200的图像需要10秒才能处理。我有几十万张图片。
一种快速的方法是简单地将色彩空间分成多个分箱,然后构造一个直方图。它的速度很快,因为每个像素只需要少量的决策,而且只需要在图像上进行一次扫描(并通过直方图查找最大值)。
更新:这里有一个粗略的图表来帮助解释我的意思。
在x轴上是分成不连续箱的颜色。 y轴显示每个bin的值,它是与该bin的颜色范围匹配的像素数。这个图像中有两个主要颜色,由两个峰值显示。
K-手段是完成这个任务的好选择,因为你知道的主色调数事前。你需要优化K-means。我认为你可以减少你的图像尺寸,只需将它缩小到100x100像素左右即可。查找你的算法在可接受的速度下工作的大小。另一种选择是在k均值聚类之前使用降维。
并试图找到快速k-means的实现。用python编写这样的东西是对python的滥用。不应该像这样使用它。
谢谢@Lazin。我会尝试将图像转换为100x100,这应该将运行时间减少4我认为。也许50x50也可以工作。 – bodacydo
有了一点修修补补,this code(我怀疑你可能已经看到了!)可以略低于第二
如果增加kmeans(min_diff=...)
值约10加速到,它产生的结果非常相似,但在900毫秒运行(相比与min_diff=1
约5000-6000ms)
进一步降低缩略图为100x100的大小似乎并没有太多或者影响结果,并采取了运行时间约250ms的
这是一个稍微调整的鳕鱼版本E,这只是parameterises的min_diff
价值,并包含了一些可怕的代码来生成与结果的HTML文件/定时
from collections import namedtuple
from math import sqrt
import random
try:
import Image
except ImportError:
from PIL import Image
Point = namedtuple('Point', ('coords', 'n', 'ct'))
Cluster = namedtuple('Cluster', ('points', 'center', 'n'))
def get_points(img):
points = []
w, h = img.size
for count, color in img.getcolors(w * h):
points.append(Point(color, 3, count))
return points
rtoh = lambda rgb: '#%s' % ''.join(('%02x' % p for p in rgb))
def colorz(filename, n=3, mindiff=1):
img = Image.open(filename)
img.thumbnail((200, 200))
w, h = img.size
points = get_points(img)
clusters = kmeans(points, n, mindiff)
rgbs = [map(int, c.center.coords) for c in clusters]
return map(rtoh, rgbs)
def euclidean(p1, p2):
return sqrt(sum([
(p1.coords[i] - p2.coords[i]) ** 2 for i in range(p1.n)
]))
def calculate_center(points, n):
vals = [0.0 for i in range(n)]
plen = 0
for p in points:
plen += p.ct
for i in range(n):
vals[i] += (p.coords[i] * p.ct)
return Point([(v/plen) for v in vals], n, 1)
def kmeans(points, k, min_diff):
clusters = [Cluster([p], p, p.n) for p in random.sample(points, k)]
while 1:
plists = [[] for i in range(k)]
for p in points:
smallest_distance = float('Inf')
for i in range(k):
distance = euclidean(p, clusters[i].center)
if distance < smallest_distance:
smallest_distance = distance
idx = i
plists[idx].append(p)
diff = 0
for i in range(k):
old = clusters[i]
center = calculate_center(plists[i], old.n)
new = Cluster(plists[i], center, old.n)
clusters[i] = new
diff = max(diff, euclidean(old.center, new.center))
if diff < min_diff:
break
return clusters
if __name__ == '__main__':
import sys
import time
for x in range(1, 11):
sys.stderr.write("mindiff %s\n" % (x))
start = time.time()
fname = "akira_940x700.png"
col = colorz(fname, 3, x)
print "<h1>%s</h1>" % x
print "<img src='%s'>" % (fname)
print "<br>"
for a in col:
print "<div style='background-color: %s; width:20px; height:20px'> </div>" % (a)
print "<br>Took %.02fms<br> % ((time.time()-start)*1000)
随机抽样,如果你真的真的需要速度 – jozefg
我觉得K-手段可能是一种选择是相当因为您事先知道群集数。也许你需要优化你的实现以获得更好的性能,或者用C或C++重写它。 – Lazin
基于划分聚类的非常快速和开源的C++实现可以在我的博客文章中找到:http://www.modejong.com/blog/post17_divquant_clustering – MoDJ