[java]BufferedImageからピクセルの値を配列へ移す/コード2パターンと速度比較

 BufferedImageを処理していて、どちらを選んだほうがよいか決めかねたため、2パターンコーディングして速度を比較しました。

  1. BufferedImageからgetRGBを使ってint[]配列を取得
  2. BufferedImageからWritableRasterを取得、さらにDataBufferを取得してそこからgetDataする方法。

この2種類を比較しています。なお、コード的には1.のほうが圧倒的にシンプルで、DataBuffer方式の方が実際色んな画像を読み込ませるなら便利でもありますが分岐処理など一寸大変かもです。

広告

getRGBを使って配列を取得する方法

static public void readImageFromGetRGB(File t){
long time1=0;
long time2 = 0;
for(int i=0; i<10;i++){
time1 = System.currentTimeMillis();
try {
BufferedImage bimg = ImageIO.read(t);
int w = bimg.getWidth();
int[] pixel = bimg.getRGB(0, 0, w, bimg.getHeight(), null, 0, w);
//System.out.println(pixel.length);
} catch (IOException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
time2 = System.currentTimeMillis();
System.out.println("use getRGB: "+(time2-time1));
}
}
シンプルイズベストな手法です。なおDataBufferからgetDataする方法のコードにもこちらにもfor文ループで10回まわすようになっていますが、これは計算時間計測のためです。若しコードを参考にしようという方がいらっしゃいましたら、適宜省いてお考え下さい。

DataBufferからgetDataする方法

コードは以下の通りです。

static public void readImageFromRasterTest(File t){
long time1=0;
long time2 = 0;
for(int i=0; i<10;i++){
time1 = System.currentTimeMillis();
try {
BufferedImage bimg = ImageIO.read(t);
int w = bimg.getWidth();
DataBuffer buf = bimg.getRaster().getDataBuffer();
if(buf.getDataType() == DataBuffer.TYPE_INT){
System.out.println("TYPE_INT");
int[] pixel = ((DataBufferInt)buf).getData();
//System.out.println(pixel.length);
}else if(buf.getDataType() == DataBuffer.TYPE_BYTE){
//System.out.println("TYPE_BYTE");
byte[] pixel = ((DataBufferByte)buf).getData();
//System.out.println(pixel.length);
}
} catch (IOException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
time2 = System.currentTimeMillis();
System.out.println("use getRaster: "+(time2-time1));
}
}

見ての通り、DataBufferがどれを格納しているかを判定して配列を考えねばなりません。なおそのかわり、RGB(ある場合はA)に分かれた値が配列の中にぶち込まれます。たとえばRGBで幅w、高さhの画像から(x,y)のG成分を取得するなら、pixel[(x+wy-1)3+2]あたりを参照すればいい…はず。間違っていたらコメントなどでお教えいただけると幸いです。

比較

 それぞれ別の画像ファイル(ただし中身の画像は一緒)を読み込ませて計測しました。なお同じコード内に書いていますが、それぞれの出力を計測する際はもう一方をコメントアウトして実行されないようにしています。
まずgetRGBでの出力。
use getRGB: 110
use getRGB: 22
use getRGB: 19
use getRGB: 23
use getRGB: 19
use getRGB: 25
use getRGB: 20
use getRGB: 19
use getRGB: 20
use getRGB: 19

次に、getRasterでの出力。

use getRaster: 83
use getRaster: 9
use getRaster: 8
use getRaster: 8
use getRaster: 8
use getRaster: 8
use getRaster: 8
use getRaster: 9
use getRaster: 8
use getRaster: 8

比較してみると、getRasterのほうが速い、のですが、最初がどちらも遅い。
ということで、試しに、

File test3 = Paths.get(str3).toFile();
try {
BufferedImage b_img = ImageIO.read(test3);
} catch (IOException e1) {
// TODO 自動生成された catch ブロック
e1.printStackTrace();
}
というのを追加してみました。str3は先の画像処理に使われたファイルと別ファイルのパスですが、そのファイルの中身の画像は先の実験に使ったものと同じです。
すると、
getRGBでは
use getRGB: 31
use getRGB: 21
use getRGB: 20
use getRGB: 19
use getRGB: 33
use getRGB: 25
use getRGB: 28
use getRGB: 25
use getRGB: 19
use getRGB: 27

getDataするほうでは
use getRaster: 10
use getRaster: 8
use getRaster: 8
use getRaster: 8
use getRaster: 9
use getRaster: 8
use getRaster: 9
use getRaster: 8
use getRaster: 8
use getRaster: 8

となりました。どうも、一度ImageIOを開くのに時間がかかるみたいです。でも基本的に、getRasterがはやいみたいですね。

その他コメントなど

 一寸求めてみましたが、実を言うとgetRasterしてgetDataBufferしてgetDataするのは速いのは早いし、それなりにカラースペースに従って配列を出してくれるのですが、例えばint[][]の二次元配列にぶち込んで画像比較なんかする場合は処理を書くコードがだいぶめんどくさくなる可能性が大いにあります。もしかしたらその辺をラップしてるからこの速度なのかもしれませんね。で、どれだけめんどくさい可能性があるかっていうと、あれです…。→ドキュメントにもあるように、カラースペースさんっていっぱいあるんですよね…。
 なんていうか、すごい余裕ができたときに構築できるならしよう、という感じ。扱うカラースペースが決まっているならgetData一択かなあ、とも思いました。

広告

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA