2010-03-30 16 views
8

.NET'teki arka plan görüntüsünde çoğunluk rengini almak istiyorum. Mümkün mü?Görüntüde çoğunluk rengi nasıl elde edilir?

+0

sen 'çoğunluk renk' anlamını açıklamak miyim? Bir görüntüde en sık kullanılan renkten mi bahsediyorsunuz? bir resmin ortalama rengi; 'en yüksek' değer rengi eşitleyici RGB? – Seidr

+3

Muhtemelen "çoğunluk rengi" ile ne kastettiğinizi açıklığa kavuşturmanız gerekiyor. Çoğu görüntü için, herhangi bir rengin uygun bir çoğunluğu oluşturması olası değildir. En sık kullanılan rengi (piksele göre piksel) veya dominant bileşeni (R, G veya B) kastettiğinizi varsayıyorum. – MusiGenesis

+0

Hıza veya doğruluğa ihtiyacınız var mı? Ayrıca en çok kullanılan renk, ortalama renk veya trend rengi mi istiyorsunuz? RGB'ye karıştı mı, yoksa karıştırılmış mı? –

cevap

6

Görüntüdeki tüm pikselleri döndürebilir ve RGB değerini belirlemek için getPixel yöntemini kullanabilirsiniz. Ardından, bir sayı ile birlikte ARGB değerini depolayan bir sözlüğe sahip olabilirsiniz. Görüntüde en çok hangi ARGB değerinin bulunduğunu görebilirsiniz. Belirtildiği gibi, benzer renkler için hiçbir sempati bulunmadığı belirtilmektedir. Daha genel bir 'genel' renk istiyorsanız, benzerlik üzerinde bir eşik olabilir. Örneğin. yerine:

if (!list.ContainsKey(rgb)) 
     list.Add(rgb, 1); 
    else 
     list[rgb]++; 

bunu yapabilirsiniz:

var added = false; 
for (int i = 0; i < 10; i++) 
{ 
    if (list.ContainsKey(rgb+i)) 
    { 
     list[rgb+i]++; 
     added = true; 
     break; 
    } 
    if (list.ContainsKey(rgb-i)) 
    { 
     list[rgb-i]++; 
     added = true; 
     break; 
    } 
} 
if(!added) 
    list.Add(rgb, 1); 

En fazla 10 eşiği ne kadar size ihtiyaç olabilir.

+0

Eğer bu "gerçek renk" jpeg ... Bu, anahtarda çok az sayıya sahip sözlükte tonlarca değer olabilir. –

+0

Anlaşmalı. Terbiyeli çalışmak için bir çeşit binning veya gruplamaya ihtiyacınız olacak. Bununla, 2 mükemmel kırmızı piksel ve bir ton ince siyah varyantı olabilir ve çoğunluk rengi olarak kırmızı ile çıkabilirsiniz. – RandomEngy

+0

Teknik olarak iyi konuşan kırmızı, o zaman çoğunluk rengi olurdu. – CeejeeB

3

Her bir pikselin rengini RGB (versus, CMYK) kullanarak karakterize ettiğinizi varsayalım, bir 3d dizi (her biri R, G ve B için bir boyut) oluşturabilirsiniz. Daha sonra, her boyutta olmasını istediğiniz kutuların sayısına karar verin - daha fazla kutu, benzer tonlar arasında yaptığınız farklılaşma.

Bu işlem tamamlandıktan sonra, 3B dizisindeki hücrelerin her birine düşen # pikselleri toplayarak görüntünüzün bitmap gösterimi boyunca yineleyin. En yüksek toplamı olan hücre baskın renk olacaktır.

Algoritmanızı her boyuttaki # kutu için kolayca yapılandırılabilir yapmak isteyebilirsiniz, böylece benzer renkler arasında ne kadar ayrımcılığa yol açabileceğini ayarlayabilirsiniz.

5

Bu, görüntünün ortalama rengini döndürür.

static Color AverageColor(string fileName) 
{ 
    using (var bmp = new Bitmap(fileName)) 
    { 
     int width = bmp.Width; 
     int height = bmp.Height; 
     int red = 0; 
     int green = 0; 
     int blue = 0; 
     int alpha = 0; 
     for (int x = 0; x < width; x++) 
      for (int y = 0; y < height; y++) 
      { 
       var pixel = bmp.GetPixel(x, y); 
       red += pixel.R; 
       green += pixel.G; 
       blue += pixel.B; 
       alpha += pixel.A; 
      } 

     Func<int, int> avg = c => c/(width * height); 

     red = avg(red); 
     green = avg(green); 
     blue = avg(blue); 
     alpha = avg(alpha); 

     var color = Color.FromArgb(alpha, red, green, blue); 

     return color; 
    } 
} 
+0

Bence sonuç, ortalama renk olan tek bir pikselin olamayacağı için "çoğunluk rengi" olarak nitelendiriliyor. – Kaniu

+0

Çok doğru ... ve bu yüzden soru altında benim yorumumda daha fazla ayrıntı sordum. Cevap yok, bu benim girişim. Performans için –

4

Bu, güvenli olmayan işaretçi erişimi kullanarak görüntü için ortalama rengi döndürecektir. Not: Kod sadece 24bppRgb için uyarlanmıştır, diğer piksel formatları için uyarlanabilir.

unsafe static Color GetColor(string filename) 
    { 
     using (var image = (Bitmap)Bitmap.FromFile(filename)) 
     { 
      if (image.PixelFormat != PixelFormat.Format24bppRgb) throw new NotSupportedException(String.Format("Unsupported pixel format: {0}", image.PixelFormat)); 

      var pixelSize = 3; 
      var bounds = new Rectangle(0, 0, image.Width, image.Height); 
      var data = image.LockBits(bounds, ImageLockMode.ReadOnly, image.PixelFormat); 

      long r = 0; 
      long g = 0; 
      long b = 0; 

      for (int y = 0; y < data.Height; ++y) 
      { 
       byte* row = (byte*)data.Scan0 + (y * data.Stride); 
       for (int x = 0; x < data.Width; ++x) 
       { 
        var pos = x * pixelSize; 
        b += row[pos]; 
        g += row[pos + 1]; 
        r += row[pos + 2]; 
       } 
      } 

      r = r/(data.Width * data.Height); 
      g = g/(data.Width * data.Height); 
      b = b/(data.Width * data.Height); 
      image.UnlockBits(data); 

      return Color.FromArgb((int)r, (int)g, (int)b); 
     } 
    } 

özü: http://gist.github.com/349210

+0

+1. Her bir pikselde GetPixel'i çağırmak çok yavaş. – RandomEngy

+1

Son derece yavaş bir abartı biraz. 15 kare/800x600 video karelerini analiz etmek için GetPixel yöntemini kullanabildim. Dolayısıyla, posterin tek bir görüntüyü analiz etmesi gerekiyorsa, GetPixel yeterli değil. – CeejeeB

İlgili konular