OSDN Git Service

QuickTimeによるカメラ入力をサポート。
authorarc <arc@7cac0a50-4618-4814-88d0-24b83990f816>
Sun, 20 Jul 2008 03:29:52 +0000 (03:29 +0000)
committerarc <arc@7cac0a50-4618-4814-88d0-24b83990f816>
Sun, 20 Jul 2008 03:29:52 +0000 (03:29 +0000)
git-svn-id: http://svn.sourceforge.jp/svnroot/nyartoolkit/NyARToolkit@102 7cac0a50-4618-4814-88d0-24b83990f816

branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/sample/NyarToolkitLinkTest.java [new file with mode: 0644]
branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/sample/QtCaptureTest.java [new file with mode: 0644]
branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/utils/QtCameraCapture.java [new file with mode: 0644]
branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/utils/QtCaptureListener.java [new file with mode: 0644]
branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/utils/QtNyARRaster_RGB.java [new file with mode: 0644]

diff --git a/branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/sample/NyarToolkitLinkTest.java b/branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/sample/NyarToolkitLinkTest.java
new file mode 100644 (file)
index 0000000..33587fa
--- /dev/null
@@ -0,0 +1,108 @@
+/**
+ * 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();
+       }
+        
+    }
+
+}
diff --git a/branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/sample/QtCaptureTest.java b/branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/sample/QtCaptureTest.java
new file mode 100644 (file)
index 0000000..5f1d95c
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * 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();
+       }
+        
+    }
+
+}
diff --git a/branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/utils/QtCameraCapture.java b/branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/utils/QtCameraCapture.java
new file mode 100644 (file)
index 0000000..6857a7a
--- /dev/null
@@ -0,0 +1,204 @@
+/**\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
diff --git a/branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/utils/QtCaptureListener.java b/branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/utils/QtCaptureListener.java
new file mode 100644 (file)
index 0000000..4d0cade
--- /dev/null
@@ -0,0 +1,13 @@
+/**\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
diff --git a/branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/utils/QtNyARRaster_RGB.java b/branches/arc/sample/qt/jp/nyatla/nyartoolkit/qt/utils/QtNyARRaster_RGB.java
new file mode 100644 (file)
index 0000000..e735e29
--- /dev/null
@@ -0,0 +1,117 @@
+/**\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