我有一个 RGB 字节的 NumPy 图像,假设它是这个 2x3 图像:
img = np.array([[[ 0, 255, 0], [255, 255, 255]], [[255, 0, 255], [ 0, 255, 255]], [[255, 0, 255], [ 0, 0, 0]]])
我还有一个调色板,涵盖了图像中使用的每种颜色。假设它是这个调色板:
palette = np.array([[255, 0, 255], [ 0, 255, 0], [ 0, 255, 255], [ 0, 0, 0], [255, 255, 255]])
是否有某种将图像与调色板进行索引的组合(或反之亦然),可以给我一个与此等效的调色板图像?
img_p = np.array([[1, 4], [0, 2], [0, 3]])
为了进行比较,我知道反向操作非常简单。 palette[img_p]将给出相当于的结果img。 我试图弄清楚是否有相反方向的类似方法可以让 NumPy 完成所有繁重的工作。
palette[img_p]
img
我知道我可以逐个迭代所有图像像素并构建自己的调色板图像。我希望有更优雅的选择。
好的,我实施了以下各种解决方案,并在一个中等测试集上运行它们:20 张图像,每张 2000x2000 像素,带有 32 个元素的三字节颜色调色板。像素被赋予随机调色板索引。所有算法都在相同的图像上运行。
计时结果:
鉴于查找数组的内存消耗很大(如果有 alpha 通道,内存消耗会非常大),我将采用这种方法。如果您想将 RAM 用在查找数组上,那么np.searchsorted查找数组的速度会快得多。
np.searchsorted
从您的测试和分析中,基于查找表的方法显然是性能最佳的选择,尽管它对内存的要求很高。如果内存使用是一个关键限制,可以考虑次优的解决方案,例如使用 np.searchsorted 或优化版本的布尔匹配。
以下是一些补充说明,以及如何实现这两种方法:
创建一个查找数组,将每种可能的 RGB 颜色映射到其调色板索引。对大多数图像来说,RGB 颜色的范围是 (256^3)(16,777,216 种颜色),这会占用较大的内存空间(~64 MB,假设每个值为 4 字节)。
import numpy as np # 创建查找表 lookup = np.zeros((256, 256, 256), dtype=np.uint32) for idx, color in enumerate(palette): lookup[color[0], color[1], color[2]] = idx # 使用查找表生成调色板图像 img_p = lookup[img[..., 0], img[..., 1], img[..., 2]] print(img_p)
通过对调色板进行排序并使用 np.searchsorted 查找 RGB 值的位置。需要确保调色板是按顺序排列的。
# 将调色板排序 sorted_idx = np.lexsort((palette[:, 2], palette[:, 1], palette[:, 0])) sorted_palette = palette[sorted_idx] # 将图像展平并在调色板中查找索引 flat_img = img.reshape(-1, 3) indices = np.searchsorted(sorted_palette, flat_img, axis=0) # 恢复原始顺序并重新调整形状 img_p = indices.reshape(img.shape[:2]) print(img_p)
scipy.sparse
joblib
numexpr