- PR -

JMF BufferからBufferedImageへの変換

投稿者投稿内容
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2004-05-11 16:35
はい。ImageToBufferも試してみました。実際にやってみると、Bufferに変換したものを戻してやると、エラーは出なかったのですが、やはり画面が固まったまま、音声だけが流れるという感じでした。

今、バイトデータを直接いじって画像を編集できるように頑張ってます。
イメージデータさえ扱えていれば・・・(泣)
sakurai
会議室デビュー日: 2004/05/10
投稿数: 7
投稿日時: 2004-05-11 17:00
BufferedImageでお望みの処理までは完了できているのでしたら、
上のサンプルのRotationEffect.javaを参考にして、
BufferedImage.getData().getDataElements(0,0,width,height,type)
で得られる配列を出力のバッファにコピーするだけでいけると思うのですが、
どうでしょうか。

たぶん、fuzukiさんの示されたコードのように、
inputのバッファをoutputにそのまま代入するだけでは駄目そうです。
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2004-05-11 22:54
getDataElementsでやる方法が今一つ分からなかったのと、直接Bufferのデータをいじる方法をやっていた途中だったので、とりあえず今はこっちの方法でできないか試行錯誤しています。

画像の明度を上げるためにBufferのそれぞれのデータの値に100を足すようなプログラムを組んでみたのですが、なぜか真っ白である場所が真っ黒になるようです。全体的には明るくなっているので完全に間違いではないようですが。どこかで0が255になってしまっているようです。
憶測としてはintからbyteへのキャストの時に白と黒が逆になってしまっているのではないかと考えています。どうも考えている間に訳が分からなくってきてしまいました。

JMFのBuffer内のデータは、それぞれbyte配列になっていて順番にr1,g1,b1,r2,g2,b2...というような感じになっているはずです。ここでそれぞれのRGBをint型の変数に入れ、100を足してやり、その後、0から255の範囲に丸めてやって、byteでキャストして元の変数に入れてやるようにしています。

コード:
int ir1 = r1;
ir1 += 100; // 明度を上げる

if(ir1 > 255) // 0から255の範囲に丸める
  ir1 = 255;
else if(ir1 < 0)
  ir1 = 0;

r1 = (byte)ir1 // キャスト(ここで白黒反転してしまっている??)

// 以下、Bufferのデータに対して同様の処理を行う



ここで分からないのは、Javaのbyte型は符号付なので、-127から127の範囲でしか表せないような気がしますが、それならばそもそも255の値を画像中でどうやって表しているのでしょうか?
それと、最後でbyteにキャストしている箇所も、intで255が入っていれば最後の8ビットが代入されるはずなので、画像は白くなるはずです。

すみません。最初の表題と話題がずれてきてしまってますね。
sakurai
会議室デビュー日: 2004/05/10
投稿数: 7
投稿日時: 2004-05-12 01:54
こちらも100%試して書いているわけではないので違っていたらすみません。ただ、JMFの情報はすごく少ないと思っているので、どんどん参考になるコードを公開した方が良いと思います。

上で示された以下のコードについて、
引用:

int ir1 = r1;
ir1 += 100; // 明度を上げる


1行目の r1 は byte型だと思いますが、この場合 r1 が 0x80 以上の値はマイナスになってしまいます。なので、1行目は正しくは
コード:

int ir1 = r1 & 0xff;


がいいと思います。(まず、r1がintにキャストされ、下位8ビットのマスクでほしい値に変換されます。)


[ メッセージ編集済み 編集者: sakurai 編集日時 2004-05-12 01:58 ]
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2004-05-12 12:52
ありがとうございます。理解しました。0xffでビット演算してやることによって正の値にするのですね。これでうまくいきました。他の処理についてもこれで全て解決しました。

結局、byteデータを直接処理する方法でやることにより、途中でイメージに変換するよりも処理速度は速くできたと思います。(それでも私の世代遅れのラップトップでは辛いですが・・・)

昨晩思いついたのですが、他にもそれぞれのbyte型のRGBの値をひとまとめにしてintの配列に入れてやり、それをイメージ型に変換してやるという方法もありますね。イメージからbyteへはPixelGrabberを使用してピクセル毎のデータを取り出し、さらにRBGを抽出してやるという感じです。試していないのでバグはあるかもしれませんが、おそらく以下のような感じで出来るのではないかと思います。

コード:
  byte[] inData = (byte[]) inBuffer.getData();
  byte[] outData = (byte[]) outBuffer.getData();
  int r, g, b;
  int[] pixels = new int[inData.length / 3];

  // Get RGB data together and store each RGB in int array
  for(int h=0,i=0; i<inData.length; h++,i+=3)
  {
    r = (int)inData[i];
    g = (int)inData[i+1];
    b = (int)inData[i+2];
    pixels[h] = 0xFF000000 | r << 16 | g << 8 | b;
  }

  VideoFormat format = (VideoFormat)inBuffer.getFormat();
  Dimension size = format.getSize();
  int width = size.width;
  int height = size.height;

  // Generate an image from pixel data
  MemoryImageSource memoryImageSource = new MemoryImageSource(width, height, pixels, 0, width);
  Image image = Toolkit.getDefaultToolkit().createImage(memoryImageSource);

  // Do something with the image here...

  // Get pixel data from the image
  int[] RestoredPixels = new int[pixels.length];
  PixelGrabber pg = new PixelGrabber(image, 0, 0, width, height, RestoredPixels, 0, width);
  try
  {
    pg.grabPixels();
  }
  catch(InterruptedException e){}

  // Extract each R, G and B, and store them as a byte data
  for(int i=0,j=0; i<RestoredPixels.length; i++,j+=3)
  {
    r = ((RestoredPixels[i] >> 16) & 0xff);
    g = ((RestoredPixels[i] >> 8) & 0xff);
    b = (RestoredPixels[i] & 0xff);
    outData[i] = (byte)r;
    outData[i+1] = (byte)g;
    outData[i+2] = (byte)b;
  }



> ただ、JMFの情報はすごく少ないと思っているので、どんどん参考になるコードを公開した方が良いと思います。

そうですね。日本語情報はもちろん、英語の情報もまだとても少ないと感じました。JMFはこれからですね。APIやマニュアルに関しても翻訳途中のページとかがあるので、これからに期待したいですね。

とにかく、本当に助かりました。どうもありがとうございました。

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