- - PR -
BufferedImageからpixel情報をRGB個別に取得する
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2006-11-08 19:44
こんにちは。
現在、bmpファイルを読み込み・画素単位の処理を施し・jpeg画像として出力するプログラムを組んでいます。 bmpファイルの読み込みはImageIOを使用してできたのですが、読み込んだBufferedImageから画素情報を取得するところでつまづいています。 WritableRasterを作成し、DataBufferIntのgetElem()でどうやらpixel情報は取得できたようなのですが、どうもデータがおかしいような気がします。 【おかしい点】 2×2画素bmpファイルの画素値が [0][0] 0 0 0 [0][1] 255 0 0 [1][0] 0 255 0 [1][1] 0 0 255 (行・列・R・G・B順) となっているのに、getElem()で取得した情報を表示させてみると [0]0 [1]16711680 [2]255 [3]65280 となっています。 RGBの値がまとめてひとつの要素に入っているのだとしても、つじつまがあいません。 よろしければご教授願います。 プログラムは下記のように作成しました。 import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.image.*; import java.awt.image.BufferedImage; import java.io.*; import java.util.Iterator; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriter; import javax.imageio.plugins.jpeg.JPEGImageWriteParam; import javax.imageio.stream.ImageOutputStream; import java.util.Locale; public class pixcelTest { public static void main(String[] args) throws Exception{ int xsize = 2; int ysize = 2; int[] pixel = new int[xsize*ysize]; /*bmpファイル読み込み処理*/ FileInputStream fis = new FileInputStream("boo.bmp"); BufferedImage image = ImageIO.read(fis);//読み込んだイメージ BufferedImage cpyImage = new BufferedImage(xsize, ysize, BufferedImage.TYPE_INT_RGB);//コピー用イメージ Graphics2D g2d = cpyImage.createGraphics(); g2d.drawImage(image, 0, 0, xsize, ysize, null);//読み込んだイメージをコピー fis.close(); WritableRaster ras = cpyImage.getRaster(); DataBufferInt buffer = (DataBufferInt)(ras.getDataBuffer()); //pixel情報取得 for(int i = 0; i < xsize*ysize; i++) pixel2[i] = buffer.getElem(i); //pixel情報表示 for(int i = 0; i < xsize*ysize; i++) System.out.println(pixel2[i]); /*jpegファイル書き出し処理*/ ImageWriter writer = null; Iterator itr = ImageIO.getImageWritersByFormatName("jpeg"); if(itr.hasNext()){ writer = (ImageWriter) itr.next(); } ImageOutputStream ios = ImageIO.createImageOutputStream(new File("boo.jpg")); writer.setOutput(ios); JPEGImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault()); iwparam.setCompressionMode(iwparam.MODE_EXPLICIT); iwparam.setCompressionQuality(0.5f); writer.write(null, new IIOImage(cpyImage, null, null), iwparam); ios.flush(); writer.dispose(); ios.close(); } } | ||||||||
|
投稿日時: 2006-11-09 09:17
16進数に直すと 16711680 -> 0x00FF0000 255 -> 0x000000FF 65280 -> 0x0000FF00 となりますから、あまりおかしいようには思わないですが。 どのように辻褄が合わないとお考えですか? | ||||||||
|
投稿日時: 2006-11-09 11:44
nagiseさん、お返事ありがとうございます。
なるほど、16進数に変換するのですね。まったく頭から抜け落ちていました。
単純にRGBが連続した値として格納されているのなら、 [1]16711680 → R:167 G:116 B:80 のようになっているのかと思い、そうなると読み込んだファイルの画素値と一致しないために「おかしいな」と思っていました。 ここからさらにRGB各値を取得するには、 Rなら0x00FF0000 Gなら0x0000FF00 Bなら0x000000FF で、論理和をとることで可能になりそうですね。 nagiseさん、本当にありがとうございます。 もう1つ、WritableRasterを作成してDataBufferIntのgetElem()を使用する方法のほかに、ColorクラスのgetRGB()を使用する方法でRGB各値の取得に成功しました。 ソースコードは以下です。 int[][] pRED = new int[ysize][xsize]; int[][] pGREEN = new int[ysize][xsize]; int[][] pBLUE = new int[ysize][xsize]; for(int i=0; i<ysize ;i++){ for(int j=0; j<xsize ;j++){ Color pixel = new Color(image.getRGB(j, i)); pRED[i][j] = pixel.getRed(); pGREEN[i][j] = pixel.getGreen(); pBLUE[i][j] = pixel.getBlue(); } } 現在この2つの取得法があるのですが、どちらを使ったほうがよいなどの優劣はあるのでしょうか? | ||||||||
|
投稿日時: 2006-11-09 13:48
Colorオブジェクトを使う場合は、ループ内で画像のピクセル数分のColorオブジェクトを生成する(そして、すぐ破棄される)ことになります。 扱う画像ファイルが小さければ問題はありませんが、巨大な画像を扱う場合はGCが無駄に発生したりして、処理性能に影響が出てしまうかもしれません。 | ||||||||
|
投稿日時: 2006-11-09 15:42
java.awt.image.RescaleOpで目的の処理は実装できませんか?
必要ないならば、そんなクラスもあると参考までに。 | ||||||||
|
投稿日時: 2006-11-09 23:02
sawatさん、未記入さん、コメントありがとうございます。
なるほど、まだ試験用の2×2サイズしか扱っていないので検討してみる必要がありそうです。 巨大な画像というのが一般的にどのていどのサイズなのかはわかりませんが、扱う画像サイズは720×540です。
そのようなクラスもあるのですね、勉強になります。 明日にでも試してみようと思います。このクラスで目的の処理が実装できたときには、御報告いたします。 お二方とも、本当にありがとうございます。 | ||||||||
|
投稿日時: 2006-11-10 13:33
RasterのgetPixels()なら
最初から論理和とってビットシフトされたデータが取得できますよ。 | ||||||||
|
投稿日時: 2006-11-10 17:21
tori31001さん、アドバイスありがとうございます。
早速試してみました。…が、なにやら配列の宣言がおかしいらしく、 java.lang.ArrayIndexOutOfBoundsException: Coordinate out of bounds! とのエラー表示が出力されてしまいました。 作成したソースコードは以下です。 xsize:画像の横サイズ ysize:画像の縦サイズ です。 WritableRaster ras = image.getRaster(); int[] pixel = new int[ysize*xsize*3]; for(int i = 0; i < ysize; i++){ for(int j = 0; j < xsize*3; j++){ ras.getPixels(j, i, xsize, ysize, pixel); } } 用意したint型配列にRGB順で各値を挿入してくれるのかと思い、縦×横×3(RGB分)の領域を確保したのですが、どうやらちがっているようです。(ちなみに縦×横の領域確保でも同様のエラーメッセージがでます。) もうすこし格闘してみます。 |