web-dev-qa-db-ja.com

Python-画像内の主要な/最も一般的な色を見つける

私はPythonを使用して画像の中で最も支配的な色/トーンを見つける方法を探しています。平均的な色合いまたは最も一般的なRGBのいずれかで十分です。 Python Imagingライブラリを調べましたが、マニュアルやVTKで簡単に探しているものに関連するものは見つかりませんでした。

しかし、私はPHP私が必要なことを行うスクリプト、 ここ (ダウンロードにログインが必要))を見つけました。スクリプトは画像を150 * 150にリサイズするようです支配的な色を引き出します。しかし、その後、私はかなり失われます。画像を小さなサイズに変更し、他のすべてのピクセルをチェックするか何かを書くことを検討しました。ただし、このアイデアをC pythonモジュールとしてアイデアとして実装する)。

しかし、そのすべての後、私はまだ困惑しています。それで、私はあなたに目を向けます。画像の主要な色を見つける簡単で効率的な方法はありますか。

53
Blue Peppers

Pillow および Scipyのクラスターパッケージ を使用するコードを次に示します。

簡単にするために、ファイル名を「image.jpg」としてハードコーディングしました。画像のサイズ変更は高速化のためです:待機しても構わない場合は、サイズ変更呼び出しをコメントアウトしてください。これで実行すると 青唐辛子のサンプル画像 通常、支配的な色は#d8c865であり、2つの唐辛子の左下にある明るい黄色がかった領域にほぼ対応しています。使用される クラスタリングアルゴリズム にはある程度のランダム性があるため、「通常」と言います。これを変更するにはさまざまな方法がありますが、目的に応じて適切な場合があります。 (確定的な結果が必要な場合は、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')
55
Peter Hansen

Python Imaging Libraryには、Imageオブジェクトのgetcolorsメソッドがあります。

im.getcolors() =>(count、color)タプルのリストまたはNone

その前に画像のサイズを変更してみて、パフォーマンスが改善されるかどうかを確認できると思います。

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

PILを使用して、画像が1x1に達するまで、各次元で2倍ずつ繰り返しサイズを変更できます。 PILが大きな要因によるダウンスケーリングにどのアルゴリズムを使用するかわからないため、1回のサイズ変更で1x1に直接移動すると情報が失われる可能性があります。最も効率的ではないかもしれませんが、画像の「平均的な」色が得られます。

5

Peterの答えに追加するには、PILがモード「P」または「RGBA」以外のほとんどのモードの画像を提供している場合、アルファマスクを適用してRGBAに変換する必要があります。あなたはそれを非常に簡単に行うことができます:

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

Color-thief を試してください。それは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

Peterが提案するように、支配的な色を見つけるためにk-meansを使用する必要はありません。これは単純な問題を複雑にします。また、選択したクラスターの量によって自分自身を制限しているため、基本的には何を見ているのかを知る必要があります。

あなたが述べたように、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()が色の量が256を超えるとNoneを返すことです。元の画像のサイズを変更することで対処できます。

全体として、それは最も正確なソリューションではないかもしれませんが、仕事を終わらせます。

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();
}
2
Ankur Gupta