Với một chút mày mò, this code (mà tôi nghi ngờ bạn có thể đã nhìn thấy!) Có thể được tăng tốc lên đến chỉ dưới một giây
Nếu bạn tăng giá trị kmeans(min_diff=...)
đến khoảng 10, nó tạo ra kết quả rất giống nhau , nhưng chạy trong 900ms (so với khoảng 5000-6000ms với min_diff=1
)
tiếp tục giảm kích thước của hình thu nhỏ để 100x100 dường như không ảnh hưởng đến kết quả gì nhiều, và phải mất thời gian chạy khoảng 250ms
Đây là một phiên bản hơi tinh chỉnh của cá tuyết e, mà chỉ parameterises giá trị min_diff
, và bao gồm một số mã khủng khiếp để tạo ra một tập tin HTML với kết quả/thời gian
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)
lấy mẫu ngẫu nhiên có thể là một lựa chọn nếu bạn thực sự thực sự cần tốc độ – jozefg
Tôi nghĩ k-means là khá lựa chọn tốt vì bạn biết số cụm trước. Có lẽ bạn cần tối ưu hóa việc triển khai của bạn để đạt được hiệu suất tốt hơn hoặc viết lại nó trong C hoặc C++. – Lazin
Việc triển khai phân vùng dựa trên phân vùng C++ rất nhanh và mã nguồn mở có thể tìm thấy tại bài đăng blog của tôi tại đây: http://www.modejong.com/blog/post17_divquant_clustering – MoDJ