Videos
Just give the number_of_colors variable a number as big as possible. System will process it properly.
import colorgram as cg
color_list = cg.extract("dot-img.jpg", 2 ** 32)
color_palette = []
for count in range(len(color_list)):
rgb = color_list[count]
color = rgb.rgb
color_palette.append(color)
The source code in colorgram:
def get_colors(samples, used, number_of_colors):
pixels = 0
colors = []
number_of_colors = min(number_of_colors, len(used))
for count, index in used[:number_of_colors]:
pixels += count
color = Color(
samples[index] // count,
samples[index + 1] // count,
samples[index + 2] // count,
count
)
colors.append(color)
for color in colors:
color.proportion /= pixels
return colors
You can work this after answers from given users but it won't work because your format is "RGB". If you want to use that kind of color, you should convert it. For example:
import colorgram as cg
import turtle as t
colors = cg.extract('pink_image.jpg', 25)
rgb_colors = []
t.speed(100)
screen = t.Screen()
for coloring in colors:
r = coloring.rgb.r
g = coloring.rgb.g
b = coloring.rgb.b
new_color = (r, g, b)
rgb_colors.append(new_color)
print(rgb_colors)
Look output where it stays above after yours. When you look at your own code, you can see that kind of output:
>> [Rgb(r=245, g=243, b=238),Rgb(r=247, g=242, b=244)] you can't use this like that. You should convert it like my code. I hope that you understand it.
Is there a tool / method in a given drawing software of extracting all of the colours from an image, mapped onto a colour wheel?
The closest I have found is hexcolor but it produces an unordered list of colours which is hard to parse. Other sites max out at 10 or so colours extracted.
My desire is to see, on a colour wheel, what colours an artist used in a given work. Is there a better way of doing this?
I have a vague memory of seeing this kind of software mentioned for use with analyzing colour in film screencaps but may be wrong.
Thank you!
One of the possibilities is to use webcolors package. I modified your code to find the name of the closest matching color on the color palette:
import cv2
import numpy as np
from PIL import Image
from sklearn.cluster import KMeans
import webcolors
from webcolors import CSS3_HEX_TO_NAMES, hex_to_rgb
image_path = "Photo1.png"
num_colors = 5
num_clusters = 5
def get_dominant_colors(image_path, num_colors=10, num_clusters=5):
image = Image.open(image_path)
image = image.resize((200, 200))
image = image.convert('RGB')
img_array = np.array(image)
pixels = img_array.reshape(-1, 3)
kmeans = KMeans(n_clusters=num_clusters, random_state=0)
labels = kmeans.fit_predict(pixels)
centers = kmeans.cluster_centers_
color_counts = {}
for label in np.unique(labels):
color = tuple(centers[label].astype(int))
color_counts[color] = np.count_nonzero(labels == label)
sorted_colors = sorted(color_counts.items(), key=lambda x: x[1], reverse=True)
dominant_colors = [color for color, count in sorted_colors[:num_colors]]
color_occurrences = [count for color, count in sorted_colors[:num_colors]]
dominant_colors_hex = ['#%02x%02x%02x' % color for color in dominant_colors]
return dominant_colors_hex, color_occurrences
dominant_colors, color_occurrences = get_dominant_colors(image_path, num_colors, num_clusters)
def closest_color(hex):
colors = {}
for key, name in CSS3_HEX_TO_NAMES.items():
r_c, g_c, b_c = hex_to_rgb(key)
rd = (int(hex[1:3], 16) - r_c) ** 2
gd = (int(hex[3:5], 16) - g_c) ** 2
bd = (int(hex[5:7], 16) - b_c) ** 2
colors[(rd + gd + bd)] = name
return colors[min(colors.keys())]
print("Dominant colors: ")
for col in dominant_colors:
col_name = closest_color(col)
print(col_name)
palette_height = 100
palette_width = 100 * num_colors
palette = np.zeros((palette_height, palette_width, 3), dtype=np.uint8)
start_x = 0
for color_hex in dominant_colors:
color_rgb = tuple(int(color_hex[i:i+2], 16) for i in (1, 3, 5))
end_x = start_x + 100
palette[:, start_x:end_x] = color_rgb
start_x = end_x
palette_image = Image.fromarray(palette)
palette_bgr = cv2.cvtColor(np.array(palette_image), cv2.COLOR_RGB2BGR)
cv2.imshow("Palette", palette_bgr)
cv2.waitKey(0)
cv2.destroyAllWindows()
You can swap the color mapping from CSS3 to HTML4, for example. It includes names for the 16 base colors Here you can find more. Just replace the line
for key, name in CSS3_HEX_TO_NAMES.items():
with
for key, name in HTML4_HEX_TO_NAMES.items():
This is the code I ended up using when I had to figure something similar out.
The above image shows that the .HTML table it generates upon hovering show sthe frequency and color name / hex value of the color. Also, if you click the color block it'll copy that hex value.
[import cv2
import numpy as np
from PIL import Image
from sklearn.cluster import KMeans
from webcolors import CSS3_HEX_TO_NAMES, hex_to_rgb
# Specify the path to the image file
image_path = "Picture.png"
def get_dominant_colors(image_path, num_colors=10, num_clusters=5):
"""
Utilizes KMeans clustering to identify dominant colors in an image.
"""
image = Image.open(image_path)
image = image.resize((200, 200))
image = image.convert('RGB')
img_array = np.array(image)
pixels = img_array.reshape(-1, 3)
kmeans = KMeans(n_clusters=num_clusters, random_state=0)
labels = kmeans.fit_predict(pixels)
centers = kmeans.cluster_centers_
color_counts = {}
for label in np.unique(labels):
color = tuple(centers\[label\].astype(int))
color_counts\[color\] = np.count_nonzero(labels == label)
sorted_colors = sorted(color_counts.items(), key=lambda x: x\[1\], reverse=True)
dominant_colors = \[color for color, count in sorted_colors\[:num_colors\]\]
color_occurrences = \[count for color, count in sorted_colors\[:num_colors\]\]
dominant_colors_hex = \['#%02x%02x%02x' % color for color in dominant_colors\]
return dominant_colors_hex, color_occurrences
def closest_color(hex):
"""
Finds the closest matching color name from CSS3 colors.
"""
colors = {}
for key, name in CSS3_HEX_TO_NAMES.items():
r_c, g_c, b_c = hex_to_rgb(key)
rd = (int(hex\[1:3\], 16) - r_c) ** 2
gd = (int(hex\[3:5\], 16) - g_c) ** 2
bd = (int(hex\[5:7\], 16) - b_c) ** 2
colors\[(rd + gd + bd)\] = name
return colors\[min(colors.keys())\]
def rgb_to_hex(rgb):
"""
Converts RGB tuple to hexadecimal color representation.
"""
return '#{:02x}{:02x}{:02x}'.format(rgb\[0\], rgb\[1\], rgb\[2\])
def get_colors(image_path):
"""
Retrieves all distinct colors present in the image.
"""
image = Image.open(image_path)
image = image.resize((200, 200))
image = image.convert('RGB')
# Fetch pixel colors
pixels = list(image.getdata())
# Identify unique colors
unique_colors = list(set(pixels))
return unique_colors
# Obtain dominant colors
dominant_colors_hex, color_occurrences = get_dominant_colors(image_path)
# Display extracted color names
print("Extracted Colors:")
for col_hex in dominant_colors_hex:
col_name = closest_color(col_hex)
print(col_name)
# Write distinct colors and their counts to a text file
with open(image_path.split('.')\[0\] + "_Color_List.txt", 'w') as f:
for col_hex, col_occ in zip(dominant_colors_hex, color_occurrences):
col_name = closest_color(col_hex)
print(f"{col_name} \[{col_occ}\]", file=f)
# Convert colors to hexadecimal representation
distinct_colors = get_colors(image_path)
distinct_colors_hex = \[rgb_to_hex(color) for color in distinct_colors\]
# Generate HTML color table
html_content = "<!DOCTYPE html>\n<html>\n<head>\n<style>\ntable {\nborder-collapse: collapse;\n}\ntd {\nborder: 1px solid black;\nwidth: 15px;\nheight: 15px;\n}\n</style>\n<script>\nfunction copyColor(hex) {\n var dummy = document.createElement('textarea');\n document.body.appendChild(dummy);\n dummy.value = hex;\n dummy.select();\n document.execCommand('copy');\n document.body.removeChild(dummy);\n}\n</script>\n</head>\n<body>\n<table>"
html_content += "\n<tr>"
for color, count, hex_code in zip(dominant_colors_hex, color_occurrences, distinct_colors_hex):
color_name = closest_color(color)
html_content += f"\n<td title='{color_name} ({hex_code}), {count} times' style='background-color:{color}' onclick='copyColor(\"{color}\")'></td>"
html_content += "\n</tr>\n</table>\n</body>\n</html>"
# Write HTML content to file
with open(image_path.split('.')\[0\] + "_Color_Table.html", 'w') as f:
f.write(html_content)][1]