22import requests
33from io import BytesIO
44import numpy as np
5+ import os
6+ import json
57from sklearn .cluster import KMeans
68
7- def get_discord_color (image_url , num_colors = 5 , crop_percentage = 0.5 ):
9+ def cache_color (image_url , cache_file = 'image_cache.json' , num_clusters = 3 ):
810 """
9- Get the most distinct color from the center of an image for Discord usage .
11+ Cache the most vibrant and colorful area of the image to avoid recalculating it .
1012
1113 Args:
12- image_url (str): The URL of the image to analyze .
13- num_colors (int ): Number of dominant colors to extract (default is 5) .
14- crop_percentage (float ): Percentage of the image to keep in the center (default is 0.5) .
14+ image_url (str): The URL of the image to cache .
15+ cache_file (str ): Path to the JSON file used to store the cached color .
16+ num_clusters (int ): Number of color clusters to detect .
1517
1618 Returns:
17- int: The most distinct color in hexadecimal format.
18-
19- Raises:
20- (Exception): If there is an issue with fetching or processing the image.
19+ int: The most vibrant and colorful color in hexadecimal format.
2120 """
21+ # Check if the cache file exists
22+ if os .path .exists (cache_file ):
23+ with open (cache_file , 'r' ) as f :
24+ cached_data = json .load (f )
25+ if image_url in cached_data :
26+ # If the color is already cached, return it
27+ return cached_data [image_url ]
28+
29+ # If color not cached, fetch and calculate it
2230 response = requests .get (image_url )
2331 img = Image .open (BytesIO (response .content ))
32+ img = img .convert ("RGB" ) # Ensure the image is in RGB format
2433
25- # Calculate the crop dimensions
26- width , height = img .size
27- crop_width = int (width * crop_percentage )
28- crop_height = int (height * crop_percentage )
29- left = (width - crop_width ) // 2
30- top = (height - crop_height ) // 2
31- right = left + crop_width
32- bottom = top + crop_height
34+ # Resize the image for faster processing
35+ img = img .resize ((img .width // 2 , img .height // 2 ))
3336
34- img = img .crop ((left , top , right , bottom ))
37+ # Convert the image to a NumPy array
38+ img_data = np .array (img )
3539
36- img = img .resize ((img .width // 2 , img .height // 2 )) # Resize for faster processing
40+ # Reshape the image data into a 2D array of pixels for clustering
41+ pixels = img_data .reshape ((- 1 , 3 ))
3742
38- img = img .convert ("RGB" ) # Ensure the image is in RGB format
43+ # Remove colors that are too close to black/gray/white
44+ mask = np .linalg .norm (pixels , axis = 1 ) > 50 # A simple threshold to remove very dark colors
45+ filtered_pixels = pixels [mask ]
46+
47+ # Perform KMeans clustering to find color clusters
48+ kmeans = KMeans (n_clusters = num_clusters , random_state = 0 )
49+ kmeans .fit (filtered_pixels )
50+
51+ # Get the centers of the clusters (the most common colors)
52+ cluster_centers = kmeans .cluster_centers_
53+
54+ # Calculate the distance from each cluster center to the black/white axis (i.e., evaluate vibrancy)
55+ distances = np .linalg .norm (cluster_centers - np .array ([0 , 0 , 0 ]), axis = 1 )
56+
57+ # Get the most vibrant cluster (the one that is farthest from black)
58+ most_vibrant_cluster_idx = np .argmax (distances )
59+ vibrant_color = cluster_centers [most_vibrant_cluster_idx ]
3960
40- img_array = np . array ( img )
41- img_flattened = img_array . reshape ( - 1 , 3 )
61+ # Convert the RGB color to hexadecimal format
62+ vibrant_color_hex = int ( '0x{:02x}{:02x}{:02x}' . format ( * vibrant_color . astype ( int )), 16 )
4263
43- kmeans = KMeans (n_clusters = num_colors )
44- kmeans .fit (img_flattened )
64+ # Cache the color
65+ if not os .path .exists (cache_file ):
66+ cached_data = {}
4567
46- dominant_color = kmeans . cluster_centers_ [ np . argmax ( np . bincount ( kmeans . labels_ ))]
68+ cached_data [ image_url ] = vibrant_color_hex
4769
48- return int ('0x{:02x}{:02x}{:02x}' .format (* dominant_color .astype (int )), 16 )
70+ # Save the color to the cache file
71+ with open (cache_file , 'w' ) as f :
72+ json .dump (cached_data , f )
73+
74+ return vibrant_color_hex
75+
76+ def get_discord_color (image_url , cache_file = 'image_cache.json' , num_clusters = 3 ):
77+ """
78+ Get the most vibrant and colorful color (Discord color) from the image for caching.
79+
80+ Args:
81+ image_url (str): The URL of the image to analyze.
82+ cache_file (str): Path to the JSON file used to store cached color.
83+ num_clusters (int): Number of color clusters to detect.
84+
85+ Returns:
86+ int: The most vibrant and colorful color in hexadecimal format.
87+ """
88+ return cache_color (image_url , cache_file , num_clusters )
0 commit comments