Python-Znajdź dominujący / najczęstszy kolor w obrazie

Szukam sposobu na znalezienie najbardziej dominującego koloru / tonu w obrazie za pomocą Pythona. Wystarczy średni odcień lub najczęstszy z RGB. Zajrzałem do biblioteki obrazowania Pythona i nie mogłem znaleźć niczego związanego z tym, czego szukałem w ich podręczniku, a także krótko w VTK.

Znalazłem jednak skrypt PHP, który robi to, czego potrzebuję, TUTAJ (login wymagany do pobrania). Skrypt wydaje się zmieniać rozmiar obrazu do 150*150, aby wydobyć dominantę colors= Jednak po tym jestem dość zagubiony. Rozważałem napisanie czegoś, co zmieniłoby Rozmiar obrazu na mały rozmiar, a następnie sprawdziłoby co drugi Piksel lub tak dla obrazu, chociaż wyobrażam sobie, że byłoby to bardzo nieefektywne (choć implementacja tego pomysłu jako modułu Pythona C może być pomysłem).

Jednak, po tym wszystkim, wciąż jestem zakłopotany. Więc zwracam się do ciebie. Czy istnieje łatwy i skuteczny sposób na znalezienie dominującego koloru na obrazie.

Author: Blue Peppers, 2010-07-14

7 answers

Oto kod wykorzystujący pil i Pakiet klastra Scipy .

Dla uproszczenia zakodowałem na twardo nazwę pliku jako " image.jpg". Zmiana rozmiaru obrazu jest dla szybkości: jeśli nie masz nic przeciwko czekaniu, skomentuj połączenie zmiany rozmiaru. Po uruchomieniu tego przykładowego obrazu niebieskiej papryki zazwyczaj mówi się, że dominującym kolorem jest #d8c865, co odpowiada mniej więcej jasnożółtemu obszarowi w lewym dolnym rogu dwóch papryk. Mówię "zwykle", ponieważ grupowanie zastosowany algorytm ma pewien stopień losowości. Istnieją różne sposoby, aby to zmienić, ale dla Twoich celów może to dobrze pasować. (Sprawdź opcje w wariancie kmeans2 (), jeśli potrzebujesz deterministycznych wyników.)

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)

Uwaga: kiedy zwiększam liczbę klastrów, aby znaleźć od 5 do 10 lub 15, często dawało to wyniki, które były zielonkawe lub niebieskawe. Biorąc pod uwagę obraz wejściowy, są to również rozsądne wyniki... Nie mogę też powiedzieć, który kolor jest naprawdę dominujący w tym obrazie, więc nie winię algorytmu!

Również mały bonus: Zapisz obraz o zmniejszonym rozmiarze tylko z N najczęstszych kolorów:

# 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
Author: Peter Hansen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-03 19:11:57

Biblioteka obrazowania Pythona posiada metody getcolors na obiektach obrazu:

Im.getcolors () = > a list of (count, kolor) krotki lub brak

Myślę, że nadal możesz spróbować zmienić rozmiar obrazu przed tym i zobaczyć, czy działa lepiej.

 11
Author: zvone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-13 23:19:07

Możesz użyć PIL, aby wielokrotnie zmieniać rozmiar obrazu w dół o współczynnik 2 w każdym wymiarze, aż osiągnie 1x1. Nie wiem, jaki algorytm pil wykorzystuje do zmniejszania o Duże czynniki, więc przejście bezpośrednio do 1x1 w jednej zmianie rozmiaru może stracić informacje. Może nie jest najbardziej wydajny, ale da ci "średni" kolor obrazu.

 5
Author: Russell Borogove,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-13 23:46:57

Jeśli nadal szukasz odpowiedzi, oto, co zadziałało dla mnie, choć niezbyt wydajne:

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
Author: Tim S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-23 18:59:51

Aby dodać do odpowiedzi Petera, jeśli pil daje Ci obraz z trybem " P "lub praktycznie dowolnym trybem, który nie jest "RGBA", musisz zastosować maskę Alfa, aby przekonwertować go na RGBA. Można to zrobić całkiem łatwo z:

if im.mode == 'P':
    im.putalpha(0)
 3
Author: Samuel Clay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-27 03:52:51

Poniżej znajduje się przykład oparty na C++ Qt, aby odgadnąć dominujący kolor obrazu. Możesz użyć PyQt i przetłumaczyć to samo Na odpowiednik Pythona.

#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
Author: Ankur Gupta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-17 07:44:29

Spróbuj Color-thief . Jest oparty na PIL i działa świetnie.

Instalacja

pip install colorthief

Użycie

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

Może również znaleźć paletę kolorów

palette = color_thief.get_palette(color_count=6)
 1
Author: Artem Bernatskyi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-26 09:01:25