我正在研究一些用于将图像转换为NES调色板的代码。我目前的代码有些成功,但非常慢。
我是通过使用毕达哥拉斯'定理。我使用RGB颜色值作为3D空间中的坐标并以此方式进行。调色板中与像素的RGB距离最小的颜色是使用的颜色。
class image_filter():
def load(self,path):
self.i = Image.open(path)
self.i = self.i.convert("RGB")
self.pix = self.i.load()
def colour_filter(self,colours=NES):
start = time.time()
for y in range(self.i.size[1]):
for x in range(self.i.size[0]):
pixel = list(self.pix[x,y])
distances = []
for colour in colours:
distance = ((colour[0]-pixel[0])**2)+((colour[1]-pixel[1])**2)+((colour[2]-pixel[2])**2)
distances.append(distance)
pixel = colours[distances.index(sorted(distances,key=lambda x:x)[0])]
self.pix[x,y] = tuple(pixel)
print "Took "+str(time.time()-start)+" seconds."
f = image_filter()
f.load("C:\\path\\to\\image.png")
f.colour_filter()
f.i.save("C:\\path\\to\\new\\image.png")
使用清单:
NES = [(124,124,124),(0,0,252),
(0,0,188),(68,40,188),
(148,0,132),(168,0,32),
(168,16,0),(136,20,0),
(80,48,0),(0,120,0),
(0,104,0),(0,88,0),
(0,64,88),(0,0,0),
(188,188,188),(0,120,248),
(0,88,248),(104,68,252),
(216,0,204),(228,0,88),
(248,56,0),(228,92,16),
(172,124,0),(0,184,0),
(0,168,0),(0,168,68),
(0,136,136),(248,248,248),
(60,188,252),(104,136,252),
(152,120,248),
(248,120,248),(248,88,152),
(248,120,88),(252,160,68),
(184,248,24),(88,216,84),
(88,248,152),(0,232,216),
(120,120,120),(252,252,252),(164,228,252),
(184,184,248),(216,184,248),
(248,184,248),(248,164,192),
(240,208,176),(252,224,168),
(248,216,120),(216,248,120),
(184,248,184),(184,248,216),
(0,252,252),(216,216,216)]
这会产生以下输入:
和输出:
这需要14到20秒,这对于预期的应用来说太长了。有谁知道有什么方法可以大大加快这个速度?
作为一个想法,我认为有可能为此使用numpy数组;但是我对numpy数组一点都不熟悉,无法将它拉下来。
如果可能的话,我也想尝试避免使用scipy - 我知道,至少在Windows下,安装起来很麻烦,而且更愿意避开。
答案 0 :(得分:3)
<强>方法#1:我们可以使用Scipy's cdist
来获得欧几里德距离,然后寻找最小距离Arg和由此选择适当的颜色
因此,以NumPy数组作为输入,我们将有一个类似的实现 -
from scipy.spatial.distance import cdist
out = colours[cdist(pix.reshape(-1,3),colours).argmin(1)].reshape(pix.shape)
方法#2:这是broadcasting
和np.einsum
的另一种方法 -
subs = pix - colours[:,None,None]
out = colours[np.einsum('ijkl,ijkl->ijk',subs,subs).argmin(0)]
PIL /列表和NumPy阵列之间的接口
要接受通过PIL读取的图像,请使用:
pix = np.asarray(Image.open('input_filename'))
使用colours
作为数组:
colours = np.asarray(NES)
# .... Use one of the listed approaches and get out as output array
输出图像:
i = Image.fromarray(out.astype('uint8'),'RGB')
i.save("output_filename")
使用给定调色板NES
-