JMFでビデオキャプチャ

まず、JMF (Java Media Framework) は Sunが配布してるJavaの標準の開発環境 (J2SE SDKとか)には含まれませんので、 別途ダウンロードしましょう。 JMFがないとビデオキャプチャできません。 またJMFをインストールする前にビデオカメラのドライバと Java開発環境をインストールしておきましょう。 今のところ動作確認済なのは Windows Xp + Logitech Quickcam Pro 4000 という組み合わせです。 JMF は MacOSには対応してません。 私も見よう見まねでやってみた段階なので、 詳しい原理まではよくわかってないところがあります。 例えば "vfw://0"って何?とか、 FrameGrabbingControl frameGrabber =(FrameGrabbingControl)player.getControl("javax.media.control.FrameGrabbingControl"); って何よとか (-_-:) とりあえずできましたよという報告だと思ってください。

なお比較的古い情報ですが、 Video for Linuxで同じようなことをやった話 Vine LinuxでQV-4000を使う などもあります。 Video for Linux でやってたことを全部JMFでもやってみようというのが趣旨です。

キャプチャしてプレビュー

キャプチャしてプレビューするだけなら、こんな簡単にできます。 キャプチャした動画をフレームに貼り付ける: PrevFrame.java。 キャプチャした動画をフルスクリーンでプレビュー: PrevFull.java

キャプチャした画像は Buffer というものに入っているが、 BufferからImageに変換して Graphics.drawImage() で描画したもの: GrabFrame.java。 Imageの中身(画素値とか)をいじるには ImageをさらにBufferedImageというものに変換しなくちゃなりません。 それについては以下に。

キャプチャしてフィルタかけて描画

ConvFrame.java。 Buffer に grab (キャプチャ) して、 BufferToImage() で Image に変換して、 Image を BufferedImage に drawImage() して、 BufferedImage に変換します。 BufferedImage を今度は Image に drawImage() して戻すんですが、 そのときフィルタ (この例では coOp) をかけることができます。 このフィルタは3×3のラプラシアンフィルタというもので、 エッジ抽出オペレータの一種ですね。 で、Imageを今度は JPanel に drawImage() して描画します。

javax.swing.Timer で再描画してるわけですが、 repaint() の直後に grab_proc() を呼んでキャプチャして、 100ミリ秒休んでいます。 つまり0.1秒おきにキャプチャしてます。 しつこいようですが、フレームレートは 10fps 程度ですね。 あまりフレームレートを上げると BufferToImage() で得られる Image が null になってしまいます。 つまり grab に失敗しているわけですね。 repaint() の直前に grab_proc() を呼んでもやはり Image が null になってしまいます。 この辺のタイミングは超アバウトですが、 ビデオカメラやPCの性質に合わせてフレームレートや grab のタイミングは調整しなきゃならんでしょう。

キャプチャサイズは Logitech Quickcam Pro 4000 (QV-4000) の場合デフォルトで 320x240 です。 このサイズを変えることもできるようですが、 めちゃくちゃ面倒臭いのでとりあえず放置します。

NegFrame.java。 こちらはできあいのフィルタを使わず、 画素値を取り出してぐりぐりいじった例です。 画素値反転させただけです。 BufferedImage.getRGB(x, y) で x, y の位置の画素値が取り出せて、 BufferedImage.setRGB(x, y) で画素値を格納できるのがわかります。 画素値は BufferedImage.TYPE_INT_RGB というものを使ってますが、 これは RGBがそれぞれ8bitで (R << 16)|(G << 8)| B になってます。

時間差分もやってみました: JikanSabun.java。 ちとソースがややこしいかもしれませんが、 EyeToy: Play の原理はこれです。

キャプチャしてしきい値処理して重心出して3Dぐりぐり

Thresh5.java。 動画をキャプチャしてしきい値処理で白黒画像にします。 暗領域の重心を求めてそのx座標で3D物体をぐりぐり動かしてみます。 つまり JMF と Java3D の連携ということをやってみました。 スクリーンショット。 右上はキャプチャのプレビュー。 左上はキャプチャしたフレームのしきい値処理。 暗領域の重心位置を赤い十字で表してます。 下はJava3D (Canvas3D) です。 その下のスライダーはしきい値を変えたり、3D物体の拡大率を変えたりするものです。 実行にはJava3DとStarfire Researchの Inspector3DS/Loader3DSが必要。