クラウド認識

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

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

単一画像の認識

対応するサンプルタイトル名「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.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を作成します。

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

連続認識モードと随時認識モードの比較

対応するサンプルタイトル名「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オブジェクトとカスタムメタデータを使用する方法を説明します。

応答に含まれるメタデータの使用

対応するサンプルタイトル名「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を読み取っています。