it-swarm.com.ru

Python - Найти доминирующий / самый распространенный цвет в изображении

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

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

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

49
Blue Peppers

Вот код, использующий Pillow и кластерный пакет Scipy .

Для простоты я жестко закодировал имя файла как "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')
52
Peter Hansen

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

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

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

13
zvone

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

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)
7
Tim S

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

6
Russell Borogove

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

if im.mode == 'P':
    im.putalpha(0)
3
Samuel Clay

Попробуй Цвет-вор . Он основан на 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
Artem Bernatskyi

Нет необходимости использовать 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. Вы можете справиться с этим, изменив размер исходного изображения.

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

2
mobiuscreek

Ниже приведен пример на основе 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();
}
1
Ankur Gupta