クラウド認識

このサンプルは、クラウド上の画像を認識して、AR.ImageTrackerクラスを使用しイメージをオーバーレイする方法を示します。

より良く理解できるように、このドキュメントで使用する画像認識型ARに関する用語の定義を以下に示します。

  • ターゲット: 認識対象の画像と認識に必要とされる抽出データ。

  • ターゲットコレクション: ターゲットの集合体。認識対象の画像すべてを含むディレクトリと見なすことができます。Wikitude SDKでは2種類の異なるターゲットコレクションを扱うことができます。

    • オンデバイスターゲットコレクション: 認識対象の画像と認識に必要とされる抽出データを含む静的なwtcファイル。格納できるターゲットの数は最大1,000です。
    • クラウドターゲットコレクション: Wikitudeサーバーに保存されたターゲットコレクション。下記の「クラウドアーカイブ」を参照してください。格納できるターゲットの数は最大50,000です。
  • クラウドアーカイブ: サーバーに保存されている、クラウド認識用に最適化されたアーカイブ。ターゲットコレクションから生成され、AR.ImageTrackerと組み合わせて使用されます。

  • ImageTracker: AR.ImageTrackerと、AR.TargetCollectionResourceの組み合わせのようにカメラビューからの入力をデバイスで直接分析および計算するのではなく、AR.ImageTrackerAR.CloudRecognitionServiceを組み合わせることで、カメラで撮影した画像をWikitude Cloud Recognitionサーバーに送信します。サーバーは送られてきた画像を指定されたクラウドアーカイブ内のターゲットと一致させるための作業を行います。 AR.CloudRecognitionServiceには、AR.TargetCollectionResourceに比べて大規模な画像データベースを検索できる利点があり、さらにはほとんどのケースで全体的なパフォーマンスも向上します。特にターゲット数の多いターゲットコレクションや性能がそれほど高くないデバイスを使用するときに効果的です。

このサンプルは以下の3つのパートで構成されています。

  1. 単一画像の認識
  2. 連続認識モードと随時認識モードの比較
  3. 応答に含まれるメタデータの使用方法

このサンプルは、ワインラベルを認識し拡張する事例に基づきます。世界中から集めたワインラベルのターゲットを含むターゲットコレクションがWikitudeサーバーにすでにセットアップされています。

単一画像の認識(1/3)※対応するサンプルタイトル名「Basic Recognition On: Click」

このセクションで説明するサンプルは、以下にあるワインラベルを認識し、拡張します。これら3つのサンプルはすべて、概ね同様の実装となっていますが、サンプル毎に部分的に機能がカスタマイズされています。

このセクションでは公開されているクラウドアーカイブを使用することに注意してください。Wikitude SDKで使用できるクラウドアーカイブを独自に作成する方法については、Manager APIのドキュメントを参照してください。

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

最初に、SDKの接続対象となるWikitudeの地域分散型サーバーを選択する必要があります。

以下のいずれかの定数でAR.context.setCloudRecognitionServerRegion関数を呼び出すことによってCloud Recognitionサーバーの地域を選択することができます。

AR.CONST.CLOUD_RECOGNITION_SERVER_REGION.AMERICAS
AR.CONST.CLOUD_RECOGNITION_SERVER_REGION.CHINA
AR.CONST.CLOUD_RECOGNITION_SERVER_REGION.EUROPE

デフォルト値は、Europeです。正しくない値が設定されている場合、SDKはEuropeを選択します。

それでは、最初のサンプルのJavaScriptコードの最初の部分 - init関数から見ていきます。

    init: function initFn() {
        this.createTracker();
        this.createOverlays();
    },

ワインが認識されたら、その評価、ワインラベル、および認識されたワインの名前(後のパート)をエンドユーザーに示すバナーを表示します。処理をシンプルにするため、すべてのターゲットで同じバナー画像を再利用します。そのため、バナー画像を一度ロードするだけで何度も再利用できます。これはcreateOverlays関数(上記のinit関数で2番目に呼び出す関数)で行います。

createOverlays: function createOverlaysFn() {
    this.bannerImg = new AR.ImageResource("assets/banner.jpg");
    this.bannerImgOverlay = new AR.ImageDrawable(this.bannerImg, 0.4, {
        translate: {
            y: -0.6
        }
    });
},

まず画像リソースを作成し、それをAR.ImageDrawableに渡します。AR.ImageDrawableは、画像認識型AR(AR.ImageTrackable)またはロケーションベース型AR(AR.GeoObject)で使用できる2D拡張オブジェクトです。画像とそのサイズを指定してAR.ImageDrawableを初期化します。さらに、オプションパラメーターを使用して、ターゲットに対する相対的な位置を指定します。

これらの下準備が済んだら、init関数で最初に呼び出すcreateTracker関数に進みます。

createTracker: function createTrackerFn() {
    World.cloudRecognitionService = new AR.CloudRecognitionService("b277eeadc6183ab57a83b07682b3ceba", "54e4b9fe6134bb74351b2aa3", {
        onInitialized: this.trackerLoaded,
        onError: this.trackerError
    });
    World.tracker = new AR.ImageTracker(this.cloudRecognitionService, {
        onError: this.trackerError
    });
},

上記のコードを見るとわかるように、AR.CloudRecognitionServiceに3つのパラメーターを渡しています。最初のパラメーターはClient API認証トークンを表しており、上のサンプルでは公開されているWikitude認証トークンを使用しています。認証トークンの詳細については、このセクションを参照してください。2番目のパラメーターはターゲットコレクションIDを表します。この一意のIDは、AR.CloudRecognitionServiceが、認証トークンに接続されているすべてのクラウドアーカイブの中からどのクラウドアーカイブを使用するかを識別します。オプションパラメーターは、最後の引数でオブジェクトとして渡します。このケースでは、onLoadedトリガーとonErrorトリガーのコールバック関数を設定しています。

AR.CloudRecognitionServiceのロードが完了すると、onInitialized()関数が呼び出されます。AR.ImageTrackerの初期化中に問題が発生した場合は、trackerError()関数が呼び出されます。特に大規模なクラウドアーカイブを扱うときは、初期化に数秒かかる場合があります。

onInitialized()関数の呼び出しが完了したら、[Scan]ボタンをユーザーに表示します。このボタンをクリックすると画像認識処理が始まり、現在のカメラビューがCloud Recognitionサーバーに送信されます。このボタンのonClickトリガー関数は以下のとおりです。

scan: function scanFn() {
    World.cloudConnection.recognize(this.onRecognition, this.onRecognitionError);
},

ユーザーが[Scan]ボタンをクリックすると、上で作成したAR.CloudRecognitionServiceのrecognize関数が呼び出されます。このrecognize関数には2つのコールバック関数を渡します。最初のコールバック関数は、毎回認識サイクルが終わるたびにSDKによって呼び出されます。2番目のコールバック関数は、指定されたクラウドアーカイブで問題が発生した場合に呼び出されます。

最初のコールバック関数、onRecognitionを以下に示します。

onRecognition: function onRecognitionFn(recognized, response) {
    if (recognized) {
        if (World.wineLabel !== undefined) {
            World.wineLabel.destroy();
        }
        if (World.wineLabelOverlay !== undefined) {
            World.wineLabelOverlay.destroy();
        }
        World.wineLabel = new AR.ImageResource("assets/" + response.targetInfo.name + ".jpg");
        World.wineLabelOverlay = new AR.ImageDrawable(World.wineLabel, 0.3, {
            translate: {
                x: -0.5,
                y: -0.6
            },
            zOrder: 1                
        });
        if (World.wineLabelAugmentation !== undefined) {
            World.wineLabelAugmentation.destroy();
        }
        World.wineLabelAugmentation = new AR.ImageTrackable(World.tracker, response.targetInfo.name , {
            drawables: {
                cam: [World.bannerImgOverlay, World.wineLabelOverlay]
            }
        });
    } else {
        document.getElementById('errorMessage').innerHTML = "<div class='errorMessage'>Recognition failed, please try again!</div>";
        setTimeout(function() {
            var e = document.getElementById('errorMessage');
            e.removeChild(e.firstChild);
        }, 3000);
    }        
},

このコールバック関数の最初のパラメーターは、サーバーがターゲットを認識できたかどうかを示すブール値です。その値は、認識結果に応じて0または1になります。2番目のパラメーターは、認識されたターゲットに関するメタデータを含むJSONオブジェクトです。ターゲットが認識された場合、このJSONオブジェクトにはtargetInfoという名前の別のJSONオブジェクトが含まれます。このオブジェクトには、ターゲット名(targetName)、その星評価(rating)、および物理的な高さ(オプション)が格納されています。ターゲットが認識されなかった場合、JSONオブジェクトは空になります。responseオブジェクトについては、次のパートで詳しく説明します。

認識が成功した場合、バナーを拡張表示します。認識されたワインラベルをすでに作成したバナーの前面に表示するため、別の拡張オブジェクトを定義しています。responseオブジェクトに含まれるtargetInfo.nameプロパティを読み取って、同じ名前の画像ファイルをロードします。バナーの前面に配置するため、zOrderプロパティを1(デフォルト値は0)に設定します。

その後で、ImageTracker、ターゲットの名前(targetInfo.name)、および拡張オブジェクトを使用して、すべてのものを集約したAR.ImageTrackableを作成します。

認識が失敗した場合は、エラーメッセージをユーザーに表示します。

連続認識モードと随時認識モードの比較(2/3)※対応するサンプルタイトル名「Continuous Recognition VS On: Click」

このパートのサンプルは、最初のパートを基に作成します。関係のある変更箇所のみを示します。先に進む前に前のパートを読み返してください。

前のパートのサンプルでは、画像の認識を随時手動で起動しました(ユーザーが[Scan]ボタンをクリック)。この方法が便利な場合もありますが、このパートで説明する連続認識モードを使用したいこともあります。大きな違いは、認識が手動のクリックによって1回だけ起動されるのではなく、定義された時間間隔で連続的に起動されることです。

この機能を有効にするために必要な変更を見ていきます。

最初の変更は'trackerLoaded'関数にあります。前のサンプルではユーザーに指示を表示するだけでしたが、今回は連続認識モードの起動も行います。

    trackerLoaded: function trackerLoadedFn() {
        this.startContinuousRecognition(750);
        this.showUserInstructions();
    },

startContinuousRecognition関数をパラメーター750を指定して呼び出します。このパラメーターは、認識を開始する頻度を示す時間間隔を表します。startContinuousRecognition関数のコードを以下に示します。

startContinuousRecognition: function startContinuousRecognitionFn(interval) {
    this.cloudRecognitionService.startContinuousRecognition(interval, this.onInterruption, this.onRecognition, this.onRecognitionError);
},

上記の関数では、AR.CloudRecognitionServicestartContinuousRecognition関数を呼び出して連続認識モードを開始しています。4つのパラメーターを渡しており、最初のパラメーターは前述したとおり、新しい認識を開始する時間間隔です。単位はミリ秒で、最小値は500です。2番目のパラメーターは、認識間隔が現在のネットワーク速度に対して高すぎる場合、SDKによって呼び出されるさらに別のコールバック関数を定義します。3番目のパラメーターは、認識サイクルが完了したときのonRecognitionErrorコールバックを定義します。最後の4番目のパラメーターは、さらにもう1つコールバック関数を定義します。この関数は、設定された認識間隔が現在のネットワーク速度に比べて短すぎる場合にSDKによって呼び出されます。

次に、コールバック関数に対する変更を示します。onRecognition関数の変更はごくわずかで、onRecognitionError関数には変更はありません。onInterruptionは新しいコールバック関数です。

最初にonRecognition関数を示します。

onRecognition: function onRecognitionFn(recognized, response) {
    if (recognized) {
        if (World.wineLabel !== undefined) {
            World.wineLabel.destroy();
        }
        if (World.wineLabelOverlay !== undefined) {
            World.wineLabelOverlay.destroy();
        }
        World.wineLabel = new AR.ImageResource("assets/" + response.targetInfo.name + ".jpg");
        World.wineLabelOverlay = new AR.ImageDrawable(World.wineLabel, 0.27, {
            translate: {
                x: -0.5,
                y: -0.6
            },
            zOrder: 1
        });
        if (World.wineLabelAugmentation !== undefined) {
            World.wineLabelAugmentation.destroy();
        }
        World.wineLabelAugmentation = new AR.ImageTrackable(World.tracker, response.targetInfo.name , {
            drawables: {
                cam: [World.bannerImgOverlay, World.wineLabelOverlay]
            }
        });
    }
},

唯一の変更は、認識が失敗したときのエラーメッセージを除去したことです。連続認識モードでは、ユーザーが実際のターゲットにカメラを向けていないときなど、認識の失敗はかなり頻繁に起こります。

次のonInterruption関数は、前のサンプルでは必要ありませんでした。この関数のコードは以下のとおりです。

onInterruption: function onInterruptionFn(suggestedInterval) {
    World.cloudRecognitionService.stopContinuousRecognition();
    World.cloudRecognitionService.startContinuousRecognition(suggestedInterval);
},

現在のネットワーク速度が設定された時間間隔に比べて十分でない場合、現在のネットワーク速度に見合った推奨される時間間隔を指定してこのコールバック関数が呼び出されます。新しい時間間隔を設定するため、連続認識モードが再起動されます。

このサンプルでは、AR.CloudRecognitionServiceの連続認識モードを有効にする方法を示しました。次のサンプルでは、サーバーのresponseオブジェクトとカスタムメタデータを使用する方法を説明します。

応答に含まれるメタデータの使用(3/3)※対応するサンプルタイトル名「Using Response Metainformation」

前のパートと同様に、このパートのサンプルも前回のパートを基に作成します。このパートに進む前に、もう一度前の2つのパートを読み返してください。

このパートでは、エンドユーザー向けの拡張オブジェクトをもう1つ追加します。今回も基となる拡張オブジェクトははどのターゲットの場合も同じなので、createOverlays関数で一度だけ作成します。この関数のコードは以下のとおりです。

createOverlays: function createOverlaysFn() {
    this.bannerImg = new AR.ImageResource("assets/bannerWithNameField.jpg");
    this.bannerImgOverlay = new AR.ImageDrawable(this.bannerImg, 0.4, {
        translate: {
            y: 0.6
        }
    });
    this.orderNowButtonImg = new AR.ImageResource("assets/orderNowButton.png");
    this.orderNowButtonOverlay = new AR.ImageDrawable(this.orderNowButtonImg, 0.3, {
        translate: {
            y: -0.6
        }
    });
},

新しく表示する拡張オブジェクトは、[Order Now]ボタンです。このボタンは、これまでの拡張オブジェクトと同じように作成します。

さらに、'onRecognition'関数を以下のように変更します。

onRecognition: function onRecognitionFn(recognized, response) {
    if (recognized) {
        if (World.wineLabelOverlay !== undefined) {
            World.wineLabel.destroy();
        }
        if (World.wineLabelOverlay !== undefined) {
            World.wineLabelOverlay.destroy();
        }
        World.wineLabel = new AR.ImageResource("assets/" + response.targetInfo.name + ".jpg");
        World.wineLabelOverlay = new AR.ImageDrawable(World.wineLabel, 0.2, {
            translate: {
                x: -0.37,
                y: 0.55
            },
            zOrder: 1
        });
        World.wineName = new AR.Label(response.metadata.name, 0.06, {
            translate: {
                y: 0.72
            },
            zOrder: 2
        });
        if (World.wineLabelAugmentation !== undefined) {
            World.wineLabelAugmentation.destroy();
        }
        World.wineLabelAugmentation = new AR.ImageTrackable(World.tracker, response.targetInfo.name , {
            drawables: {
                cam: [World.bannerImgOverlay, World.wineLabelOverlay, World.wineName]
            }
        });
        World.orderNowButtonOverlay.onClick = function() {
            AR.context.openInBrowser(response.metadata.shop_url);
        }
        if (World.orderNowAugmentation !== undefined) {
            World.orderNowAugmentation.destroy();
        }
        World.orderNowAugmentation = new AR.ImageTrackable(World.tracker, response.targetInfo.name, {
            drawables: {
                cam: World.orderNowButtonOverlay
            }
        });
    }
},

クラウドアーカイブを作成したとき、すべてのターゲットのカスタムメタデータが定義されました。メタデータの内容は必要に応じて自由に定義することができます。ターゲットのメタデータを追加する方法については、Manager APIのAPIリファレンスを参照してください。このサンプルでは、以下の2つのフィールドを作成しました。

  • metadata.name: ワインの実際の名前。
  • metadata.shop_url: そのワインを販売しているオンラインショップのURL。

上記のメタデータを含むターゲットを、Manager APIでターゲットを作成するときのJSONは以下のようになります。

    "metadata":{
         "name":"Lote 43 Cabernet Sauvignon-Merlot",
        "shop_url":"http://loja.miolo.com.br/ch/index.aspx"
     }

ワインの名前をバナーに表示するため、AR.Labelを作成します。最初のパラメーターはラベルのテキスト、2番目のパラメーターはSDU単位の高さ、3番目のパラメーターセットは任意指定のオプションです。AR.Labelの最初のパラメーターを設定するため、カスタムメタデータオブジェクトから前述のnameを読み取ります。サーバーから返されたresponseオブジェクトはJSONオブジェクトなので、ドット記法を使用できます。

作成したAR.ImageDrawableオブジェクトと同様に、AR.LabelAR.ImageTrackableに追加して、バナーに表示するものすべてを集約します。

次に、orderNowButtonOverlayonClickトリガーを追加し、そこでAR.contextクラスを使用してブラウザでオンラインショップ開きます。この場合もサーバーのresponseオブジェクトとカスタムメタデータを使用して、shop_urlからオンラインショップのURLを読み取っています。