2010-07-13 15 views
38

baskın/En yaygın renk bulun. RGB'nin ortalama tonu veya en yaygın olanı yapılacaktır. Python Imaging kütüphanesine baktım ve el kitabında aradığım şeyle ilgili bir şey bulamadım ve ayrıca kısaca VTK'da da bulamadım.Python - Ben piton kullanarak görüntüdeki en dominant renk/tonunu bulmak için bir yol arıyorum bir görüntü

ancak ben, here (indirmek için giriş yapılması gerekir) ne gerek yapar hangi bir PHP komut dosyası buldunuz. Komut, dominant renkleri ortaya çıkarmak için görüntüyü 150 * 150'ye yeniden boyutlandırıyor gibi görünüyor. Ancak bundan sonra oldukça kayboldum. Görüntüyü küçük bir boyuta yeniden boyutlandıracak bir şey yazmayı düşünürdüm, sonra başka bir pikseli veya görüntü için kontrol etmeyi düşünmüştüm, ancak bunun çok verimsiz olacağını hayal etsem de (bu fikri bir C python modülü olarak kullanmak bir fikir olabilir).

Ancak bütün bunlar sonra, hala stumped. Ben de sana dönüyorum, SO. Bir görüntüdeki baskın rengi bulmanın kolay ve verimli bir yolu var mı?

+0

Ben Yeniden boyutlandırma algoritmasının sizin için ortalamanın bir kısmını yapmasını sağlamak için resmi yeniden boyutlandırdığını tahmin ediyorum. – Skurmedel

cevap

39

İşte PIL ve Scipy's cluster package kod yapma yaramaz.

Kolaylık olması açısından ben "image.jpg" olarak dosya adını kodlanmış ettik. Görüntünün yeniden boyutlandırılması hız içindir: beklemeye aldırmazsanız, yeniden boyutlandırılan aramayı yorumlayın. Bu sample image of blue peppers üzerinde çalışırken, genellikle baskın rengin, iki biberin sol alt kısmındaki parlak sarımsı bölgeye karşılık gelen # d8c865 olduğunu söyler. "Genellikle" diyorum çünkü clustering algorithm kullanılan rasgele bir dereceye sahiptir. Bunu değiştirmenin çeşitli yolları vardır, ancak amaçlarınız için uygun olabilir. (Eğer deterministik sonuçlar gerekirse kmeans2() varyant seçenekleri göz atın.)

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) 

Not: Ben 5 ila 10 veya 15'e bulmak için kümelerinin sayısını artırmak, bunun sıkça yeşilimsi olan sonuçlar verdi veya mavimsi. Giriş görüntüsü göz önüne alındığında, bunlar da makul sonuçlardır ... Bu resimde hangi rengin gerçekten baskın olduğunu anlayamıyorum, bu yüzden algoritmayı hata etmiyorum!

Ayrıca küçük ikramiye: Sadece N en-sık renklerle indirgenmiş boyutlu görüntüyü kaydetmek: PIL size mod "P" ile bir görüntü verip vermediğini

# 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' 
+1

Vay. Bu harika. Neredeyse tam olarak aradığım şey. Scipy'ye baktım ve cevabın orada bir yerde olduğunu hissetmiştim: P Cevabınız için teşekkür ederim. –

+0

Harika cevap. Benim için çalıştı. Ancak küçük bir sorum vardı. Siyahın en sık görülen durumda ikinci en sık kullanılan rengi nasıl bulabilirim? – frakman1

+0

@ frakman1, argmax() sadece ilkini veren bir kolaylık işlevidir. Yapmanız gereken şey, sayım dizisini (orijinal endeksleri takip ederek) sıralamaktır, sonra ilkinden ziyade ikinci (veya ikinci son) girişini seçer (hangi argmax'ın yaptığı etkilidir). –

10

Python Imaging Library Görüntü nesneler üzerinde metot getcolors vardır:

im.getcolors() => a list of (count, color) tuples or None

Ben hala o önce resmi yeniden boyutlandırma deneyin ve daha iyi performans göstermesi durumunda görebilirsiniz sanırım.

5

Bunu 1x1 ulaşana kadar defalarca her boyut içinde 2 kat görüntüyü aşağı yeniden boyutlandırmak için PIL kullanabilirsiniz. PIL'in, büyük faktörler tarafından ölçek küçültme için kullandığı algoritmayı bilmiyorum, bu nedenle tek bir yeniden boyutlandırmada doğrudan 1x1'e gitmek bilgi kaybına neden olabilir. En verimli olmayabilir, ancak görüntünün "ortalama" rengini verecektir.

3

, Peter cevabı eklemek veya hemen hemen "RGBA" olmayan herhangi bir mod, daha sonra RGBA'ya dönüştürmek için bir alfa maskesi uygulamanız gerekir.Sen oldukça kolay yapabilir:

if im.mode == 'P': 
    im.putalpha(0) 
1

Below is a c++ Qt based example to guess the predominant image color. You can use PyQt and translate the same to Python equivalent.

#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

hala bir cevap arıyorsanız, burada korkunç verimli değil olsa benim için çalıştı budur:

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) 
+0

png için, img.getpixel'ın r, g, b, a değerini döndürdüğü (üç yerine dört değer) işlemek için bunu hafifçe ayarlamanız gerekir. Ya da yine de benim için yaptı. – rossdavidh

+0

Bu, pikselleri eşit olmayan şekilde ağırlar. Dokunduğunuz son piksel, toplam değerin yarısına katkıda bulunur. Piksel, bunun yarısına katkıda bulunur. Aslında sadece son 8 piksel ortalamayı etkileyecektir. –

+0

Haklısınız - aptalca bir hata. Sadece cevabı düzenledim - eğer işe yararsa bana bildirin. –

İlgili konular