2010-12-13 9 views
9

Ich möchte die am häufigsten verwendete Farbe aus einem Bild erhalten. Ich benutze Java und möchte die vorherrschende Farbe haben. Gibt es irgendeine cbir java Bibliothek, um das zu machen?Die gebräuchlichste Farbe eines Bildes erhalten

Dank

+0

Was genau meinen Sie mit "vorherrschende"? – Thomas

+0

Die am häufigsten verwendete Farbe im Bild? –

Antwort

2

Sie kann Schleife der BufferedImage (zwei Schleifen - ein von 0 bis Breite und ein von 0 bis Höhe) und getRgb(x, y) den Anruf bekommen. Zählen Sie dann jeden anderen Wert. Sie können hierfür eine Map verwenden (key = color, value = Anzahl der Vorkommen).

+0

Wirklich? Es könnte bis zu 16.581.375 Farben geben. – dogbane

+0

Sie sorgen sich also um die Erinnerung? – Bozho

+2

Ja. Könnte nur mein PC sein, aber ich habe ein OOM nach etwa 4 Millionen Farben in meiner Karte. – dogbane

9

Wie genau soll das sein? Sie können den Ansatz von Bozhos verwenden und eine Schleife über das gesamte Bild ziehen, dies kann jedoch für große Bilder langsam sein. Es gibt 16777216 mögliche RGB-Werte und das Beibehalten der Zähler in einer Map ist nicht sehr effizient.

Eine Alternative besteht darin, das Bild unter Verwendung von getScaledInstance neu zu skalieren, um es auf eine kleinere Version, z.B. ein 1x1 Bild und dann getRGB, um die Farbe dieses Pixels zu erhalten. Sie können mit verschiedenen Resampling-Algorithmen wie SCALE_REPLICATE und SCALE_AREA_AVERAGING experimentieren, um zu sehen, was für Sie am besten funktioniert.

+0

Beachten Sie, dass dieser Ansatz zu einem anderen Ergebnis führt als der Ansatz von Bozhos. Im letzteren Fall wird die Farbe, die am häufigsten im Bild erscheint, bestimmt, während Sie versuchen, etwas wie "die durchschnittliche Farbe" zu finden - ein unklar definierter Begriff, aber es ist klar, dass die zurückgegebene Farbe möglicherweise gar nicht im Original erscheint Bild.Ich sage nicht, dass eine Herangehensweise besser ist als die andere, ich denke, dass das ursprüngliche Plakat klarstellen muss, wonach er sucht. – Thomas

+0

Ja, das verstehe ich, weshalb ich gefragt habe, wie viel Genauigkeit erforderlich ist. Wenn Sie den 'ReplicateScaleFilter' verwenden, erhalten Sie eine Farbe, die im Originalbild erscheint, da" Zeilen und Spalten von Pixeln nicht verkleinert werden ". Es führt kein "Mischen" wie der "AreaAveragingScaleFilter" durch. – dogbane

+1

Woher hast du die Nummer 16581375? Wenn wir über 8 Bits pro Kanal sprechen, gibt es 2^24 = 16777216 mögliche RGB-Werte. – Jesper

3

Was ist, wenn Sie Ihr Bild als ein großes lineares Pixel-Array betrachten und danach alles, was Sie tun müssen, einfach sortieren? Wenn Sie es sortiert haben, können Sie den längsten Teil der gleichen Werte zählen.

3

Je nachdem, wie genau Sie den Farbwert benötigen, sollten Sie "Farbeimer" berücksichtigen, die ähnliche Farben sammeln, um Speicherprobleme zu vermeiden. Dies würde bedeuten, den Farbraum in "Intervalle" von Farben aufzuteilen, wobei alle Farben, die ähnlich (d. H. Nahe beieinander) sind, als die gleiche Farbe gezählt werden. Durch Ändern der Intervallgröße haben Sie die Möglichkeit, den Kompromiss zwischen Genauigkeit und Speicherverbrauch direkt zu manipulieren.


Bearbeiten: Was Sie wollen, ist im Grunde ein Histogramm (gehen Sie nach oben). Es gibt höchstwahrscheinlich gut etablierte Standardlösungen, um eine davon effizient zu berechnen.

+0

Ja, zählen Sie einfach jede Farbe (ziemlich einfach den Farbwert als Index für ein Array von Ganzzahlen zu verwenden), den Sie schnell erhöhen können. Das Array wird kleiner sein als das analysierte Bild und das Inkrementieren einer ganzen Zahl ist in den meisten (allen?) Programmiersprachen ziemlich billig. – Eno

1

Ich würde den Farbton jedes Pixels und dann die Kardinalität jedes Farbtons berechnen (erstellt ein Histogramm). Vielleicht durch Sättigung gewichten. Wenden Sie dann einen Tiefpassfilter an und suchen Sie das Maximum. Konvertieren Sie den Farbton schließlich wieder in RGB.

Dies setzt voraus, dass wenn Sie nur die rote Ebene eines Bildes hätten, das Ergebnis "rot" sein sollte, nicht ein bisschen rosa.

4

Danke für die Antworten. Hier ist ein praktisches Beispiel für Bozhos Methode. Es filtert auch Weiß/Grau/Schwarz heraus.

import java.awt.image.BufferedImage; 
import java.io.File; 
import java.util.Collections; 
import java.util.Comparator; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.LinkedList; 
import java.util.List; 
import java.util.Map; 
import javax.imageio.ImageIO; 
import javax.imageio.ImageReader; 
import javax.imageio.stream.ImageInputStream; 


public class ImageTester { 


    public static void main(String args[]) throws Exception { 
     File file = new File("C:\\Users\\Andrew\\Desktop\\myImage.gif"); 
     ImageInputStream is = ImageIO.createImageInputStream(file); 
     Iterator iter = ImageIO.getImageReaders(is); 

     if (!iter.hasNext()) 
     { 
      System.out.println("Cannot load the specified file "+ file); 
      System.exit(1); 
     } 
     ImageReader imageReader = (ImageReader)iter.next(); 
     imageReader.setInput(is); 

     BufferedImage image = imageReader.read(0); 

     int height = image.getHeight(); 
     int width = image.getWidth(); 

     Map m = new HashMap(); 
     for(int i=0; i < width ; i++) 
     { 
      for(int j=0; j < height ; j++) 
      { 
       int rgb = image.getRGB(i, j); 
       int[] rgbArr = getRGBArr(rgb);     
       // Filter out grays....     
       if (!isGray(rgbArr)) {     
         Integer counter = (Integer) m.get(rgb); 
         if (counter == null) 
          counter = 0; 
         counter++;         
         m.put(rgb, counter);     
       }     
      } 
     }   
     String colourHex = getMostCommonColour(m); 
     System.out.println(colourHex); 
    } 


    public static String getMostCommonColour(Map map) { 
     List list = new LinkedList(map.entrySet()); 
     Collections.sort(list, new Comparator() { 
       public int compare(Object o1, Object o2) { 
       return ((Comparable) ((Map.Entry) (o1)).getValue()) 
        .compareTo(((Map.Entry) (o2)).getValue()); 
       } 
     });  
     Map.Entry me = (Map.Entry)list.get(list.size()-1); 
     int[] rgb= getRGBArr((Integer)me.getKey()); 
     return Integer.toHexString(rgb[0])+" "+Integer.toHexString(rgb[1])+" "+Integer.toHexString(rgb[2]);   
    }  

    public static int[] getRGBArr(int pixel) { 
     int alpha = (pixel >> 24) & 0xff; 
     int red = (pixel >> 16) & 0xff; 
     int green = (pixel >> 8) & 0xff; 
     int blue = (pixel) & 0xff; 
     return new int[]{red,green,blue}; 

    } 
    public static boolean isGray(int[] rgbArr) { 
     int rgDiff = rgbArr[0] - rgbArr[1]; 
     int rbDiff = rgbArr[0] - rgbArr[2]; 
     // Filter out black, white and grays...... (tolerance within 10 pixels) 
     int tolerance = 10; 
     if (rgDiff > tolerance || rgDiff < -tolerance) 
      if (rbDiff > tolerance || rbDiff < -tolerance) { 
       return false; 
      }     
     return true; 
    } 
} 
+0

sieht aus wie eine teure Art zu tun, indem über jedes Pixel iteriert wird. Es wird leicht für ein 5MP Foto sterben – Taranfx

+0

Wenn das Bild massiv ist, ändern Sie es zuerst. –

0

Andrew Dyster Code funktioniert gut, schnelle Reaktion in android

import java.util.Collections; 
import java.util.Comparator; 
import java.util.HashMap; 
import java.util.LinkedList; 
import java.util.List; 
import java.util.Map; 

import android.graphics.Bitmap; 

public class ImageTester { 

    public interface ImageColor { 
     void onImageColor(int r, int g, int b); 
    } 

    @SuppressWarnings({ "unchecked", "rawtypes" }) 
    public static void getMostCommonColour(final Bitmap image, 
      final ImageColor heColor) { 
     new Thread(new Runnable() { 
      private int rgb; 

      @Override 
      public void run() { 
       int height = image.getHeight(); 
       int width = image.getWidth(); 
       Map m = new HashMap(); 
       int boderWid = width/4; 
       int borderHeigh = height/4; 

       for (int i = boderWid; i < width - boderWid;) { 
        for (int j = borderHeigh; j < height - borderHeigh;) { 
         try { 
          rgb = image.getPixel(i, j); 

         } catch (Exception e) { 
          continue; 
         }finally{ 
          i += 20; 
          j += 20; 
         } 
         int[] rgbArr = getRGBArr(rgb); 
         // Filter out grays.... 
         if (!isGray(rgbArr)) { 
          Integer counter = (Integer) m.get(rgb); 
          if (counter == null) 
           counter = 0; 
          counter++; 
          m.put(rgb, counter); 

         } 

        } 
       } 
       List list = new LinkedList(m.entrySet()); 
       Collections.sort(list, new Comparator() { 
        public int compare(Object o1, Object o2) { 
         return ((Comparable) ((Map.Entry) (o1)).getValue()) 
           .compareTo(((Map.Entry) (o2)).getValue()); 
        } 
       }); 
       Map.Entry me = (Map.Entry) list.get(list.size() - 1); 
       int[] rgb = getRGBArr((Integer) me.getKey()); 
       heColor.onImageColor(rgb[0], rgb[1], rgb[2]); 

      } 
     }).start(); 
    } 

    public static int[] getRGBArr(int pixel) { 
     int red = (pixel >> 16) & 0xff; 
     int green = (pixel >> 8) & 0xff; 
     int blue = (pixel) & 0xff; 
     return new int[] { red, green, blue }; 

    } 

    public static boolean isGray(int[] rgbArr) { 
     int rgDiff = rgbArr[0] - rgbArr[1]; 
     int rbDiff = rgbArr[0] - rgbArr[2]; 
     int tolerance = 10; 
     if (rgDiff > tolerance || rgDiff < -tolerance) 
      if (rbDiff > tolerance || rbDiff < -tolerance) { 
       return false; 
      } 
     return true; 
    } 
} 
Verwandte Themen