Edit这是一种更快的方法,使用np.searchsorted
.
def rev_lookup_by_sort(img, palette):
M = (1 + palette.max())**np.arange(3)
p1d, ix = np.unique(palette @ M, return_index=True)
return ix[np.searchsorted(p1d, img @ M)]
正确性(相当于rev_lookup_by_dict()
在下面的原始答案中):
np.array_equal(
rev_lookup_by_sort(img, palette),
rev_lookup_by_dict(img, palette),
)
加速(对于 1000 x 1000 图像和 1000 种颜色的调色板):
orig = %timeit -o rev_lookup_by_dict(img, palette)
# 2.47 s ± 10.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
v2 = %timeit -o rev_lookup_by_sort(img, palette)
# 71.8 ms ± 93.7 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
>>> orig.average / v2.average
34.46
所以这个答案使用np.searchsorted
在该尺寸下速度提高了 30 倍。
原答案
最初的镜头给出了一个较慢的版本(希望我们能做得更好)。它使用一个dict
,其中键是作为元组的颜色。
def rev_lookup_by_dict(img, palette):
d = {tuple(v): k for k, v in enumerate(palette)}
def func(pix):
return d.get(tuple(pix), -1)
return np.apply_along_axis(func, -1, img)
img_p = rev_lookup_by_dict(img, palette)
请注意,“未找到颜色”表示为-1
in img_p
.
关于您的(修改后的)数据:
>>> img_p
array([[1, 4],
[0, 2],
[0, 3]])
更大的例子:
# setup
from math import isqrt
w, h = 1000, 1000
s = isqrt(w * h)
palette = np.random.randint(0, 256, (s, 3))
img = palette[np.random.randint(0, s, (w, h))]
Test:
img_p = rev_lookup_by_dict(img, palette)
>>> np.array_equal(palette[img_p], img)
True
Timing:
%timeit rev_lookup_by_dict(img, palette)
# 2.48 s ± 16.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
这确实很糟糕,但希望我们能做得更好。