巷で評判(?)のSDKを使ってみます。

KDDIの「SATCH」と metaioの「Mobile SDK」、 QUALCOMMの「VuForia」。



目次

SATCH


   SATCHをダウンロードしてインストール
   Satch Studioを使ってコンテンツ作成
   アプリ生成用の環境構築
   サンプルアプリ生成
   新規アプリ生成

    New
   AR Viewer Library for Android (satch_Android_jp.zip)が更新されました。
   最新版の更新はこちらから
   (ユーザー登録が必要です)


   SATCH系のプロジェクトのご紹介

     SATCHで1000円札を検出するAR

     SATCHのTOUCH MEを使ってみる

     SATCHのマーカーをタップしてしゃべらせてみる

     SATCHのマーカーをタップしてうたわせてみる

     SATCHでエンブレムを検出してシュート

     SketchUpのモデルをSATCHで使う

     SATCHを使ってArt_ProjectでAR(シングル・トラッキング)

     SATCHを使ってArt_ProjectでAR(マルチ・トラッキング)

     マルチ・トラッキングして地図やWebと連携するAR
     画像トラッキングして地図やWeb・ストリートビューと連携するAR

     SATCHのトラッキング・シナリオをSDカードからロードして使う

     フェルメールの37作品をトラッキングする

     ゴッホのひまわりを検出して、しゃべらせるARを作ってみましょう

     ゴッホのひまわりを検出して、4ヵ国語で解説してみましょう

     アンドロイドでバーコード読み取り

     AR(拡張現実):QRコードとマーカーで絵画を表示してみる

     QRコードとマーカーで絵画を表示してみる(拡張版)

     SATCHのcompassを使って距離と高さを測ってみる

     SATCH AR SDKの顔検出を試してみる

     SATCHでアニメ顔検出をやってみる

     OpenCVのカスケードをSATCHで使ってみる

     SATCHを使ってお顔のパーツを複数(並列)トラッキング

     SATCHのパーティクルシステムを試してみる

     SATCHのパーティクルシステムを試してみる2

     SATCHのパーティクルシステムとトラッキングの複合技


metaio Mobile SDK





VuForia





TOP

KDDIのSATCHを使ってみる

使用するには、ユーザー登録が必要です。

ログインページから新規登録ができます。

1:SATCHをダウンロードしてインストール

SATCH Developer site

Android用に2つダウンロードします。

AR Viewer Library for Android

Authoring Tool (SATCH Studio)

ダウンロード後、satch_Authoring_Tool_jp.zipを解凍して、SatchStudioSetup.exeを起動してインストールします。

以下のような画面になったら、ユーザー登録に設定した、IDとパスワードを入力して、Activateします。





インストールできたら、メニュのTotal immersionの中の「SatchStudio.exe」で起動。





2:Satch Studioを使ってコンテンツ作成

基本的な流れは、
SATCHのDeveloper siteの開発ガイドを見れば、問題なくできます。

ただ、初めての場合、とまどう部分もあるので、その辺をフォローしてみます。

1.3.1で出てくる「Outliner(アウトライナー)」





1.3.2で出てくる「Object editor(オブジェクト・エディター)」





1.4の6で出てくる「Calibrate(キャリブレート)」

説明の流れでは、この場合カメラはPauseの状態のままですが、この場合うまくいきません。

リセットボタンを押しておく必要があります。





1.5.1で出てくる「Solution Explorer(ソリューション・エクスプローラー)」





1.7.2で出てくる「3Dビュー(ビューポート・ウィンドウ)へとドラッグ&ドロップ」





Satch Studioでは、コンテンツはこういう感じになります。

ターゲット(flyer)を見る角度が変わると、DemoRobotのスケールや角度も変わります、面白い。





ちなみに、コンテンツ作成の最終成果物は「シナリオ」と呼ばれる一連のファイル群です。
このシナリオを使って、アプリを作成します。

追記(2012/05/17)
SATCHで使える3Dモデルの作成は、3dsMaxかMayaだけだと思ってましたので自作はGive Upって感じでした。
(どっちもバカ高い、50万くらいする...)
でも、どうもマニュアルを読むと、D'Fusionのオブジェクト・レンダリングエンジンはOgreみたい。
で、Ogreモデルを作って、それを取り込めばいい....らしいのです。3dsMaxやMayaではなく、Google SketchUpで3Dモデルを 作成し、それをOgreモデルでexportできるプラグインがあるようだ.....。
要調査!

結果(2012/05/30)
どうやらいけるっぽいです。
ここを参照
SketchUpのモデルをSATCHで使う




3:アプリ生成用の環境構築

環境構築の仕方は
ここ「PhoneGapでネイティブアプリ」
に書いておいたままでいいようです。

さらに、Targetのパッケージはすべてインストールするようにしたほうが無難です(入らないものもありますが)。で、Accept all。


4・1:サンプルアプリ生成

まず、サンプルを使ってみます。

SATCH Developer siteのサンプルにある「
Views」です。

ここでは、Google Mapsも使用されるので、まずEclipseのSDK Managerで Targetに「Google APi」のパッケージがインストールされているか チェックしてください。

次に、GoogleのAPIキーを取得しておく必要があります。

取得方法はこのページを参照。

例えば、Windows XPの場合。

debug.keystoreを使いますが、場所は「C:¥Documents and Settings¥<ユーザー名>¥.android¥debug.keystore」です。

DOS窓(コンソール)で、Javaのkeytool.exeを使います。パスが通っていない場合は、JREのインストール先のbinフォルダに移動してください。

コンソールで以下のコマンドを実行。

>keytool -list -keystore "C:¥Documents and Settings¥<ユーザー名>¥.android¥debug.keystore"

パスワードを聞いてきますが、無視していいです。

例えば、「94:1E:43:49:87:73:BB:E6:A6:88:D7:20:F1:8E:B5:98」のようなものが表示されますが、これがMD5 Fingerprint です。

で、次にこのページに移動して、 下のほうにある空欄にFingerprintを入力して、「Generate API Key」ボタンをクリックすればいいです。

後は、サンプルの解説にあるとおりでいけます。

結果は、こんな感じ。





この状態でスマホを振ると色が変わります。





このソースを参考にして、自分のアプリを作ってみましょう。

4・2:新規アプリ生成

SATCHのDeveloper siteで公開されている、一番シンプルなアプリを作ってみます。

サンプルのオリジナルコードのままでは動かないと思います(多分)、ちょっと変更が必要。

(1)Eclipseを起動して、プロジェクトを新規に作成

File -> New -> Other

Android -> Android Project

プロジェクト名は「Tutorial」。
Project Name -> Tutorial
Build Target -> Android 2.3.3
Package Name -> com.kddi.satch.tutorial

プロジェクトの"assets"フォルダにScenarioフォルダーを作成、その中に作成済みのScenario_aフォルダーをコピー。

前にダウンロードした、AR Viewer Library for Android (satch_Android_jp.zip)を解凍。

プロジェクトに"libs"フォルダを作成し、satch.jarをコピー。

"libs"フォルダ内に"armeabi"フォルダを作成し、libsatchAnrdoid.soとlibtiAndroidAR2.soをコピー。

プロジェクトをRefresh。

satch.jarを右クリックしてビルドパスを通します。
Build Path -> Add to Build Path

(2)AndroidManifest.xmlを編集

<Activityに以下を追加
	android:screenOrientation="landscape"
android:configChanges="orientation|keyboard|keyboardHidden"


</application>の下に以下を追加 <!-- 画像解像度を設定します --> <supports-screens android:anyDensity="false" android:normalScreens="true" android:largeScreens="true" android:smallScreens="true" android:resizeable="true"> </supports-screens> <!-- カメラ機能、ライセンス認証で利用するパーミッションを許可します --> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- オートフォーカスを設定します --> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <uses-sdk android:minSdkVersion="7" />


(3)プロジェクトにパッケージを追加

File -> New -> Package
Name -> com.kddi.satch.tutorialactivity このパッケージに、抽象クラスを作成。

com.kddi.satch.tutorialactivityを選んで、

File -> New -> Class
Name ->TutorialActivity_simple
Modifiers -> Public/abstract

コードはサンプルのまま、以下の通り。

TutorialActivity_simple.java

package com.kddi.satch.tutorialactivity;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.View;
import android.widget.FrameLayout;

import com.kddi.satch.LoadScenarioStatus;
import com.kddi.satch.ARViewer;

public abstract class TutorialActivity_simple extends Activity {
    protected abstract String getSampleScenarioName();
    protected abstract String getSampleLogTag();
    protected boolean _isInitializedCorrectly;
    protected ARViewer _kddiComponent;
    protected FrameLayout _frameLayout;
    
    public void resetMembers(){
        _isInitializedCorrectly = false;
        _frameLayout = null;
        _kddiComponent = null;
    }
    private static final int DIALOG_EXIT = 0;
    
    public void initComponent(){
        _isInitializedCorrectly = false;
        _kddiComponent = new ARViewer(this);
        // This FrameLayout must be empty (but initialized) when you pass it to the kddiComponent.initialize() method.
        _frameLayout = new FrameLayout(this);
        _kddiComponent.initialize(_frameLayout);
        _isInitializedCorrectly = true;
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Add null to AR Viewer Library compornent's reference.
        resetMembers();
    }
    
    @Override
    public void onRestart() {
        super.onRestart();
    }
    
    @Override
    public void onStart() {
        super.onStart();
        // Create AR Viewer Library compornent.
        initComponent();
        postInitComponent();
        initContentView();
        if (_isInitializedCorrectly) {
            // Do authorize and madia is loaded.
            // You must call loadScenario() method.
            loadScenario();
        }
    }
    
    @Override
    public void onResume(){
        super.onResume();
        if (_isInitializedCorrectly) {
            // GL context is recreated and media is reloaded.
            _kddiComponent.onResume();
            reservePlayScenario();
        }
    }
    
    @Override
    public void onPause() {
        // When the activity is paused the GL context is destroyed, so all media is unloaded.
        if (_isInitializedCorrectly) {
            cancelReservePlayScenario();
        if (_kddiComponent.checkLoadScenarioStatus() == LoadScenarioStatus.COMPLETE) {
            _kddiComponent.pauseScenario();
        }
            _kddiComponent.onPause();
        }
        super.onPause();
    }
    
    @Override
    public void onStop() {
        releaseContentView();
        // Destroy AR Viewer Library Objects.
        if (_isInitializedCorrectly){
            _kddiComponent.terminate();
            _kddiComponent = null;
            _frameLayout = null;
        }
        super.onStop();
    }
    
    @Override
    public void onDestroy() {
        // Destroy AR Viewer Library Objects.
        if (_isInitializedCorrectly){
            _frameLayout = null;
            _kddiComponent = null;
        }
        super.onDestroy();
        resetMembers(); // forced clean
    }
    
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent msg){
        switch(keyCode){
            case android.view.KeyEvent.KEYCODE_BACK :
            showDialog( DIALOG_EXIT );
            return true;
        }
        return false;
    }
    
    public void postInitComponent(){
        // override this if you need to do some special handling on the component after standard initialization
        if (_isInitializedCorrectly) {
            _kddiComponent.activateAutoFocusOnDownEvent(true);
        }
    }
    
    public void initContentView(){
        // override this if you need to do some special handling on the component after standard initialization
        if (_isInitializedCorrectly) {
            // you'll probably use some other UI object as the content view that itself will embed the component's frame layout -- here you can change all this
            // by default, the frame layout containing DFusion will be the activity content view
            setContentView(_frameLayout);
        }
    }
    
    public void releaseContentView(){
        // override this if you need to do some special handling on the component after standard initialization
        if (_isInitializedCorrectly) {
            // do here the release of the your UI instances (if customized)
        }
    }
    
    public void loadScenario(){
        ApplicationInfo appInfo = null;
        PackageManager packMgmr = getApplicationContext().getPackageManager();
        try {
            appInfo = packMgmr.getApplicationInfo(getPackageName(), 0);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("Unable to locate assets, aborting...");
        }
        String dpdfile = appInfo.sourceDir + getSampleScenarioName();
        _kddiComponent.loadScenario(dpdfile);
    }
    
    // Set polling rate for loading the media.
    private final int REPEAT_INTERVAL = 100;
    private Handler handler = new Handler();
    private Runnable runnable = null;
    
    
    //
    private void reservePlayScenario(){
        if (runnable == null){
            runnable = new Runnable(){
                @Override
                public void run(){
                    LoadScenarioStatus status = _kddiComponent.checkLoadScenarioStatus();
                    if (status == LoadScenarioStatus.CANCEL){
                        // cancel(appli suspend)
                    }else if (status == LoadScenarioStatus.COMPLETE){
                        // Ready to play scenario
                        _frameLayout.setVisibility(View.VISIBLE);
                        _kddiComponent.playScenario();
                    }else if (
                        status == LoadScenarioStatus.ERROR_NETWORK_UNUSABLE ||
                        // faild to load a media becase of no network connection.
                        status == LoadScenarioStatus.ERROR_NETWORK ||
                        // faild to load a media becase of network error.
                        status == LoadScenarioStatus.ERROR_SOFTWAREKEY ||
                        // faild to load a media becase software key has not be found on server.
                        status == LoadScenarioStatus.ERROR_CONTENT_STOPPED ||
                        // faild to load a media becase content has stopped.
                        status == LoadScenarioStatus.ERROR_SERVER ||
                        // faild to load a media becase of server error.
                        status == LoadScenarioStatus.ERROR_ETC
                        // faild to load a media becase of another error.
                        ){
                    // error
                    }else{
                        handler.postDelayed(this, REPEAT_INTERVAL);
                    }
                }
            };
            handler.postDelayed(runnable, REPEAT_INTERVAL);
        }
    }
    
    //
    
    private void cancelReservePlayScenario(){
        if (handler != null && runnable != null){
            handler.removeCallbacks(runnable);
            runnable = null;
        }
    }
    
    protected Dialog onCreateDialog(int id) {
        Dialog dialog;
        switch(id) {
            case DIALOG_EXIT:
            {
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setMessage(
                    "Really want to quit the sample?"
                )
                .setCancelable(true)
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        finish();
                    }})
                    .setNegativeButton("No", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                        }});
                    dialog = builder.create();
                    break;
            }
            default:
            dialog = null;
        }
        return dialog;
    }
    
    
    
}


既存のTutorialActivity.javaを上の抽象クラスを継承するコードに書き換えます。

下の赤字の部分が変更点です。

sample.dpdは作成時、小文字のファイル名になっている...と思います。

TutorialActivity.java

package com.kddi.satch.tutorial;


import com.kddi.satch.tutorialactivity.TutorialActivity_simple;

public class TutorialActivity extends TutorialActivity_simple{
    private static final String THIS_CLASS_SHORT_NAME = TutorialActivity.class.getName().replace("com.kddi.satch.tutorial.", "");
    private static final String THIS_LOGTAG  = THIS_CLASS_SHORT_NAME;
    // Set AR scenario file path.
    private static final String SCENARIO_NAME = "/assets/Scenario/Scenario_a/sample.dpd";
    protected String getSampleScenarioName() { return SCENARIO_NAME; }
    protected String getSampleLogTag() { return THIS_LOGTAG;   }
    
    @Override
    public void postInitComponent(){
        super.postInitComponent();
    }
    
}



(4)アプリを登録する

コーディングは以上ですが、このままでは動きません。

実機で動かそうとすると以下のようなライセンス・エラーになります。





SATCH Developer siteのマイページに移動。


New(2012/09/19)
レギュレーションが変わりましたので修正しておきます。

新規の場合、アプリ追加ボタンをクリックします。





最低限、必要な項目は以下の通り。

●対象OS
    Android/iOS

●アプリ名称
    適当に

●公開範囲
    とりあえずは非公開

●アプリアID
   


マイページに戻って、「コンテンツ一覧」をクリックします。





「コンテンツ追加」ボタンをクリックします。





アプリ名称を確認して、コンテンツ名称を記入して、署名ファイルを選びます。





sample.dpd.dfkファイルです。

登録ボタンをクリックすると、署名ファイルのダウンロード画面が出てきます。







ファイルをダウンロードして、assets/Scenario/Scenario_a/sample.dpd.dfkに上書きしてください。

以上でアプリ生成完了。

こんな、感じです。





サンプルのトラッキング画像は印刷すると、A4に収まるサイズですが、カメラは60cm位の距離でも検出できるようです。 それ以上離れると難しいみたい。一度検出すれば、かなり離れていてもトラックできますが、一度ロストするとダメみたい。 再度接近して検出し直しましょう。


動作確認:docomo Xperia acro


別途、
1000円札検出もやってみました。







TOP

metaioのMobile SDKを使ってみる

有償版と無償版があります、無償版ではアプリにスプラッシュとウォーターマークが表示されるようです。

このウォーターマークが結構大きいようで、製品アプリを作ろうとする場合は邪魔になります。

まあ、ここでは製品アプリをつくる気はないので無償版を使います(有償版だと結構なお値段しますです..はいTT)。

Mobile SDKのページ


SDKをダウンロードしましょう...と思ったのですが、最初はどこにあるか戸惑います。

ダウンロード用のリンクが見当たらない。

あれこれ探してようやく分かりました。まず「Free Full Version」のボタンをクリック。

Dear Customers.....というダイアログが出ます。

で、このダイアログをスクロールダウンして最後まで行くと、メールアドレスを入れるフィールドと「Agree」のボタンがあります。

メールアドレスを入れて、Agreeをクリックすると、ダウンロードリンクの書かれたメールが送られます。

これをクリックするとダウンロードが開始されます。

57MBくらいの結構なサイズのファイルです。

Under construction

Next
junaioを使ったアルファチャンネル入り動画の再生をやってみる....予定。

TOP

QUALCOMMのVuForiaを使ってみる

結論から言うと、デプロイ時にエラーが発生し、まだ原因が特定できていません。

まあ、そこに至るまでの顛末をレポートします。

QUALCOMMのVuForiaを使用するには、

Eclipse + Android SDK + ADT + Cygwin(Windowsの場合) + Android NDKの環境が必要。

環境構築の仕方は
ここ「PhoneGapでネイティブアプリ」

ここ「アンドロイドでOpenCV(特徴点検出)」
に書いておきました。

VuForiaもSATCHと同じで、ユーザー登録が必要です。

SDKのページから新規登録ができます。

右上の「Register」ボタンをクリックしてパスワード取得。

IDはメールアドレスになります。

「vuforia-sdk-android-1-5-9.exe」と「vuforia-unity-android-1-5-10.exe」をダウンロード。

vuforia-sdk-android-1-5-9.exeをダブルクリックしてインストール。

デフォルトでは、「C:¥Development¥Android」の中にインストールされます。

サンプルを使ってみます。

「C:¥Development¥Android\vuforia-sdk-android-1-5-9¥samples」にあります。

まず、適当なプロジェクトをNDKでビルドします。

CygwinのTerminalを起動。

例:
$cd /cygdrive/c/Development/Android/vuforia-sdk-android-1-5-9/samples/ImageTargets
$ndk-build

Eclipseを起動して、「ImageTargets」をインポート。

ImageTargetsを右クリック-->Properties-->Android-->Android 2.3.3をtargetにする。

mageTargetsを右クリック-->Android Tools-->Fix Project Properties

genフォルダーが作成されます。

以下のようなエラーがでる...はず。

Unbound classpath variable: 'QCAR_SDK_ROOT/build/java/QCAR/QCAR.jar' in project 'ImageTargets' ImageTargets

再度、ImageTargetsを右クリック-->Properties-->Java Build Path-->Libraries

QCAR_SDK_ROOTに問題があるようなので....。

以下のようにEditします





Variableをクリック。

Variable Selectionで「QCAR_SDK_ROOT」をRemoveして、次にNewをクリック。

New Variable Entryで、

Nameに「QCAR_SDK_ROOT」、
Pathには「C:¥Development¥Android¥vuforia-sdk-android-1-5-9¥build¥java¥QCAR¥QCAR.java」

Edit Variable Entryで、「QCAR_SDK_ROOT」。

これで、見た目のエラーは出なくなる...はず。

でも実機に送ると...





なんでやねん(TT;

TOP