2010-03-30 17 views
8

Chcę pobrać kolor większości w obrazie tła w .NET. Czy to możliwe?Jak uzyskać kolorowy kolor na obrazie?

+0

można wyjaśnić znaczenie 'kolor większościowego'? Masz na myśli kolor najczęściej używany w obrazie; średni kolor obrazu; kolor "najwyższej" odpowiadający RGB? – Seidr

+3

Prawdopodobnie musisz wyjaśnić, co masz na myśli przez "kolor większościowy". W przypadku większości zdjęć mało prawdopodobne jest, aby jeden kolor stanowił prawidłową większość. Zakładam, że masz na myśli albo najczęstszy kolor (piksel po pikselu), albo dominujący składnik (albo R, G albo B). – MusiGenesis

+0

Czy potrzebujesz prędkości lub dokładności? Chcesz również najczęściej używanego koloru, średniego koloru lub modnego koloru? Czy potrzebujesz mieszanego lub spienionego RGB? –

Odpowiedz

6

Można przechodzić przez wszystkie piksele obrazu i użyć metody getPixel do określenia wartości RGB. Następnie możesz mieć słownik przechowujący wartość ARGB wraz z liczbą. Następnie możesz sprawdzić, która wartość ARGB jest najbardziej widoczna na obrazie.

var list = new Dictionary<int, int>(); 
Bitmap myImage = (Bitmap)Bitmap.FromFile("C:/test.jpeg"); 
for (int x = 0; x < myImage.Width; x++) 
{ 
    for (int y = 0; y < myImage.Height; y++) 
    { 
     int rgb = myImage.GetPixel(x, y).ToArgb(); 
     if (!list.ContainsKey(rgb)) 
      list.Add(rgb, 1); 
     else 
      list[rgb]++; 
    } 
} 

Jak podkreślono, nie ma to sympatii dla podobnych kolorów. Jeśli chcesz uzyskać bardziej "ogólny" kolor większości, możesz mieć próg podobieństwa. na przykład zamiast:

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

można zrobić:

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); 

Mogłeś się progu 10 do czegokolwiek potrzebne.

+0

Jeśli jest to jpeg "true color", może to być mnóstwo wartości w słowniku z bardzo małą liczbą zliczeń na klucz. –

+0

Uzgodnione. Będziesz potrzebował jakiegoś rodzaju binowania lub grupowania, by pracować przyzwoicie. Dzięki temu możesz mieć 2 doskonale czerwone piksele i tonę subtelnych wariantów czerni i wyjść z czerwoną jako kolor większości. – RandomEngy

+0

Cóż, technicznie rzecz biorąc kolor czerwony byłby wówczas kolorem większości. – CeejeeB

3

Zakładając, że charakteryzujesz kolor każdego piksela za pomocą RGB (w porównaniu, powiedzmy, CMYK), możesz zbudować tablicę 3d (po jednym wymiarze dla R, G i B). Następnie wybierz liczbę pojemników, które chcesz mieć w każdym z wymiarów - im więcej pojemników, tym większe zróżnicowanie między podobnymi odcieniami.

Po wykonaniu tej czynności należy po prostu powtórzyć bitmapową reprezentację obrazu, sumująC# pikseli, które przypadają do każdej z komórek w tablicy 3d. Komórka o największej sumie będzie dominującym kolorem.

Prawdopodobnie chcesz, aby Twój algorytm był łatwo konfigurowalny dla # binów w każdym wymiarze, aby można było dostosować stopień rozróżniania podobnych kolorów.

image = new Bitmap("C:\\test.bmp", true); 
int x, y; 
// Loop through the images pixels to product 3d histogram 
for(x=0; x<image.Width; x++) 
{ 
    for(y=0; y<image.Height; y++) 
    { 
     Color pixelColor = image.GetPixel(x, y); 

     // Increment color count in appropriate cell of your 3d histogram here 
     ... 
    } 
} 
5

Spowoduje to wyświetlenie średniego koloru obrazu.

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

Nie sądzę, że wynik kwalifikuje się jako "kolor większościowy", ponieważ może nie być nawet jednego piksela, który jest średnim kolorem. – Kaniu

+0

Bardzo prawdziwe ... i dlatego poprosiłem o więcej szczegółów w moim komentarzu pod pytaniem. Brak odpowiedzi, więc to jest mój wpis. –

4

Spowoduje to wyświetlenie średniego koloru obrazu przy użyciu niebezpiecznego dostępu do wskaźnika. Uwaga: kod jest dostosowany tylko do 24bppRbb, może być dostosowany do innych formatów pikseli.

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); 
     } 
    } 

sedno: http://gist.github.com/349210

+0

+1 za wydajność. Wywoływanie GetPixel na każdym pojedynczym pikselu jest bardzo powolne. – RandomEngy

+1

Wyjątkowo powolny jest nieco przesady. Byłem w stanie wykorzystać metodę GetPixel do analizy klatek wideo przy rozdzielczości 15 klatek na sekundę 800x600. Jeśli więc plakat wystarczy przeanalizować jeden obraz, GetPixel jest więcej niż wystarczający. – CeejeeB

Powiązane problemy