- PR -

配列の中に占める各要素の割合を求めたい

1
投稿者投稿内容
Lyijykyyneleet
会議室デビュー日: 2005/11/25
投稿数: 11
お住まい・勤務地: 北海道
投稿日時: 2006-10-01 02:54
こんにちは。
現在、画像の色情報をPixelGrabberを使用して配列に収め、その配列の中に含まれる色の割合を求めるプログラムを作成しています。
とりあえず、以下のようなソースのプログラムを作成し、何の色が何パーセント存在するのかを出力させることに成功いたしました。
ところが、このプログラムだと、画像の色の種類が多いと出力が膨大な数になってしまい、データを取るのに適さない事が分かりました。
そこで、色素数の多い順10位程度までを昇順に並べたらどうか、と考えたのですが、色素の値と色素の数を対応させて並べ替えるにはどうすればよいのかが分からずに詰まっています。
うまく、色素の値と数を対応して並べ替える方法はないでしょうか。ご教授宜しくお願いします。

ソースコード:

<<GetParcentage.java>>

package imgAnalyzing.numeric;

import imgAnalyzing.PixelGrab;

import java.util.Arrays;

public class GetPercentage {

//配列に挿入した画像の色情報から各色の占める割合(Percentage)を算出するプログラム

public static void main(String args[]){

int count;
int i, j;
int c = 0;

String loadFileName = args[0];
PixelGrab pixelGrab = new PixelGrab();
int[] rgb = pixelGrab.getPixelData(loadFileName);

Arrays.sort(rgb);
int[] counterArray = new int[rgb.length];

for( i = 0; i < rgb.length; i = i + count){
count = 1;
for( j = i + 1; j < rgb.length; j++){
if(rgb[i] == rgb[j]){
count = count + 1;
}else{
System.out.println(rgb[i] + "=" + count);
System.out.println(count*100/rgb.length + "%");
break;
}
}

if( j == rgb.length){
System.out.println(rgb[i] + "=" + count);
System.out.println(count*100/rgb.length + "%");
}

counterArray[c] = count;
c = c + 1;

}

}


}

<<imgAnalyzing.PixelGrab.java>>

package imgAnalyzing;

import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class PixelGrab {
public int[] getPixelData(String loadFileName){

String fileName = loadFileName;
BufferedImage bufferedImage = null;
int width, height, size;
int[] rgb;

try {
System.out.println("Read file from : " + fileName);
bufferedImage = ImageIO.read(new File(fileName));
}catch(IOException e){ e.printStackTrace(); }

width = bufferedImage.getWidth();
height = bufferedImage.getHeight();
size = width * height;

rgb = new int[size];

PixelGrabber pixelGrabber = new PixelGrabber(bufferedImage, 0, 0, width, height, rgb, 0, width);

try{
pixelGrabber.grabPixels();
} catch(InterruptedException e){}

return rgb;

}
}
小僧
ぬし
会議室デビュー日: 2002/08/14
投稿数: 526
投稿日時: 2006-10-01 06:22
ちょっと考えてみました。

画像の色情報をラップしたクラスをTreeMapに追加。
キー値 = 色情報を文字列にした値。
色情報のカウントアップは、この追加したクラスに対して行う。
色情報のソートは、TreeMapのComparatorをちょっといじって、
ラップクラスの回数で判定するようにする。

考え方だけで、実装コードはございません。

[ メッセージ編集済み 編集者: 小僧 編集日時 2006-10-01 06:36 ]
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2006-10-01 10:54
こういう場合、要求仕様として、近接した色(たとえば RGB 値が (100, 100, 100) と (100, 100, 101))も厳密に区別するのか、それとも色を縮約していわゆるヒストグラムのように扱うのかで違ってきます。ヒストグラムなら簡単なのでここでは省き、以下はあくまでも厳密に区別することを考えます。

PixelGrabber を使われるということなので、RGB は最大で24ビット値の情報量という前提を付けることができます。2 の 24乗 = 16,777,216 なので、カウント用に、
int x[16777216];
という配列を用意します。たかだか 64MB です。
あとは、RGB 値でインデックスを特定して、その要素のカウントをカウントアップしていきます。

つぎにソートですがこれが多少面倒くさい。16,777,216件のソートを真面目にやって効率よくおこなえる手法は現在の技術ではないのですが、配列はいわゆるスパース(sparse)になっていて、要素値が0や1のものがほとんどなので、最初にそれらを配列のお尻のほうにどんどん移していきます。最後に、要素値が2以上の範囲のインデックスの配列の部分に対してのみ、通常のソート(java.util.Arrays.sort はマージソート)をおこないます。

と、言葉だけで書いてもなかなか伝わりにくいかもしれませんね。

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2006-10-02 09:08
引用:

unibonさんの書き込み (2006-10-01 10:54) より:
PixelGrabber を使われるということなので、RGB は最大で24ビット値の情報量という前提を付けることができます。2 の 24乗 = 16,777,216 なので、カウント用に、
int x[16777216];
という配列を用意します。たかだか 64MB です。
あとは、RGB 値でインデックスを特定して、その要素のカウントをカウントアップしていきます。



たかだか64Mって言える時代だものな〜。富豪的プログラミングですね。
色情報からカウントしている変数にダイレクトにアクセスできるのだから
ある意味では要素数が固定のハッシュとも言えるのでしょうかね

しかし、RGBが256階調のまんまカウントしても
いまひとつ嬉しい結果を得られない気がしますね。
16色パレットとかなら分布を見たくなる気もしますが。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2006-10-02 10:29
要素数 2^24 の配列を用意するなんて信じられない。いくらなんでもこれは富豪的プログラミングの範疇を越えてるでしょ。アルファ要素が必要になっただけで要素数 2^32 の配列を用意する必要が出てくる。

(一般的な)画像ということであれば、新しい画素を抽出するたびに HashMap に追加するだけでもいいと思う。実際の画像というのは、ものすごく偏りがあるので XGA サイズの 24ビット色の風景画でも実際の色数は 2,000色程度しかないことが多い。イラストっぽいのはさらに色数は少ない。なので新しい色を見つけたら HashMap に追加。すでに HashMap に格納されている色だったら、取り出して、カウント加算という方法でもある程度実用になる。

さらに高速化するには。完全ハッシュ値(hash = R * 65536 + G * 256 + B) を使うのではなく、わざとハッシュを衝突させる。ハッシュ値は 2^24 通りにばらけても効果はほとんどなく、5,000通り程度にばらければ効果十分。このとき、R, G, B の上位ビットよりも下位ビットでハッシュ値を計算したほうが値がばらけやすくてよい。

他の人も言ってるけど、厳密にカウントしても意味がないことが多い。もし近似色をまとめたいと思ったら「色差」についても調べてみて。RGB で色差を計算するよりも Lab 系に変換して色差を計算したほうが、人間の視覚に自然なカタチになる。


[ メッセージ編集済み 編集者: 未記入 編集日時 2006-10-02 10:30 ]
1

スキルアップ/キャリアアップ(JOB@IT)