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.
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'
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.
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.
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)
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)
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();
}
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)