【问题标题】:Getting the most common color of an image获取图像最常见的颜色
【发布时间】:2011-05-24 13:18:48
【问题描述】:

我想从图像中获取最常见的颜色。我使用 Java,我希望拥有最主要的颜色。有没有 cbir java 库来做这个?

谢谢

【问题讨论】:

  • 你所说的“主要”是什么意思?
  • 图片中最常见的颜色?

标签: java colors cbir


【解决方案1】:

您希望它有多准确?您可以使用 Bozhos 的方法并循环遍历整个图像,但这对于大图像可能会很慢。有 16777216 个可能的 RGB 值,在 Map 中为它们保留计数器并不是很有效。

另一种方法是使用getScaledInstance 重新采样图像以将其缩小到更小的版本,例如1x1 图像,然后使用getRGB 获取该像素的颜色。您可以尝试不同的重采样算法,例如 SCALE_REPLICATESCALE_AREA_AVERAGING,看看哪种算法最适合您。

【讨论】:

  • 请注意,这种方法的结果与 Bozhos 的方法不同。在后者中,图像中最常出现的颜色是在您的方法试图找到类似“平均颜色”之类的东西时确定的——这是一个定义不明确的概念,但很明显,返回的颜色甚至可能不会出现在原始颜色的任何地方图片。我并不是说一种方法比另一种更好,我想原始发布者必须澄清他/她在寻找什么。
  • 是的,我明白这一点,因此我问需要多少准确度。如果您使用ReplicateScaleFilter,您将获得一种出现在原始图像中的颜色,因为它“省略了像素行和列以按比例缩小”。它不会像AreaAveragingScaleFilter 那样做任何“混合”。
  • 你从哪里得到 16581375 的号码?如果我们谈论的是每个通道 8 位,则有 2^24 = 16777216 个可能的 RGB 值。
【解决方案2】:

感谢您的回答。这是 Bozho 方法的一个实际例子。它还会过滤掉白色/灰色/黑色。

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

【讨论】:

  • 通过迭代每个像素看起来像是一种昂贵的方式。 5MP 照片很容易死
  • 如果图片很大,先调整大小。
【解决方案3】:

如果您将图像视为一个大的线性像素阵列,然后您所要做的就是对它进行排序怎么办?排序后,您可以计算相同值的最长部分。

【讨论】:

    【解决方案4】:

    根据您需要颜色值的精确程度,您可能需要考虑收集相似颜色的“颜色桶”以避免内存问题。这意味着将颜色空间划分为颜色的“间隔”,其中足够相似(即靠近在一起)的所有颜色都被视为相同颜色。通过更改间隔大小,您可以直接在准确性和内存消耗之间进行权衡。


    编辑:你想要的基本上是一个直方图(去查一下)。很可能有成熟的标准解决方案可以有效地计算其中之一。

    【讨论】:

    • 是的,只需计算可以快速递增的每种颜色(很容易将颜色值用作整数数组的索引)。该数组将小于正在分析的图像,并且在大多数(所有?)编程语言中递增一个整数非常便宜。
    【解决方案5】:

    您可以循环BufferedImage(两个循环 - 一个从 0 到宽度,一个从 0 到高度),然后调用 getRgb(x, y)。然后计算每个不同的值。您可以为此使用 Map(键 = 颜色,值 = 出现次数)。

    【讨论】:

    • 真的吗?最多可以有 16,581,375 种颜色。
    • 是的。可能只是我的电脑,但在我的地图中有大约 400 万种颜色后,我得到了 OOM。
    【解决方案6】:

    我会计算每个像素的色调,然后计算每个色调的基数(创建一个直方图)。也许按饱和度加权。然后,应用低通滤波器,并找到最大值。最后从色调转换回 RGB。

    这假设如果您只有图像的红色平面,您希望结果是“红色”,而不是某种粉红色。

    【讨论】:

      【解决方案7】:

      Andrew Dyster 代码运行良好,在 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;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-07-17
        • 1970-01-01
        • 2011-03-15
        • 1970-01-01
        • 1970-01-01
        • 2010-12-17
        • 1970-01-01
        • 2010-12-19
        • 2016-03-09
        相关资源
        最近更新 更多