Mit ein wenig Bastelei, this code (was ich Sie vermuten, dass vielleicht schon gesehen haben!) Beschleunigt werden kann, um knapp unter einem zweiten
Wenn Sie den kmeans(min_diff=...)
Wert auf etwa 10 erhöhen, produziert sie sehr ähnliche Ergebnisse in 900ms, aber läuft (im Vergleich zu etwa 5000-6000ms mit min_diff=1
)
Weiterhin ist die Größe der Vorschaubilder zu 100x100 Abnahme scheint nicht die Ergebnisse viel entweder zu beeinflussen, und nimmt die Laufzeit etwa 250 ms
Hier ist eine leicht abgewandelte Version des Kabeljaus e, die nur parametrisiert den min_diff
Wert und enthält einen schrecklichen Code, um eine HTML-Datei mit den Ergebnissen/Timing
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)
Zufallsauswahl eine Option sein könnte, zu generieren, wenn Sie wirklich wirklich – jozefg
brauchen Geschwindigkeit k-means ich denke, ist ziemlich Gute Wahl, weil Sie die Anzahl der Cluster vorher wissen. Vielleicht müssen Sie Ihre Implementierung optimieren, um eine bessere Leistung zu erzielen, oder sie in C oder C++ neu schreiben. – Lazin
Eine sehr schnelle und Open-Source-C++ - Implementierung von division-based Clustering finden Sie in meinem Blog-Post hier: http://www.modejong.com/blog/post17_divquant_clustering – MoDJ