有没有一种有效的方法可以将RGB图像的主要颜色进行二进制处理?

问题描述 投票:0回答:1

我正在做一个项目,在这个项目中,粗略地说,我想从RGB图像中提取顶部的 n 从图像中提取颜色,以及衡量每种颜色的相对受欢迎程度。我开始使用PIL和 getcolors() 方法,但很快就遇到了转换(频率、颜色)元组的问题。getcolors() 返回到 RGB 值--甚至返回到 PIL 调色板中的颜色。也就是说,PIL的结果是它将RGB值映射到一个单一的维度上。

from PIL import Image
import numpy as np

filename ='test_img.png'

imgP = Image.open('/Users/JohnDoe/Documents' + filename).convert('P')

totalpix = imgP.size[0]*imgP.size[1]

# Get colors
colors = imgP.getcolors()
colors.sort(key=itemgetter(0))
colors.reverse()

colorfreq = np.zeros(len(colors))
colorindex = np.zeros_like(colorfreq)

# Determine the most common colors and their indices
for i, c in enumerate(colors):
    colorfreq[i] = c[0]
    colorindex[i] = c[1]

    if colorfreq.sum() > totalpix*0.95:
        colorfreq = np.delete(np.unique(colorfreq), 0)
        colorindex = np.delete(np.unique(colorindex), 0)
        print("Number of colors extracted: " + str(colorfreq.shape[0]))
        break

遇到上面的路障后,我想我应该转向matplotlib。然而,虽然得到一个RGB值的数组已经很容易了,但我不知道如何将它适当地bin化。我研究了matplotlib的colormaps和 柱状图归一化 但这对于已经是彩色的图像来说,似乎并不适用。接下来想到的是创建RGB值的 "bin",然后用这种方法提取主色。不过我不知道这是否可行,总之怀疑有更好的方法。

import matplotlib.image as mpimg
import numpy as np

filename ='test_img.png'

# Read image and remove the alpha values
img = mpimg.imread('/Users/JohnDoe/Documents/' + filename)
img = img[:, :, 0:3]

谢谢你的意见!我正在做一个项目。

python image-processing colors python-imaging-library rgb
1个回答
1
投票

如果有关系的话,我正好有枕头6.2.1。

此外,文件中还提供了 getcolors() 指出,如果图像中的实际颜色数量超过了该图像中的 maxcolors 参数,则 None 被返回。

所以,我自己的实验是这样的。

img = Image.open(filename)
im_rgb = img.convert('RGB')
colors = im_rgb.getcolors(maxcolors=200000)   # A suitably large number empirically determined 
print(len(colors))
colors = sorted(colors, key = lambda x:-x[0])
print(im_rgb)
print(colors[:12])

输出

21407
<PIL.Image.Image image mode=RGB size=144x256 at 0x3E9DE90>
[(43, (36, 30, 14)), (42, (38, 29, 12)), (39, (35, 29, 13)), (37, (41, 33, 14)), (35, (42, 34, 15)), (32, (37, 28, 11)), (32, (2, 2, 2)), (32, (44, 36, 17)), (31, (37, 30, 12)), (30, (31, 25, 11)), (29, (43, 35, 16)), (28, (46, 35, 15))]

正如你所看到的,图像恰好有21407种不同的颜色 我打印出了最上面的12种。每一种颜色都是一个元组,大概的形式是 (r, g, b)


0
投票

这是我最后能够弄清楚的,使用了 np.histogramdd() 以及@quamrana的帮助解答。

谢谢你的帮助! (不过,还是很感谢任何效率方面的建议。)

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from math import log10, sqrt
from numpy.random import default_rng

im_rgb = Image.open(filename).convert('RGB')
colors = im_rgb.getcolors(maxcolors=200000)   # A suitably large number empirically determined

colors = sorted(colors, key = lambda x:-x[0])

threshold = 250
near_white = [c for c in colors if c[1][0] > threshold and c[1][1] > threshold and c[1][2] > threshold]
removed = 0
for c in near_white:
    colors.pop(colors.index(c))
    removed += 1

print(str(removed) + " colors near white removed.")

RGB = [[c[1][i]/255 for i in range(3)] for c in colors]
freq =[c[0] for c in colors]

fig, ax = plt.subplots()

bins = 10
hist, binedges = np.histogramdd(np.array(RGB), bins=bins, weights=freq)

rg = default_rng(12345)
plot_width = 50
plot_height = plot_width
for x, _ in enumerate(binedges[0][0:-1]):
    for y, _ in enumerate(binedges[1][0:-1]):
        for z, _ in enumerate(binedges[2][0:-1]):
            rect_x = rg.random() * plot_width - plot_width / 2
            rect_y = rg.random() * plot_height - plot_height / 2
            rect_w = 100*log10(1+ sqrt(hist[x, y, z] / hist.sum()))
            rect_h = rect_w
            c = (binedges[0][x] + 0.5/bins, binedges[1][y] + 0.5/bins, binedges[2][z] +  0.5/bins)
            ax.add_patch(plt.Rectangle((rect_x, rect_y), rect_w, rect_h, color=c, alpha=1.))

ax.set_aspect('equal')
ax.set_xlim(auto=True)
ax.set_ylim(auto=True)
ax.plot()
plt.show()
© www.soinside.com 2019 - 2024. All rights reserved.