Python - Найти доминирующий / самый распространенный цвет в изображении - PullRequest
51 голосов
/ 14 июля 2010

Я ищу способ найти наиболее доминирующий цвет / тон на изображении, используя python.Подойдет либо средний оттенок, либо самый распространенный из RGB.Я посмотрел библиотеку изображений Python и не смог найти ничего, касающегося того, что я искал, в их руководстве, а также кратко о VTK.

Однако я нашел скрипт PHP, который делает то, что мне нужно, здесь (требуется логин для загрузки).Сценарий, кажется, изменяет размер изображения до 150 * 150, чтобы выявить доминирующие цвета.Однако после этого я довольно заблудился.Я решил написать что-нибудь, что изменило бы размер изображения до небольшого размера, а затем проверил каждый второй пиксель на предмет его изображения, хотя я думаю, что это было бы очень неэффективно (хотя реализация этой идеи в качестве модуля C Python может быть идеей).

Однако, после всего этого, я все еще в тупике.Так что я обращаюсь к вам, ТАК.Существует ли простой, эффективный способ найти доминирующий цвет на изображении.

Ответы [ 8 ]

53 голосов
/ 14 июля 2010

Вот код, использующий Подушка и Кластерный пакет Сципи .

Для простоты я жестко закодировал имя файла как «image.jpg».Изменение размера изображения для скорости: если вы не возражаете против ожидания, закомментируйте вызов изменения размера.При работе с этим образцом изображения синих перцев обычно говорится, что доминирующим цветом является # d8c865, что примерно соответствует яркой желтоватой области в левом нижнем углу двух перцев.Я говорю «обычно», потому что используемый алгоритм кластеризации имеет некоторую степень случайности.Есть несколько способов изменить это, но для ваших целей это может хорошо подойти.(Проверьте параметры варианта kmeans2 (), если вам нужны детерминированные результаты.)

from __future__ import print_function
import binascii
import struct
from PIL 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 = binascii.hexlify(bytearray(int(c) for c in peak)).decode('ascii')
print('most frequent is %s (#%s)' % (peak, colour))

Примечание: когда я увеличиваю количество кластеров, чтобы найти от 5 до 10 или 15, он часто дает результаты, которыебыли зеленоватыми или голубоватыми.Учитывая исходное изображение, это тоже приемлемые результаты ... Я не могу сказать, какой цвет действительно доминирует в этом изображении, поэтому я не ошибаюсь в алгоритме!

Также небольшой бонус: сохранитеуменьшенное изображение только с N наиболее часто встречающимися цветами:

# bonus: save image using only the N most common colours
import imageio
c = ar.copy()
for i, code in enumerate(codes):
    c[scipy.r_[scipy.where(vecs==i)],:] = code
imageio.imwrite('clusters.png', c.reshape(*shape).astype(np.uint8))
print('saved clustered image')
13 голосов
/ 14 июля 2010

Библиотека изображений Python имеет метод getcolors для объектов Image:

im.getcolors () => список (количество, цвет) кортежи или нет

Полагаю, вы можете попробовать изменить размер изображения до этого и посмотреть, будет ли оно лучше.

7 голосов
/ 08 ноября 2015

Если вы все еще ищете ответ, вот что сработало для меня, хотя и не очень эффективно:

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)
6 голосов
/ 14 июля 2010

Вы можете использовать PIL для многократного изменения размера изображения в 2 раза в каждом измерении, пока оно не достигнет 1x1. Я не знаю, какой алгоритм использует PIL для уменьшения масштаба по большим факторам, поэтому переход к 1x1 при одном изменении размера может привести к потере информации. Возможно, он не самый эффективный, но он даст вам «средний» цвет изображения.

3 голосов
/ 26 августа 2018

Попробуйте Цвет-вор .Он основан на PIL и работает потрясающе.

Установка

pip install colorthief

Использование

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

Также можно найти цветную палитру

palette = color_thief.get_palette(color_count=6)
3 голосов
/ 27 января 2011

Чтобы добавить к ответу Питера, если PIL дает вам изображение с режимом «P» или почти любым другим режимом, который не является «RGBA», то вам нужно применить альфа-маску, чтобы преобразовать его в RGBA. Вы можете сделать это довольно легко с помощью:

if im.mode == 'P':
    im.putalpha(0)
2 голосов
/ 18 октября 2018

Нет необходимости использовать k-средства, чтобы найти доминирующий цвет, как предлагает Питер. Это усложняет простую проблему. Вы также ограничиваете количество выбранных вами кластеров, поэтому в основном вам нужно знать, на что вы смотрите.

Как вы упомянули и как предлагает zvone, быстрое решение для поиска наиболее распространенного / доминирующего цвета - использование библиотеки Pillow . Нам просто нужно отсортировать пиксели по их количеству.

from PIL import Image

    def dominant_color(filename):
        #Resizing parameters
        width, height = 150,150
        image = Image.open(filename)
        image = image.resize((width, height),resample = 0)
        #Get colors from image object
        pixels = image.getcolors(width * height)
        #Sort them by count number(first element of tuple)
        sorted_pixels = sorted(pixels, key=lambda t: t[0])
        #Get the most frequent color
        dominant_color = sorted_pixels[-1][1]
        return dominant_color

Единственная проблема заключается в том, что метод getcolors() возвращает значение None, если количество цветов превышает 256. С этим можно справиться, изменив исходное изображение.

В целом, это может быть не самое точное решение, но оно выполняет свою работу.

1 голос
/ 17 января 2012

Ниже приведен пример на основе c ++ Qt, позволяющий угадать преобладающий цвет изображения. Вы можете использовать PyQt и перевести то же самое в эквивалент 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();
}
...