Helloo,
我正在创建一个项目,试图在其中提取图像中颜色的数量作为输出。我已经能够获得颜色的数量和它们的名称以及它们的数量,但是问题是它遍历每个像素,即使是白色和黑色,它也会获得所有颜色的不同程度。
所以,这是我的问题,如何扩展度数,使其仅显示白色而不显示不同等级的白色,是否有更好的方法来提取图像中颜色的数量及其数量和百分比? / p>
总结:对于仅是2种颜色(以视力为准)的图像,输出的颜色太多了,我想得到只封闭基本可见颜色的结果。
我还只包括了大于1%的颜色
colors_dict = {..."FE0000": "Red","C71585": "Red-violet"} <------------ huge dictionary of colors this is just one example
img = Image.open("Moustiques_Design_2.JPG")
size = w, h = img.size
data = img.load()
colors = []
for x in range(w):
for y in range(h):
color = data[x, y]
hex_color_lower = ''.join([hex(c)[2:].rjust(2, '0') for c in color])
hex_color = hex_color_lower.upper()
colors.append(hex_color)
total = w * h
color_hex = []
color_count = []
color_percent = []
df = pd.DataFrame()
for color, count in Counter(colors).items():
percent = count/total * \
100 # Do not make it int. Majority of colors are < 1%, unless you want >= 1%
if percent > 1:
color_hex.append(color)
color_count.append(count)
color_percent.append(percent)
df['color'] = color_hex
df['count'] = color_count
df['percent'] = color_percent
df['color_name'] = df['color'].map(colors_dict)
df.to_excel(r'C:\Users\User\Desktop\Project\export_dataframe.xlsx',
index=False, header=True)
print('done')
这是结果:
必需的输出
答案 0 :(得分:1)
好的,我想我已经找到了您的问题的解决方案,我不会说这是最有效的解决方案,但是它应该可以工作
我所做的是,首先,我对您的代码进行了一些修改,如果颜色在colors_dict
中,则首先对颜色进行排序,然后按其计数进行排序,因此当颜色不在{{1 }}出现,并且计数百分比小于1%,该程序会自动忽略其余颜色,因此不会迭代所有颜色
然后我添加了两个函数:colors_dict
和color_bounds(color, bound)
check_bounds(bounds, color_hex)
的作用是(使用输入范围)获得与输入颜色相似的颜色范围(例如,范围为2),该函数将返回color_bounds
和{ {1}}代表颜色C93AE0
然后C536DC
使用颜色的边界,并检查是否有任何更频繁使用的颜色(已使用的颜色)在边界内,如果是,则不会添加
C738DE
再给我一点时间,我可以使代码更高效,但是到目前为止,我认为我已经回答了您的问题,请告诉我这是否有帮助:D
PS您应该能够调整check_bounds
中的边界以包含更多或更少的颜色
我在代码中留给import pandas as pd
from PIL import Image
from collections import Counter
def color_bounds(color, bound):
r, g, b = color[:2], color[2:4], color[4:]
bounds = int(r, 16), int(g, 16), int(b, 16)
upper_bounds = []
lower_bounds = []
# upper_bounds = ""
# lower_bounds = ""
for value in bounds:
upper = value + bound
lower = value - bound
while upper > 255:
upper -= 1
while lower < 0:
lower += 1
"""
upper = hex(upper).split("x")[-1].upper()
lower = hex(lower).split("x")[-1].upper()
if len(upper) == 1:
upper = "0" + upper
if len(lower) == 1:
lower = "0" + lower
"""
upper_bounds.append(upper)
lower_bounds.append(lower)
# upper_bounds += upper
# lower_bounds += lower
return (upper_bounds, lower_bounds)
def check_bounds(bounds, colors):
upper_bounds = bounds[0]
lower_bounds = bounds[1]
for color in colors:
r, g, b = color[:2], color[2:4], color[4:]
bounds = int(r, 16), int(g, 16), int(b, 16)
similar = [False, False, False]
for i in range(0, 3):
if bounds[i] <= upper_bounds[i] and bounds[i] >= lower_bounds[i]:
similar[i] = True
if similar[0] and similar[1] and similar[2]:
return False
return True
colors_dict = {"000000": "Black", "FFFFFF": "White"} #<------------ huge dictionary of colors this is just one example
img = Image.open("image.jpg")
size = w, h = img.size
data = img.load()
colors = []
for x in range(w):
for y in range(h):
color = data[x, y]
hex_color_lower = ''.join([hex(c)[2:].rjust(2, '0') for c in color])
hex_color = hex_color_lower.upper()
colors.append(hex_color)
total = w * h
color_hex = []
color_count = []
color_percent = []
df = pd.DataFrame()
def key(i):
try:
color = colors_dict[i[0]]
except:
color = ""
return color, i[1]
colors = Counter(colors).items()
for color, count in sorted(colors, key=key, reverse=True):
percent = count/total * \
100 # Do not make it int. Majority of colors are < 1%, unless you want >= 1%
if percent > 1:
# New functions to ignore colours that are similar to more frequent colours
# Make the bound value bigger to include more colours and smaller to include less
bounds = color_bounds(color, 16)
if check_bounds(bounds, color_hex):
color_hex.append(color)
color_count.append(count)
color_percent.append(percent)
else: break
df['color'] = color_hex
df['count'] = color_count
df['percent'] = color_percent
df['color_name'] = df['color'].map(colors_dict)
df.to_excel(r'export_dataframe.xlsx',
index=False, header=True)
print('done')
的PPS将边界转换回十六进制,如果您想这样做,则只需要在color_bounds
中添加一个函数即可将其转换回到十进制rgb值
答案 1 :(得分:1)
我建议使用numpy。类似于:
from PIL import Image
import numpy as np
img = Image.open("Moustiques_Design_2.JPG")
data = np.array(img.getdata()) # data is a numpy array of shape (nb_pixels, 3)
colors = np.array([
[255,255,255], # white
[0,0,0], # black
[254,0,0], # red
[199,21,133], # C71585 "Red-violet"
# etc.
])
# difference of each pixel to each color (thanks to numpy it's fast)
differences = data.reshape((data.shape[0], 1, 3)) - colors
distances = np.linalg.norm(differences, axis=(2)) # distance of each pixel to each color
closest_color_indices = np.argmin(distances, axis=1) # index (in array colors) of the closest color to each pixel
color_counts = collections.Counter(closest_color_indices)
然后,color_counts
是每种颜色的近似该颜色的像素数。例如,如果colors_counts = Counter({0: 36675, 3: 5612, 2: 5864, 1: 2474})
,则意味着36675像素最接近白色(比字典中的任何其他颜色),2474近似黑色,5864近似红色,5612接近红紫色等,然后可以计算百分比并以Excel形式输出,就像您在代码中所做的一样:
color_names = ['white', 'black', 'red', 'red-violet']
col_hex = []
col_count = []
col_percent = []
col_names = []
total = sum(color_counts.values())
for index, count in color_counts.items():
print(index, count)
percent = count/total * \
100 # Do not make it int. Majority of colors are < 1%, unless you want >= 1%
if percent > 1:
rgb = tuple(colors[index])
col_hex.append('%02x%02x%02x' % (rgb))
col_count.append(count)
col_percent.append(percent)
col_names.append(color_names[index])
df = pd.DataFrame()
df['color'] = col_hex
df['count'] = col_count
df['percent'] = col_percent
df.to_excel(r'C:\Users\User\Desktop\Project\export_dataframe.xlsx',
index=False, header=True)
print('done')
颜色和像素之间的每个差异都是3个值的向量。您可能需要考虑其他色彩空间,例如YUV或CIE。