Python-trouver la couleur dominante/la plus commune dans une image

Je cherche un moyen de trouver la couleur/tonalité la plus dominante dans une image en utilisant python. Soit l'ombre moyenne ou le plus commun de RVB fera l'affaire. J'ai regardé la bibliothèque D'imagerie Python, et je n'ai rien trouvé concernant ce que je cherchais dans leur manuel, et aussi brièvement à VTK.

J'ai cependant trouvé un script PHP qui fait ce dont j'ai besoin, ici (Connexion requise pour télécharger). Le script semble redimensionner l'image à 150*150, pour apporter de la dominante couleur. Cependant, après cela, je suis assez perdu. J'ai envisagé d'écrire quelque chose qui redimensionnerait l'image à une petite taille puis vérifierait tous les autres pixels pour son image, bien que j'imagine que ce serait très inefficace (bien que l'implémentation de cette idée en tant que module c python puisse être une idée).

Cependant, après tout cela, je suis toujours perplexe. Je me tourne donc vers vous, DONC. Existe-t-il un moyen facile et efficace de trouver la couleur dominante dans une image.

42
demandé sur Blue Peppers 2010-07-14 02:05:55

7 réponses

Voici le code qui utilise PIL et Le Paquet de cluster de Scipy .

Pour simplifier, j'ai codé en dur le nom de fichier comme " image.jpg". Redimensionner l'image est pour la vitesse: si cela ne vous dérange pas l'attente, commenter l'appel de redimensionnement. Lorsqu'il est exécuté sur cette exemple d'image de poivrons bleus , il est généralement dit que la couleur dominante est #d8c865, ce qui correspond à peu près à la zone jaunâtre brillante en bas à gauche des deux poivrons. Je dis "habituellement" parce que le clustering l'algorithme Utilisé a un degré de caractère aléatoire. Il existe différentes façons de changer cela, mais pour vos besoins, cela peut bien convenir. (Consultez les options de la variante kmeans2 () si vous avez besoin de résultats déterministes.)

import struct
import Image
import numpy as np
import scipy
import scipy.misc
import scipy.cluster

NUM_CLUSTERS = 5

print 'reading image'
im = Image.open('image.jpg')
im = im.resize((150, 150))      # optional, to reduce time
ar = np.asarray(im)
shape = ar.shape
ar = ar.reshape(scipy.product(shape[:2]), shape[2]).astype(float)

print 'finding clusters'
codes, dist = scipy.cluster.vq.kmeans(ar, NUM_CLUSTERS)
print 'cluster centres:\n', codes

vecs, dist = scipy.cluster.vq.vq(ar, codes)         # assign codes
counts, bins = scipy.histogram(vecs, len(codes))    # count occurrences

index_max = scipy.argmax(counts)                    # find most frequent
peak = codes[index_max]
colour = ''.join(chr(int(c)) for c in peak).encode('hex')
print 'most frequent is %s (#%s)' % (peak, colour)

Note: lorsque j'augmente le nombre de grappes à trouver de 5 à 10 ou 15, cela donne souvent des résultats verdâtres ou bleuâtres. Compte tenu de l'image d'entrée, ce sont aussi des résultats raisonnables... Je ne peux pas dire quelle couleur est vraiment dominante dans cette image non plus, donc, je ne blâme pas l'algorithme!

Aussi un petit bonus: enregistrez l'image de taille réduite avec seulement les n couleurs les plus fréquentes:

# bonus: save image using only the N most common colours
c = ar.copy()
for i, code in enumerate(codes):
    c[scipy.r_[scipy.where(vecs==i)],:] = code
scipy.misc.imsave('clusters.png', c.reshape(*shape))
print 'saved clustered image'
45
répondu Peter Hansen 2017-12-03 19:11:57

La bibliothèque D'imagerie Python a la méthode getcolors sur les objets Image:

Im.getcolors() => une liste de (comte, couleur) tuples ou Aucun

Je suppose que vous pouvez toujours essayer de redimensionner l'image avant cela et voir si elle fonctionne mieux.

11
répondu zvone 2010-07-13 23:19:07

Vous pouvez utiliser PIL pour redimensionner à plusieurs reprises l'image d'un facteur 2 dans chaque dimension jusqu'à ce qu'elle atteigne 1x1. Je ne sais pas quel algorithme PIL utilise pour réduire l'échelle par de grands facteurs, donc aller directement à 1x1 dans un seul redimensionnement pourrait perdre des informations. Ce n'est peut-être pas le plus efficace, mais cela vous donnera la couleur "moyenne" de l'image.

5
répondu Russell Borogove 2010-07-13 23:46:57

Si vous cherchez toujours une réponse, voici ce qui a fonctionné pour moi, mais pas terriblement efficace:

from PIL import Image

def compute_average_image_color(img):
    width, height = img.size

    r_total = 0
    g_total = 0
    b_total = 0

    count = 0
    for x in range(0, width):
        for y in range(0, height):
            r, g, b = img.getpixel((x,y))
            r_total += r
            g_total += g
            b_total += b
            count += 1

    return (r_total/count, g_total/count, b_total/count)

img = Image.open('image.png')
#img = img.resize((50,50))  # Small optimization
average_color = compute_average_image_color(img)
print(average_color)
5
répondu Tim S 2017-01-23 18:59:51

Pour ajouter à la réponse de Peter, si PIL vous donne une image avec le mode " P "ou à peu près n'importe quel mode qui n'est pas "RGBA", alors vous devez appliquer un masque alpha pour le convertir en RGBA. Vous pouvez le faire assez facilement avec:

if im.mode == 'P':
    im.putalpha(0)
3
répondu Samuel Clay 2011-01-27 03:52:51

Voici un exemple basé sur C++ Qt pour deviner la couleur d'image prédominante. Vous pouvez utiliser PyQt et traduire la même chose en équivalent Python.

#include <Qt/QtGui>
#include <Qt/QtCore>
#include <QtGui/QApplication>

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    QPixmap pixmap("logo.png");
    QImage image = pixmap.toImage();
    QRgb col;
    QMap<QRgb,int> rgbcount;
    QRgb greatest = 0;

    int width = pixmap.width();
    int height = pixmap.height();

    int count = 0;
    for (int i = 0; i < width; ++i)
    {
        for (int j = 0; j < height; ++j)
        {
            col = image.pixel(i, j);
            if (rgbcount.contains(col)) {
                rgbcount[col] = rgbcount[col] + 1;
            }
            else  {
                rgbcount[col] = 1;
            }

            if (rgbcount[col] > count)  {
                greatest = col;
                count = rgbcount[col];
            }

        }
    }
    qDebug() << count << greatest;
    return app.exec();
}
1
répondu Ankur Gupta 2012-01-17 07:44:29

Essayez color-thief . Il est basé sur PIL et fonctionne génial.

Installation

pip install colorthief

L'Utilisation de

from colorthief import ColorThief
color_thief = ColorThief('/path/to/imagefile')
# get the dominant color
dominant_color = color_thief.get_color(quality=1)

Il peut également trouver palette de couleurs

palette = color_thief.get_palette(color_count=6)
1
répondu Artem Bernatskyi 2018-08-26 09:01:25