I need some support in adding details to my code. In my code, I am just using 1 image (see attachment, called "Photo1").
When I run the whole code, it will give me the following output:
,"Dominant Colors:
['#263f6c', '#4c5d85', '#d3d6d8', '#9db1c6', '#7388a7']"
I don't want the output as codes, I want to know exactly which colors are the dominant colors (example: red, blue, black) and return it in a column called "extracted colors"
How can I add these details in my code?
import cv2
import numpy as np
from PIL import Image
from sklearn.cluster import KMeans
image_path = "Photo1.jpg"
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)
print("Dominant Colors:")
print(dominant_colors)
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()
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():