一覧に戻る

Android ネイティブAPIのクラウド認識

2017.09.22AndroidネイティブAPI

Android ネイティブAPIのクラウド認識

このトピックではAR.ImageTrackerクラスとAR.CloudRecognitionServiceクラスを使用してクラウドサーバー上の画像を認識し、拡張する方法を示します。
まずは、より良く理解できるように、このドキュメントで使用する画像認識型ARに関する用語の定義を以下に示します。
  • ターゲット: 認識対象の画像と認識に必要とされる抽出データ。
  • ターゲットコレクション: ターゲットの集合体。認識対象の画像すべてを含むディレクトリと見なすことができます。Wikitude SDKでは2種類の異なるターゲットコレクションを扱うことができます。
    • オンデバイスターゲットコレクション: 認識対象の画像と認識に必要とされる抽出データを含む静的なwtcファイル。格納できるターゲットの数は最大1,000です。
    • クラウドターゲットコレクション: Wikitudeサーバーに保存されたターゲットコレクション。下記の「クラウドアーカイブ」を参照してください。格納できるターゲットの数は最大50,000です。
  • クラウドアーカイブ: サーバーに保存されている、クラウド認識用に最適化されたアーカイブ。ターゲットコレクションから生成され、AR.CloudRecognitionServiceと組み合わせて使用されます。
  • CloudRecognitionService: AR.CloudRecognitionServiceは、カメラビューからの入力をデバイスで直接分析および計算するのではなく、カメラで撮影した画像をWikitude Cloud Recognitionサーバーに送信します。サーバーは送られてきた画像を指定されたクラウドアーカイブ内のターゲットとマッチングします。AR.CloudRecognitionServiceを使用すると大規模な画像データベースを検索できる利点があり、さらにはほとんどのケースで全体的なパフォーマンスも向上します。特にターゲット数の多いターゲットコレクションや性能がそれほど高くないデバイスを使用するときに効果的です。

以下のクラウド認識のサンプルではどちらも、外部レンダリングを使用します。詳細はAndroid ネイティブAPIのレンダリングを参照してください。

CloudTrackerには、随時認識モードと連続認識モードの2種類の実行モードがあります。随時認識モードでは認識サイクルが1回だけ実行され、連続認識モードでは可変の間隔で連続的に認識が実行されます。サンプルを基にそれぞれのモードについて説明します。

地域サーバーのエンドポイント

最初に、SDKの接続対象となるWikitudeの地域分散型サーバーを選択する必要があります。
TrackerManagerのsetCloudRecognitionServerRegionを呼び出すことにより、クラウド認識サーバーの地域を選択することができます。その後、作成したすべてのCloudRecognitionServiceは選択した地域を使用します。次のコード例では、クラウド認識サーバーの場所をデフォルト設定のEuropeからAmericasに変更しています。

mWikitudeSDK.getTrackerManager().setCloudRecognitionServerRegion(TrackerManager.ServerRegion.AMERICAS);

随時認識モード

サンプルのOnClickCloudTrackingActivityクラスを確認します。まずはonCreateメソッドです。onCreateでは、WikitudeSDKのインスタンスを作成した後、TrackerManagerを取得してcreateCloudRecognitionServiceを呼び出し、認証トークンとターゲットコレクションIDを渡しています。3番目のパラメータは、サーバーとの通信がいつ確立したかを知らせるコールバックです。障害が発生した場合は、onErrorコールバック関数が呼び出されます。デバッグ目的のためにエラーを記録するだけですが、実際のプロジェクトでは、すでにアプリはテストされているので、ターゲットコレクションIDの間違いのような問題でなければ、ログを削除してCloudRecognitionServiceは再度ロードされます。成功した場合は、onInitializedコールバック関数が呼び出され、TrackerManagerでcreateImageTrackerを呼び出してImageTrackerを作成することができます。 最初のパラメータは、作成したばかりのクラウド認識サービスです。2番目のパラメータを使用してトラッキングイベントを受け取るアクティビティを登録できます。これを動作させるには、アクティビティにImageTrackerEventListenerを実装します。

public class OnClickCloudTrackingActivity extends Activity implements ImageTrackerEventListener, ExternalRendering {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        mWikitudeSDK.onCreate(getApplicationContext(), this, startupConfiguration);
        mCloudRecognitionService = mWikitudeSDK.getTrackerManager().createCloudRecognitionService("b277eeadc6183ab57a83b07682b3ceba", "54e4b9fe6134bb74351b2aa3", new CloudRecognitionServiceInitializationCallback() {
            @Override
            public void onInitialized() {
                mWikitudeSDK.getTrackerManager().createImageTracker(mCloudRecognitionService, OnClickCloudTrackingActivity.this, null);
            }

            @Override
            public void onError(int errorCode, String errorMessage) {
                Log.e(TAG, "Cloud Recognition Service failed to initialize. Reason: " + errorMessage);
            }
        });
    }

認識を開始するためにボタンを定義し、CloudRecognitionServiceのrecognizeメソッドを呼び出す匿名のOnClickListenerを設定します。

@Override
public void onRenderExtensionCreated(final RenderExtension renderExtension) {
    ...
    Button recognizeButton = (Button) findViewById(R.id.on_click_cloud_tracking_recognize_button);
    recognizeButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(final View view_) {
            mCloudRecognitionService.recognize(new CloudRecognitionServiceListener() {
                ...
            }
        });
    })
}

この関数のパラメータは、CloudRecognitionServiceによってトリガされたイベントに反応するためのコールバックメソッドを提供します。onResponseメソッドは、クラウド認識サービスへの接続が成功し、応答を受けたときに呼び出されます。このレスポンスはCloudRecognitionServiceResponseパラメータを通してアクセスでき、isRecognizedメソッドを呼び出すことで、ターゲットがクラウド認識サービスによって実際に認識されたことを判断できます。ターゲットに関する追加情報は、getTargetInformationsおよびgetMetadata関数を使用して取得できます。onErrorメソッドは、クラウド認識サーバーに接続する際に接続エラーが発生したときに呼び出されます。

mCloudRecognitionService.recognize(new CloudRecognitionServiceListener() {
    @Override
    public void onResponse(final CloudRecognitionServiceResponse response) {
        if (response.isRecognized()) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    EditText targetInformationTextField = (EditText) findViewById(R.id.on_click_cloud_tracking_info_field);
                    targetInformationTextField.setText(response.getTargetInformations().get("name"), TextView.BufferType.NORMAL);
                    targetInformationTextField.setVisibility(View.VISIBLE);
                }
            });
        } else {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    EditText targetInformationTextField = (EditText) findViewById(R.id.on_click_cloud_tracking_info_field);
                    targetInformationTextField.setText("Recognition failed - Please try again", TextView.BufferType.NORMAL);
                    targetInformationTextField.setVisibility(View.VISIBLE);
                }
            });
        }
    }

    @Override
    public void onError(final int errorCode, final String errorMessage) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                EditText targetInformationTextField = (EditText) findViewById(R.id.on_click_cloud_tracking_info_field);
                targetInformationTextField.setText("Recognition failed - Error code: " + errorCode + " Message: " + errorMessage);
                targetInformationTextField.setVisibility(View.VISIBLE);
            }
        });
    }
});

ImageTrackerListenerは、ImageTrackerがステータスを伝えることを可能にするコールバックを定義します。一方で読み込み処理に関する通知を受け取り、もう一方ではトラッキング処理に関する更新を受け取ります。読み込み処理に関するメソッドでは、ImageTrackerが正常に読み込まれ、リクエスト後にCloudRecognitionServiceから受け取ったターゲットが初期化された場合、onTargetsLoadedメソッドが呼び出されます。onErrorLoadingTargetsメソッドは、ImageTracker内のCloudRecognitionServiceレスポンスからターゲットを読み込む際に問題が発生したときに呼び出されます。 このとき、問題に関する詳細情報を含むerrorMessageを受け取ります。

@Override
public void onTargetsLoaded(ImageTracker tracker) {
    Log.v(TAG, "Image tracker loaded");
}

@Override
public void onErrorLoadingTargets(ImageTracker tracker, int errorCode, final String errorMessage) {
    Log.v(TAG, "Unable to load image tracker. Reason: " + errorMessage);
}

次に、トラッキング処理に関するコールバックを確認します。onImageRecognizedメソッドとonRecognitionSuccessfulは、ImageTrackerがターゲットの1つのトラッキングを開始した場合に呼び出されます。onImageRecognizedの呼び出し後、onImageTrackedを呼び出します。これらの呼び出しでは、ImageTrackerは現在のターゲットに関する情報を含むImageTargetクラスのインスタンスを渡します。このオブジェクトには、ターゲットの名前やターゲットまでの距離などのターゲットに関する一般的な情報の他に現在のフレーム内のターゲットの位置を定義するマトリックスも含まれます。画像が認識されるとStrokedRectangleインスタンスを登録し、ImageTargetオブジェクトを使用してそのマトリックスを更新し、画像をロストしたときにその登録を解除します。スケール値を設定すると、StrokedRectangleをターゲットのアスペクト比に合わせることができます。

@Override
public void onImageRecognized(ImageTracker tracker, final ImageTarget target) {
    Log.v(TAG, "Recognized target " + target.getName());

    StrokedRectangle strokedRectangle = new StrokedRectangle(StrokedRectangle.Type.STANDARD);
    mGLRenderer.setRenderablesForKey(target.getName() + target.getUniqueId(), strokedRectangle, null);
}

@Override
public void onImageTracked(ImageTracker tracker, final ImageTarget target) {
    StrokedRectangle strokedRectangle = (StrokedRectangle)mGLRenderer.getRenderableForKey(target.getName() + target.getUniqueId());

    if (strokedRectangle != null) {
        strokedRectangle.projectionMatrix = target.getProjectionMatrix();
        strokedRectangle.viewMatrix = target.getViewMatrix();

        strokedRectangle.setXScale(target.getTargetScale().getX());
        strokedRectangle.setYScale(target.getTargetScale().getY());
    }
}

@Override
public void onImageLost(final ImageTracker tracker, final ImageTarget target) {
    Log.v(TAG, "Lost target " + target.getName());
    mGLRenderer.removeRenderablesForKey(target.getName() + target.getUniqueId());
}

連続認識モード

随時認識モードは特定のケースに便利ですが、おそらく連続認識モードの方がよく使用されると思われます。連続認識モードでは、CloudRecognitionServiceの認識関数を呼び出す間隔を設定します。
随時認識モードと同様にボタンを定義して、CloudRecognitionServiceのstartContinuousRecognitionメソッドを呼び出す匿名のOnClickListenerをミリ秒単位で渡します。モバイルインターネットは接続環境が悪い可能性があるため、1500~2000msの間隔を使用することを推奨します。2番目のパラメータは、要求した間隔が小さすぎるかどうかを判断するために使用できるリスナーです。インターバルタイムが経過して前のリクエストが終了しなかった場合、将来使用されるべき推奨インターバルでonInterruptionメソッドが呼び出されます。3番目のパラメータは、CloudRecognitionServiceListener型のリスナーであり、随時認識のセクションで説明したのと同じ方法で動作します。

private void startContinuousRecognition() {
    ...
    mCloudRecognitionService.startContinuousRecognition(mRecognitionInterval, new ContinuousCloudRecognitionServiceInterruptionListener() {
        @Override
        public void onInterruption(int preferredInterval) {
            ...
        }
    }, new CloudRecognitionServiceListener() {
        @Override
        public void onResponse(final CloudRecognitionServiceResponse response) {
            ...
        }

        @Override
        public void onError(final int errorCode, final String errorMessage) {
            ...
        }
    });

}