增加图像中检测到的颜色范围

时间:2020-10-31 22:39:25

标签: python pandas

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')

这是结果:

enter image description here

必需的输出

enter image description here

2 个答案:

答案 0 :(得分:1)

好的,我想我已经找到了您的问题的解决方案,我不会说这是最有效的解决方案,但是它应该可以工作

我所做的是,首先,我对您的代码进行了一些修改,如果颜色在colors_dict中,则首先对颜色进行排序,然后按其计数进行排序,因此当颜色不在{{1 }}出现,并且计数百分比小于1%,该程序会自动忽略其余颜色,因此不会迭代所有颜色

然后我添加了两个函数:colors_dictcolor_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。