--- /dev/null
+/**
+ * VFM+ARToolkitテストプログラム
+ * カメラから取り込んだデータからマーカーを検出して、一致度と変換行列を表示します。
+ * (c)2008 A虎@nyatla.jp
+ * airmail(at)ebony.plala.or.jp
+ * http://nyatla.jp/
+ */
+package jp.nyatla.nyartoolkit.qt.sample;
+
+import jp.nyatla.nyartoolkit.NyARException;
+import jp.nyatla.nyartoolkit.qt.utils.*;
+
+import java.awt.*;
+
+import jp.nyatla.nyartoolkit.core.*;
+import jp.nyatla.nyartoolkit.detector.*;
+
+
+public class NyarToolkitLinkTest extends Frame implements QtCaptureListener
+{
+ private final String CARCODE_FILE ="../../Data/patt.hiro";
+ private final String PARAM_FILE ="../../Data/camera_para.dat";
+ private QtCameraCapture capture;
+ private NyARSingleDetectMarker nya;
+ private QtNyARRaster_RGB raster;
+ private NyARTransMatResult trans_mat_result=new NyARTransMatResult();
+
+ public NyarToolkitLinkTest() throws NyARException,NyARException
+ {
+ setTitle("QtCaptureTest");
+ setBounds(0,0,320+64,240+64);
+ //キャプチャの準備
+ capture=new QtCameraCapture(320,240,30f);
+ capture.setCaptureListener(this);
+
+ //NyARToolkitの準備
+ NyARParam ar_param=new NyARParam();
+ NyARCode ar_code =new NyARCode(16,16);
+ ar_param.loadFromARFile(PARAM_FILE);
+ ar_param.changeSize(320,240);
+ nya=new NyARSingleDetectMarker(ar_param,ar_code,80.0);
+ ar_code.loadFromARFile(CARCODE_FILE);
+ //キャプチャイメージ用のラスタを準備
+ raster=new QtNyARRaster_RGB(320,240);
+ }
+
+
+
+ public void onUpdateBuffer(byte[] pixels)
+ {
+ try{
+ //キャプチャしたバッファをラスタにセット
+ raster.setBuffer(pixels);
+
+ //キャプチャしたイメージを表示用に加工
+ Image img= raster.createImage();
+
+ Graphics g = getGraphics();
+ double[][] atm=null;
+
+ //マーカー検出
+ boolean is_marker_exist=nya.detectMarkerLite(raster,100);
+ if(is_marker_exist){
+ //変換行列を取得
+ nya.getTransmationMatrix(this.trans_mat_result);
+ atm=this.trans_mat_result.getArray();
+ }
+ //情報を画面に書く
+ g.drawImage(img, 32, 32,this);
+ if(is_marker_exist){
+ g.drawString("マーカー検出:"+nya.getConfidence(),32,50);
+ for(int i=0;i<3;i++){
+ for(int i2=0;i2<4;i2++){
+ g.drawString("["+i+"]["+i2+"]"+atm[i][i2],32,50+(1+i2*3+i)*16);
+ }
+
+ }
+ }else{
+ g.drawString("マーカー未検出:",32,100);
+ }
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+
+
+
+
+ }
+ private void startCapture()
+ {
+ try{
+ capture.start();
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+ public static void main(String[] args) {
+ try{
+ NyarToolkitLinkTest mainwin = new NyarToolkitLinkTest();
+ mainwin.setVisible(true);
+ mainwin.startCapture();
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+
+ }
+
+}
--- /dev/null
+/**
+ * VFMキャプチャテストプログラム
+ * (c)2008 A虎@nyatla.jp
+ * airmail@ebony.plala.or.jp
+ * http://nyatla.jp/
+ */
+package jp.nyatla.nyartoolkit.qt.sample;
+
+import jp.nyatla.nyartoolkit.NyARException;
+import jp.nyatla.nyartoolkit.qt.utils.*;
+
+import java.awt.*;
+
+
+
+public class QtCaptureTest extends Frame implements QtCaptureListener{
+ public QtCaptureTest() throws NyARException
+ {
+ setTitle("QtCaptureTest");
+ setBounds(0,0,320+64,240+64);
+ capture=new QtCameraCapture(320,240,30f);
+ capture.setCaptureListener(this);
+ //キャプチャイメージ用のラスタを準備
+ raster=new QtNyARRaster_RGB(320,240);
+ }
+
+
+
+ private QtCameraCapture capture;
+ private QtNyARRaster_RGB raster;
+ public void onUpdateBuffer(byte[] pixels)
+ {
+ raster.setBuffer(pixels);
+ Image img=raster.createImage();
+ Graphics g = getGraphics();
+ g.drawImage(img, 32, 32,this);
+ }
+ private void startCapture()
+ {
+ try{
+ capture.start();
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+ public static void main(String[] args) {
+ try{
+ QtCaptureTest mainwin = new QtCaptureTest();
+ mainwin.setVisible(true);
+ mainwin.startCapture();
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+
+ }
+
+}
--- /dev/null
+/**\r
+ * QuickTimeお手軽キャプチャクラス\r
+ * (c)2008 arc@dmz, A虎@nyatla.jp\r
+ * arc@digitalmuseum.jp\r
+ * http://nyatla.jp/\r
+ */\r
+package jp.nyatla.nyartoolkit.qt.utils;\r
+\r
+import java.awt.Dimension;\r
+import java.awt.event.ActionEvent;\r
+import java.awt.event.ActionListener;\r
+import java.io.File;\r
+\r
+import javax.swing.Timer;\r
+\r
+import quicktime.QTException;\r
+import quicktime.QTSession;\r
+import quicktime.io.QTFile;\r
+import quicktime.qd.PixMap;\r
+import quicktime.qd.QDConstants;\r
+import quicktime.qd.QDGraphics;\r
+import quicktime.qd.QDRect;\r
+import quicktime.std.StdQTConstants;\r
+import quicktime.std.movies.Movie;\r
+import quicktime.std.movies.media.DataRef;\r
+import quicktime.std.sg.SGVideoChannel;\r
+import quicktime.std.sg.SequenceGrabber;\r
+import quicktime.util.RawEncodedImage;\r
+\r
+import jp.nyatla.nyartoolkit.NyARException;\r
+\r
+\r
+public class QtCameraCapture implements ActionListener\r
+{\r
+\r
+ private Dimension image_size;\r
+ private QtCaptureListener capture_listener;\r
+\r
+ protected float fps = 30; // キャプチャ画像を取得するfps\r
+ protected byte[] pixels; // キャプチャ画像の実データを保持するバイト型配列\r
+\r
+ // キャプチャに使うタイマー\r
+ private Timer timer;\r
+\r
+ // QTJava用のあれこれ\r
+ private QDGraphics graphics;\r
+ private QDRect bounds;\r
+ private SequenceGrabber grabber;\r
+ private SGVideoChannel channel;\r
+ private RawEncodedImage rawEncodedImage;\r
+ private Movie movie;\r
+\r
+ // ピクセルフォーマット変換用の一時変数\r
+ private int[] pixels_int;\r
+ \r
+ public static final int PIXEL_FORMAT_RGB = quicktime.util.EndianOrder.isNativeLittleEndian() ?\r
+ QDConstants.k32BGRAPixelFormat : QDGraphics.kDefaultPixelFormat;\r
+ public QtCameraCapture(int i_width,int i_height,float i_rate)\r
+ {\r
+ image_size = new Dimension(i_width,i_height);\r
+ fps = i_rate;\r
+ }\r
+ public Dimension getSize()\r
+ {\r
+ return image_size;\r
+ }\r
+ public byte[] readBuffer() throws NyARException\r
+ {\r
+ if(grabber==null){\r
+ throw new NyARException();\r
+ }\r
+ return pixels;\r
+ }\r
+ public void setCaptureListener(QtCaptureListener i_listener) throws NyARException\r
+ {\r
+ if(grabber!=null){\r
+ throw new NyARException();\r
+ }\r
+ capture_listener=i_listener;\r
+ \r
+ }\r
+\r
+ public void prepSetInput(Object input) throws QTException {\r
+ QTSession.open();\r
+ bounds = new QDRect(image_size.width, image_size.height);\r
+ graphics = new QDGraphics(\r
+ quicktime.util.EndianOrder.isNativeLittleEndian() ?\r
+ QDConstants.k32BGRAPixelFormat : QDGraphics.kDefaultPixelFormat,\r
+ bounds);\r
+ if (input != null && input.getClass().equals(File.class)) {\r
+ movie = quicktime.std.movies.Movie.fromDataRef(\r
+ new DataRef(new QTFile((File) input)),\r
+ StdQTConstants.newMovieActive\r
+ );\r
+ } else {\r
+ grabber = new SequenceGrabber();\r
+ grabber.setGWorld(graphics, null);\r
+ channel = new SGVideoChannel(grabber);\r
+ channel.setBounds(bounds);\r
+\r
+ // seqGrabPreview == 2, Processingでmagic numberとしてハードコートされていた…\r
+ channel.setUsage(StdQTConstants.seqGrabPreview);\r
+\r
+ if (input != null) {\r
+ try {\r
+ channel.setDevice(input.toString());\r
+ } catch (QTException e) {\r
+ e.printStackTrace();\r
+ throw e;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Webcamの設定ダイアログを表示する。\r
+ * 既定のWebcamでは駄目な場合(複数のWebcamが接続されているPCなど)ではこれを実行するとよい。\r
+ */\r
+ public void prepShowDialog() throws QTException { channel.settingsDialog(); }\r
+\r
+ public void start() throws NyARException\r
+ {\r
+ try {\r
+\r
+ if (grabber == null) prepSetInput(null);\r
+\r
+ if (movie == null) {\r
+ grabber.prepare(true, false); // あってもなくてもよさそう\r
+ grabber.startPreview();\r
+ } else {\r
+ movie.preroll(0, 1.0f);\r
+ while (movie.maxLoadedTimeInMovie() == 0)\r
+ movie.task(100);\r
+ movie.setRate(1);\r
+ movie.getPict(movie.getTime()).draw(graphics, bounds);\r
+ }\r
+ PixMap pixmap = graphics.getPixMap();\r
+ rawEncodedImage = pixmap.getPixelData();\r
+\r
+ image_size.width = rawEncodedImage.getRowBytes() / 4;\r
+ pixels = new byte[image_size.width * image_size.height * 3];\r
+ pixels_int = new int[image_size.width * image_size.height];\r
+ } catch (QTException e) {\r
+ QTSession.close();\r
+ throw new NyARException(e);\r
+ }\r
+\r
+ // キャプチャイメージを定期的に更新するタイマー\r
+ timer = new Timer((int) (1000/fps), this);\r
+ timer.start();\r
+ }\r
+ public void stop()\r
+ {\r
+ finalize();\r
+ }\r
+\r
+ /** タイマー処理。キャプチャイメージの更新結果をリスナに伝える。 */\r
+ public void actionPerformed(ActionEvent event) {\r
+\r
+ // 画像をQTJavaのRawEncodedImageとして取得\r
+ try {\r
+ if (movie == null) {\r
+ grabber.idle();\r
+ } else {\r
+ if (movie.isDone()) movie.goToBeginning();\r
+ movie.getPict(movie.getTime()).draw(graphics, bounds);\r
+ }\r
+ } catch (QTException e) {\r
+ QTSession.close();\r
+ e.printStackTrace();\r
+ }\r
+\r
+ // RawEncodedImageをint列に落とし込む\r
+ rawEncodedImage.copyToArray(0, pixels_int, 0, pixels_int.length);\r
+\r
+ // バイト列を生成する\r
+ int idx_byte = 0;\r
+ for (int idx = 0; idx < image_size.width*image_size.height; idx ++) {\r
+ pixels[idx_byte ++] = (byte) (pixels_int[idx] >> 16);\r
+ pixels[idx_byte ++] = (byte) (pixels_int[idx] >> 8 & 0xff);\r
+ pixels[idx_byte ++] = (byte) (pixels_int[idx] & 0xff);\r
+ }\r
+\r
+ // 各リスナに更新されたバイト列を渡す\r
+ capture_listener.onUpdateBuffer(pixels);\r
+ }\r
+\r
+ protected void finalize()\r
+ {\r
+ try {\r
+ if (movie == null) {\r
+ grabber.stop();\r
+ grabber.release();\r
+ grabber.disposeChannel(channel);\r
+ }\r
+ } catch (Exception e) {\r
+ e.printStackTrace();\r
+ } finally {\r
+ QTSession.close();\r
+ }\r
+ timer.stop();\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * QuickTimeお手軽キャプチャ用リスナ\r
+ * (c)2008 arc@dmz, A虎@nyatla.jp\r
+ * arc@digitalmuseum.jp\r
+ * http://nyatla.jp/\r
+ */\r
+package jp.nyatla.nyartoolkit.qt.utils;\r
+\r
+\r
+public interface QtCaptureListener{\r
+ public void onUpdateBuffer(byte[] i_buffer);\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * RGB形式のbyte配列をラップするNyARRasterです。\r
+ * 保持したデータからBufferedImageを出力する機能も持ちます。\r
+ * (c)2008 arc@dmz, A虎@nyatla.jp\r
+ * arc@digitalmuseum.jp\r
+ * http://nyatla.jp/\r
+ */\r
+package jp.nyatla.nyartoolkit.qt.utils;\r
+\r
+\r
+import java.awt.image.BufferedImage;\r
+import java.awt.image.DataBuffer;\r
+import java.awt.image.WritableRaster;\r
+\r
+import jp.nyatla.nyartoolkit.NyARException;\r
+import jp.nyatla.nyartoolkit.core.raster.NyARRaster;\r
+\r
+\r
+public class QtNyARRaster_RGB implements NyARRaster\r
+{\r
+ protected byte[] ref_buf;\r
+ protected int width=0;\r
+ protected int height=0;\r
+ private WritableRaster raster;\r
+ private BufferedImage image;\r
+\r
+\r
+ /**\r
+ * RGB形式のJMFバッファをラップするオブジェクトをつくります。\r
+ * 生成直後のオブジェクトはデータを持ちません。\r
+ * メンバ関数はsetBufferを実行後に使用可能になります。\r
+ */\r
+ public QtNyARRaster_RGB(int i_width,int i_height)\r
+ {\r
+ ref_buf=null;\r
+ width=i_width;\r
+ height=i_height;\r
+ raster = WritableRaster.createInterleavedRaster(DataBuffer.TYPE_BYTE,\r
+ width, height,\r
+ width*3, 3,\r
+ new int[] { 0, 1, 2 }, null); \r
+ image = new BufferedImage(width, height,\r
+ BufferedImage.TYPE_3BYTE_BGR);\r
+ }\r
+ /**\r
+ * javax.media.Bufferを分析して、その分析結果をNyARRasterに適合する形で保持します。\r
+ * 関数実行後に外部でi_bufferの内容変更した場合には、再度setBuffer関数を呼び出してください。\r
+ * @param i_buffer\r
+ * RGB形式のデータを格納したjavax.media.Bufferオブジェクトを指定してください。\r
+ * @return\r
+ * i_bufferをラップしたオブジェクトを返します。\r
+ * @throws NyARException\r
+ */\r
+ public void setBuffer(byte[] i_buffer)\r
+ {\r
+ ref_buf=i_buffer;\r
+ }\r
+ public int getPixelTotal(int i_x,int i_y)\r
+ {\r
+ int bp=(i_x+i_y*width)*3;\r
+ byte[] ref=this.ref_buf;\r
+ return (ref[bp] & 0xff)+(ref[bp+1] & 0xff)+(ref[bp+2] & 0xff);\r
+ }\r
+ public void getPixelTotalRowLine(int i_row,int[] o_line)\r
+ {\r
+ final byte[] ref=this.ref_buf;\r
+ int bp=(i_row+1)*this.width*3-3;\r
+ for(int i=this.width-1;i>=0;i--){\r
+ o_line[i]=(ref[bp] & 0xff)+(ref[bp+1] & 0xff)+(ref[bp+2] & 0xff);\r
+ bp-=3;\r
+ }\r
+ } \r
+ public int getWidth()\r
+ {\r
+ return width;\r
+ }\r
+ public int getHeight()\r
+ {\r
+ return height;\r
+ }\r
+ public void getPixel(int i_x,int i_y,int[] i_rgb)\r
+ {\r
+ int bp=(i_x+i_y*this.width)*3;\r
+ byte[] ref=this.ref_buf;\r
+ i_rgb[0]=ref[bp+0];//R\r
+ i_rgb[1]=ref[bp+1];//G\r
+ i_rgb[2]=ref[bp+2];//B\r
+ }\r
+ /**\r
+ * データを持っているかを返します。\r
+ * @return\r
+ */\r
+ public boolean hasData()\r
+ {\r
+ return ref_buf!=null;\r
+ }\r
+ public void getPixelSet(int[] i_x,int i_y[],int i_num,int[] o_rgb)\r
+ {\r
+ int width=this.width;\r
+ byte[] ref=this.ref_buf;\r
+ int bp;\r
+ for(int i=i_num-1;i>=0;i--){\r
+ bp=(i_x[i]+i_y[i]*width)*3;\r
+ o_rgb[i*3+0]=ref[bp+0];//R\r
+ o_rgb[i*3+1]=ref[bp+1];//G\r
+ o_rgb[i*3+2]=ref[bp+2];//B\r
+ } \r
+ return;\r
+ }\r
+\r
+ /** 保持しているデータからBufferedImageを作って返します。 */\r
+ public BufferedImage createImage() {\r
+ raster.setDataElements(0, 0, width, height, ref_buf);\r
+ image.setData(raster);\r
+ return image;\r
+ }\r
+}\r