Search code examples
pythonopencvk-means

Python - Image Colors Extrapolation - KMeans error


i have found this tutorial on how to write a python script that uses OpenCV and Kmeans for extrapolating the top colors from an image and plot them in a pie chart using Matplot.

The code is the following:

from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
import cv2
from collections import Counter
from skimage.color import rgb2lab, deltaE_cie76
import os

# Define a function that will convert the colours in HEX
def RGB2HEX(color):
    return "#{:02x}{:02x}{:02x}".format(int(color[0]), int(color[1]), int(color[2]))

# Define an image path in order to read it from OpenCV and convert in RGB
def get_image(image_path):
    image = cv2.imread(image_path)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    return image

# Define a method for extracting the top colors from an image and plot them through Matplot
def get_colors(image, number_of_colors, show_chart):
    
    # Resize the image (not required) then reshape the input images in a two dimensional array
    modified_image = cv2.resize(image, (600, 400), interpolation = cv2.INTER_AREA)
    modified_image = modified_image.reshape(modified_image.shape[0]*modified_image.shape[1], 3)
    
    # Use the KMeans algorithm that creates clusters of colors through a fit and predict funciont in order to extract and map into lables variables
    clf = KMeans(n_clusters = number_of_colors)
    labels = clf.fit_predict(modified_image)
    
    counts = Counter(labels)
    counts = dict(sorted(counts.items()))
    
    center_colors = clf.cluster_centers_
    # Order the colors by iterating through the keys
    ordered_colors = [center_colors[i] for i in counts.keys()]
    hex_colors = [RGB2HEX(ordered_colors[i]) for i in counts.keys()]
    rgb_colors = [ordered_colors[i] for i in counts.keys()]

    plt.figure(figsize = (8, 6))
    plt.pie(counts.values(), labels = hex_colors, colors = hex_colors)
    
    # Retunr the RGB colors extracted
    return rgb_colors

# Call the method and pass the image path
get_colors(get_image('.\sample.jpg'), 8, True)

The problem is that when i run the script, taking a sample image in input, the following warning occurs:

PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\sklearn\cluster\_kmeans.py:870: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning
  warnings.warn(

While usually i expect that a warning should not block the script execution, matplot is launched but then it crashes immediately without plotting anything at all.

Any suggestions?

Thanks!

Tried to search on internet, but nothing came through.


Solution

  • The issue is probably unrelated to the warning message.
    We should simply call plt.show() after plt.pie(...) for displaying the figure.


    Sample image for testing jp.png:
    enter image description here


    Updated code sample:

    from sklearn.cluster import KMeans
    import matplotlib.pyplot as plt
    import numpy as np
    import cv2
    from collections import Counter
    from skimage.color import rgb2lab, deltaE_cie76
    import os
    
    # Define a function that will convert the colours in HEX
    def RGB2HEX(color):
        return "#{:02x}{:02x}{:02x}".format(int(color[0]), int(color[1]), int(color[2]))
    
    # Define an image path in order to read it from OpenCV and convert in RGB
    def get_image(image_path):
        image = cv2.imread(image_path)
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        return image
    
    # Define a method for extracting the top colors from an image and plot them through Matplot
    def get_colors(image, number_of_colors, show_chart):
        
        # Resize the image (not required) then reshape the input images in a two dimensional array
        modified_image = cv2.resize(image, (600, 400), interpolation = cv2.INTER_AREA)
        modified_image = modified_image.reshape(modified_image.shape[0]*modified_image.shape[1], 3)
        
        # Use the KMeans algorithm that creates clusters of colors through a fit and predict funciont in order to extract and map into lables variables
        clf = KMeans(n_clusters = number_of_colors)
        labels = clf.fit_predict(modified_image)
        
        counts = Counter(labels)
        counts = dict(sorted(counts.items()))
        
        center_colors = clf.cluster_centers_
        # Order the colors by iterating through the keys
        ordered_colors = [center_colors[i] for i in counts.keys()]
        hex_colors = [RGB2HEX(ordered_colors[i]) for i in counts.keys()]
        rgb_colors = [ordered_colors[i] for i in counts.keys()]
    
        plt.figure(figsize = (8, 6))
        plt.pie(counts.values(), labels = hex_colors, colors = hex_colors)
        plt.show()
        
        # Retunr the RGB colors extracted
        return rgb_colors
    
    # Call the method and pass the image path
    #get_colors(get_image('.\sample.jpg'), 8, True)
    get_colors(get_image('.\jp.png'), 8, True)  # https://pyimagesearch.com/2014/05/26/opencv-python-k-means-color-clustering/
    

    Output figure:
    enter image description here