目標: 組み込みで用意されているCameraサービスとGUIコンポーネントを使って、カメラ映像をウィンドウに表示する。
materealライブラリでUSB接続されたWebカメラを使うには、Cameraサービスを初期化します。
import java.awt.image.RenderedImage; import java.io.File; import javax.imageio.ImageIO; import jp.digitalmuseum.mr.Matereal; import jp.digitalmuseum.mr.service.Camera; /** * Run a camera service to capture an image. * * @author Jun KATO */ public class RunCameraAndSaveImage { public static void main(String[] args) { // Run a camera. Camera camera = new Camera(); camera.start(); // Save an image captured from the camera. try { Thread.sleep(3000); RenderedImage image = camera.getImage(); ImageIO.write(image, "JPEG", new File("test.jpg")); } catch (Exception e) { e.printStackTrace(); } finally { Matereal.getInstance().dispose(); } } }
サービスを起動した直後は真っ黒な画像が撮れるため、わざと撮影まで3秒あけています。Matereal.getInstance().dispose()はライブラリの終了処理を呼び出します。これで起動したサービスがすべてシャットダウンされ、プログラムが終了します。
Cameraサービスは起動している間じゅうカメラの画像を取得し続けます。このように、画像を定期的に配信するサービスはImageProviderインタフェースを実装しています。materealに組み込みで用意されているサービスの中では、他に簡易2次元シミュレータのHakoniwaサービスもImageProviderインタフェースを実装しています。
さて、ImageProviderから画像を毎フレーム取得するためにはリスナインタフェースImageProvider.ImageListenerを実装します。したがって、カメラで撮影している映像を画面に表示するためには、JPanelクラスを継承し、ImageListenerインタフェースを実装した新しいパネルクラスを作成し、それをJFrameに追加する…といった工程が必要です。
利便性を考え、Materealには組み込みでImageProviderの画像を表示するためのGUIコンポーネントImageProviderPanelが用意されています。このコンポーネントは、使い終わったときにリスナの登録を外すためdispose()を呼ぶ必要があります。このような終了処理を伴うコンポーネント(DisposableComponent)を表示するために、JFrameを継承したGUIコンポーネントDisposeOnCloseFrameが用意されています。
実際のコードはRunCamera.javaのようになります。(以下転載)
import jp.digitalmuseum.mr.Matereal; import jp.digitalmuseum.mr.gui.*; import jp.digitalmuseum.mr.service.Camera; /** * Run a camera service and show captured images. * * @author Jun KATO */ public class RunCamera { public static void main(String[] args) { // Run a camera. Camera camera = new Camera(); camera.start(); // Make and show a window for showing captured image. DisposeOnCloseFrame frame = new DisposeOnCloseFrame( new ImageProviderPanel(camera)) { private static final long serialVersionUID = 1L; @Override public void dispose() { super.dispose(); // Shutdown Matereal when the window is closed. Matereal.getInstance().dispose(); } }; frame.setFrameSize(camera.getWidth(), camera.getHeight()); } }
最近のPCではカメラを複数台繋ぐことも珍しくありません。そのような場合は、ユーザに使用するカメラを選択してもらいましょう。
例えば、先のソースにimport宣言を加え、
import javax.swing.JOptionPane;
選択ダイアログを表示して、得られた結果を引数としてCameraサービスをインスタンス化することができます。
// Let users select a device to capture images. String identifier = (String) JOptionPane.showInputDialog(null, "Select a device to capture images.", "Device list", JOptionPane.QUESTION_MESSAGE, null, Camera.queryIdentifiers(), null); Camera camera; if ((identifier != null) && (identifier.length() > 0)) { camera = new Camera(identifier); } else { return; } camera.start();
なお、カメラのキャプチャ解像度を指定するにはcamera.start()より前にcamera.setSize(800, 600)のようにサイズ指定を挟みます。1)
以上の内容がサンプルコードのRunCameraWithDialog.javaに書かれています。