如何在 RGB 图像上使用调色板提取主色?

How to extract dominant colors using palettes on RGB images?

我正在尝试构建一个可以从图像中提取主色的模块。例如,我正在尝试从此旗帜图像中提取四种颜色:

getpalettegetcolors 方法 return None,如果我尝试在 RGB 模式下使用它们。 (我试过设置 maxcolors,我仍然得到 None。)

paletted = img.convert('RGB', palette=Image.ADAPTIVE, colors=4)
print(paletted.getpalette())
print(paletted.getcolors(maxcolors=256))
# None
# None

如果我转换成P模式,我可以使用这些模块,但是我失去了黄色。

paletted = img.convert('P', palette=Image.ADAPTIVE, colors=4)
paletted.show()

我做错了什么?

首先,下面的是行不通的,或者更确切地说,是被忽略了:

paletted = img.convert('RGB', palette=Image.ADAPTIVE, colors=4)

来自 Image.convert 上的文档:

palette – Palette to use when converting from mode "RGB" to "P". Available palettes are WEB or ADAPTIVE.

您正在从 RGB 转换为 RGB,因此 palettecolors 参数将被忽略。

下一个问题,这也阻止了正确转换到模式 P:您的 JPG 图像带有 JPG 瑕疵。您的图像包含的颜色比您预期的要多得多。来自 Image.getcolors 上的文档:

maxcolors – Maximum number of colors. If this number is exceeded, this method returns None. The default limit is 256 colors.

增加maxcolors(某些完整的 24 位 RGB 图像可能的最大不同颜色数为 224),并检查四种最突出的颜色:

from PIL import Image

img = Image.open('47ckF.jpg')
n_dom_colors = 4
dom_colors = sorted(img.getcolors(2 ** 24), reverse=True)[:n_dom_colors]
print(dom_colors)
# [(135779, (0, 0, 0)), (132476, (0, 0, 254)), (109155, (254, 0, 0)), (2892, (251, 2, 0))]

您会得到纯黑色、近纯蓝色、近纯红色和红色变体。黄色在哪里?神器!你有大量的黑色、蓝色和红色,它们都比第一种黄色更突出。例如,即使设置 n_dom_colors = 20 也不会显示第一个黄色。

如何实现,您可能有什么想法?看看 Image.quantize,它会给你一个模式 P 使用颜色量化的图像:

from PIL import Image

img = Image.open('47ckF.jpg')
img = img.quantize(colors=4, kmeans=4).convert('RGB')
n_dom_colors = 4
dom_colors = sorted(img.getcolors(2 ** 24), reverse=True)[:n_dom_colors]
print(dom_colors)
# [(139872, (1, 0, 1)), (138350, (0, 0, 253)), (134957, (252, 1, 1)), (3321, (253, 240, 12))]

你得到近纯黑色、近纯蓝色、近纯红色和黄色变体!

供参考,量化和重新转换的图像:

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.16299-SP0
Python:        3.9.1
PyCharm:       2021.1.1
Pillow:        8.2.0
----------------------------------------