9

画像から最も一般的な色を取得したいと思います。私は Java を使用しており、最も優勢な色を使用したいと考えています。これを行うためのcbir Javaライブラリはありますか?

ありがとう

4

7 に答える 7

10

これをどれだけ正確にしたいですか?Bozhos のアプローチを使用して画像全体をループすることはできますが、これは大きな画像では遅くなる可能性があります。16777216 の可能な RGB 値があり、それらのカウンターを Map に保持することはあまり効率的ではありません。

別の方法として、 を使用して画像をリサンプリングしgetScaledInstance、1x1 画像などの小さいバージョンに縮小してから、 を使用getRGBしてそのピクセルの色を取得する方法があります。SCALE_REPLICATESCALE_AREA_AVERAGINGなどのさまざまなリサンプリング アルゴリズムを試して、最適なものを確認できます。

于 2010-12-13T09:33:44.460 に答える
4

答えてくれてありがとう。これが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;
    }
}
于 2011-06-06T09:25:46.570 に答える
3

画像をピクセルの大きな線形配列と見なし、その後は並べ替えるだけでよいとしたらどうでしょうか? ソートすると、同じ値の最も長い部分を数えることができます。

于 2010-12-13T10:16:26.193 に答える
3

色の値をどの程度正確にする必要があるかに応じて、メモリの問題を回避するために、類似した色を収集する「カラー バケット」を検討することをお勧めします。これは、色空間を色の「間隔」に分割することを意味します。ここでは、十分に類似している (つまり、互いに近い) すべての色が同じ色としてカウントされます。間隔のサイズを変更することで、精度とメモリ消費量のトレードオフを直接操作できます。


編集:基本的にはヒストグラムが必要です(調べてください)。それらの1つを効率的に計算するための確立された標準的なソリューションがおそらくあります。

于 2010-12-13T10:17:22.113 に答える
2

BufferedImage(2 つのループ - 1 つは 0 から幅まで、もう 1 つは 0 から高さまで) をループして、呼び出しを取得できますgetRgb(x, y)。次に、それぞれの値を数えます。そのためにa を使用できますMap(キー = 色、値 = 出現回数)。

于 2010-12-13T09:11:27.563 に答える
1

各ピクセルの色相を計算し、次に各色相のカーディナリティを計算します (ヒストグラムを作成します)。おそらく彩度による重み付け。次に、ローパス フィルターを適用し、最大値を見つけます。最後に色相から RGB に変換します。

これは、画像の赤い面だけがある場合、結果をピンクの色合いではなく「赤」にすることを前提としています。

于 2010-12-13T14:56:50.377 に答える
0

アンドリュー・ダイスターのコードは正常に動作しており、アンドロイドでの迅速な対応

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;
    }
}
于 2014-06-17T14:15:58.193 に答える