有没有一种有效的方法来对 RGB 图像中的主要颜色进行分箱?
Is there an efficient way to bin the main colors from an RGB image?
我正在从事一个项目,简单地说,我想从图像中提取前 n 种颜色以及每种颜色的相对受欢迎程度。我开始使用 PIL 和 getcolors()
方法,但很快 运行 变成了将(频率,颜色)元组 getcolors()
returns 转换回 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 值,但我不确定如何适当地对它进行分类。我查看了 matplotlib 颜色映射和 colormap normalization 但这似乎与已经彩色的图像无关。接下来想到的是创建 "bins" 的 RGB 值并以这种方式提取主要颜色。不过,我不知道这是否可行,无论如何我怀疑有更好的方法。
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]
感谢您的意见!
如果重要的话,我正好有枕头 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)
的形式
这是我最终能够弄清楚的,利用 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()
我正在从事一个项目,简单地说,我想从图像中提取前 n 种颜色以及每种颜色的相对受欢迎程度。我开始使用 PIL 和 getcolors()
方法,但很快 运行 变成了将(频率,颜色)元组 getcolors()
returns 转换回 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 值,但我不确定如何适当地对它进行分类。我查看了 matplotlib 颜色映射和 colormap normalization 但这似乎与已经彩色的图像无关。接下来想到的是创建 "bins" 的 RGB 值并以这种方式提取主要颜色。不过,我不知道这是否可行,无论如何我怀疑有更好的方法。
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]
感谢您的意见!
如果重要的话,我正好有枕头 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)
这是我最终能够弄清楚的,利用 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()