一覧に戻る

iOS ネイティブAPIの画像認識

2017.09.22iOSネイティブAPI

画像認識

このトピックではカメラビュー内の画像を認識し、それらの画像の上に拡張オブジェクトを表示する方法を示します。
まずは、より良く理解できるように、このドキュメントで使用する画像認識型ARに関する用語の定義を以下に示します。

  • ターゲット: 認識対象の2D画像と認識に必要とされる抽出データ。
  • ターゲットコレクション: 2Dターゲットの集合体。1つのターゲットコレクションには最大1,000のターゲットを格納できます。
  • 画像トラッカー: トラッカーはカメラビューの画像を分析し、ターゲットコレクションに格納されたターゲットを検出します。複数のトラッカーを作成できますが、同時に使用できるトラッカーは1つだけです。

シンプルな画像認識

サンプルのNative Examples/Controller/ClientTrackingフォルダにあるWTSimpleClientTrackerViewControllerのコードを解説します。ここではWikitude SDK ネイティブAPIの使い方に関する一般的な概念についても説明します。

Wikitude SDK ネイティブAPIをXcodeプロジェクトに統合する方法については、「iOS ネイティブAPIのセットアップ」をご確認ください。

この例では、外部レンダリングを使用します。レンダリングの設定方法と、内部レンダリングと外部レンダリングの違いについては、レンダリングのトピックスを参照してください。

WTWikitudeNativeSDKクラスは、MVCパターンのモデルとして標準のiOSビューコントローラーで使用されるように構成されています。このクラスは、Wikitude SDK ネイティブAPIに関連する中心的な出発点となり、異なる種類のトラッカーを作成し、デリゲートオブジェクトを介してそれらの情報を受け取るためのファクトリメソッドを提供します。

一般的な使い方は、ビューコントローラー内でWTWikitudeNativeSDKオブジェクトへの強い参照を持ち、このビューコントローラーをWTWikitudeNativeSDKDelegateプロトコルに準拠するように定義することです。

@interface WTSimpleClientTrackerViewController () <WTWikitudeNativeSDKDelegate, WTImageTrackerDelegate>

WTWikitudeNativeSDKDelegateプロトコルは、SDK固有のイベント処理に使用できるメソッドを定義します。これは、たとえばAPI呼び出しから直接返すことができないランタイムエラーなどを伝えるための手段です。そのようなエラーには、カメラ認証ステータスの変更やレンダリング設定の不一致に関する情報が含まれる場合があります。

認識されたターゲット、トラッキング中のターゲット、または見失ったターゲットに関する画像トラッカーの情報を取得するため、このビューコントローラーはWTImageTrackerDelegateプロトコルにも準拠します。このプロトコルのメソッドはすべてオプションです。したがって、SDKから情報を提供するだけであり、アプリケーションに何のアクションも要求しません。さらに、このプロトコルは特定の画像トラッカーオブジェクトのロードステータスに関する情報も提供します。

次のステップは、WTWikitudeNativeSDKクラスのインスタンスを作成することです。開発者が手動で作成するのはこのオブジェクトだけです。その他のオブジェクトはすべて、WTWikitudeNativeSDKオブジェクトのファクトリメソッドによって作成されます。

WTWikitudeNativeSDKオブジェクトはいつでもインスタンス化でき、アプリケーションの特定のライフサイクルイベントに依存しません。内部プロセスをアプリケーションに統合するには、-start:completionと-stopを使用します。これら2つのメソッドは、- viewWillAppear: | - viewWillDisappear:または-viewDidAppear: | -viewDidDisappear:から呼び出します。 Wikitude SDK ネイティブAPIの起動動作を細かく調整するには、-start:completion:の最初のブロックパラメーターに、すでに作成してセットアップしたWTNativeSDKStartupConfiguration型のオブジェクトを含めます。このオブジェクトのパブリックプロパティを使用して、Wikitude SDK ネイティブAPIの起動方法をさらに詳細に定義できます。このオプションの通常の設定は、デバイスカメラの開始時の解像度やターゲットレンダリング時のフレームレートを定義したカメラプリセットです。 2番目のブロックパラメーターには、最終的な起動フェーズ中に特定のプロパティを考慮するかどうかを示すブール値を含めます。エラーが発生した場合、isRunningがNOに設定され、指定したNSErrorオブジェクトにエラーに関する詳細情報が格納されます。

2番目のブロックパラメーターはTrackerオブジェクトを作成する場所としても適しており、実行状態がYESの場合にWikitude SDK ネイティブAPIからTrackerオブジェクトを作成できます。画像トラッカーは、.wtcファイル(Wikitude Target Collection)で表されるターゲットコレクションを読み込むターゲットコレクションリソースで動作します。.wtcファイルは、アプリケーションバンドルに含めることができ、NSBundleメソッドのURLForResource:withExtension:subdirectory:を使用して取得したファイルURL、またはサーバにアップロードしてWikitude SDK ネイティブAPIからダウンロードすることができます。

最初に、TargetCollectionResourceはWTWikitudeNativeSDKのcreateTargetCollectionResourceFromURL:completionファクトリメソッドによって作成され、ターゲットコレクションを含むファイルの読み込みが正常に終了すると、ImageTrackerはパラメーターとして作成されます。

画像トラッカーの読み込み完了を通知するのは、デリゲートメソッド-imageTrackerDidLoadTargets:が呼び出されるか、または、-imageTracker:didFailToLoadTargets:が.wtcを読み込めなかった場合です。Target Collection Resourceが正常に終了しても、画像トラッカーがターゲットの読み込みに失敗した場合は、ファイルは正常に読み込まれても、画像トラッカーが破損しているか、サポートされていないバージョン、またはターゲットコレクションのファイルではない可能性があります。

[self.wikitudeSDK start:nil completion:^(BOOL isRunning, NSError * __nonnull error) {
    if ( !isRunning ) {
        NSLog(@"Wikitude SDK is not running. Reason: %@", [error localizedDescription]);
    }
    else
    {
        __weak typeof(self) weakSelf = self;

        NSURL *imageTrackerResourceURL = [[NSBundle mainBundle] URLForResource:@"magazine" withExtension:@"wtc" subdirectory:@"Assets"];
        self.targetCollectionResource = [self.wikitudeSDK.trackerManager createTargetCollectionResourceFromURL:imageTrackerResourceURL completion:^(BOOL success, NSError * _Nullable error) {
            if ( !success )
            {
                NSLog(@"Failed to load URL resource. Reason: %@", [error localizedDescription]);
            }
            else
            {
                weakSelf.imageTracker = [weakSelf.wikitudeSDK.trackerManager createImageTrackerFromTargetCollectionResource:weakSelf.targetCollectionResource delegate:weakSelf configuration:nil];
            }
        }];
    }
}];

次に、Tracker固有のデータを取得する方法を確認します。WTImageTrackerDelegateには、Trackerがターゲットを見つけたとき、見失ったとき、またはトラッキングしたときに呼び出される3つのメソッドがあります。

  • -imageTracker:didRecognizeImage: 現在のカメラビュー内に新しいターゲットが見つかった場合に呼び出されます。
  • -imageTracker:didTrackImage: 既知のターゲットが新しい位置に移動したときに呼び出されます。
  • -imageTracker:didLoseImage: 既知のターゲットが最新のカメラビュー内で確認できなくなったときに呼び出されます。

WTImageTargetオブジェクトは、たとえば、ターゲットの位置が変更されたなどの、ターゲット変更情報を提供します。ターゲットの位置はOpenGLのモデルビュー行列によって表されます。

- (void)imageTracker:(nonnull WTImageTracker *)imageTracker didRecognizeTarget:(nonnull WTImageTarget *)recognizedTarget
{
    NSLog(@"recognized target '%@'", [recognizedTarget name]);
    _isTracking = YES;
}

- (void)imageTracker:(nonnull WTImageTracker *)imageTracker didTrackTarget:(nonnull WTImageTarget *)trackedTarget
{
    [self.renderableRectangle setProjectionMatrix:trackedTarget.projection];
    [self.renderableRectangle setModelViewMatrix:trackedTarget.modelView];
}

- (void)imageTracker:(nonnull WTImageTracker *)imageTracker didLoseTarget:(nonnull WTImageTarget *)lostTarget
{
    NSLog(@"lost target '%@'", [lostTarget name]);
    _isTracking = NO;
}


- (void)imageTrackerDidLoadTargets:(nonnull WTImageTracker *)imageTracker
{
    NSLog(@"Image tracker loaded");
}

- (void)imageTracker:(nonnull WTImageTracker *)imageTracker didFailToLoadTargets withError:(nonnull NSError *)error
{
    NSLog(@"Unable to load image tracker. Reason: %@", [error localizedDescription]);
}

複数ターゲットの画像認識

Simple 2D Client Trackingのサンプルに複数ターゲットのトラッキングを追加する手順を示します。このサンプルは、サンプルアプリケーションフォルダのNative Examples/Controller/ClientTrackingにあります。

Simple 2D Client Trackingのサンプルでは、ターゲットを1つだけトラッキングしますが、これは簡単に変更できます。このサンプルでは、最大5つのターゲットをトラッキングします。最大数の設定は、5つのターゲットがトラッキングされている場合は、追加のターゲット検索を停止できるのでパフォーマンスの最適化になります。ユースケースで最大数を設定できる場合は、この方法をお勧めします。

はじめにUIViewControllerをWTImageTargetDelegateにしなければならないため、画像ターゲット間の距離の変化に対応できます。

@interface WTMultipleTargetsTrackerViewController () <WTWikitudeNativeSDKDelegate, WTImageTrackerDelegate, WTImageTargetDelegate>

複数ターゲットをトラッキングする場合は、トラッキングを視覚化するために複数のStrokedRectangleインスタンスが必要です。そのため、renderableRectangleを取り除き、代わりにNSMutableDictionaryを作成します。

@property (nonatomic, strong) NSMutableDictionary *renderableRectangles;

-viewDidLoadでは辞書を初期化し、その他はそのまま残します。
Wikitude SDK ネイティブAPIに追加が必要な唯一の設定は-viewDidAppear:です。ここでは主に以前と同じように画像トラッカーを作成しますが、最後のパラメーターとしてWTImageTrackerConfigurationを追加します。この設定では、画像トラッカーに、同時にトラッキング可能なターゲットの最大数を5に設定するよう指示します。もう1つの必要な設定はdistanceChangedThresholdで、Wikitude SDK ネイティブAPIが -didRecognizeChangeBetweenImageTarget:andImageTarget:コールバック関数を起動するための2つのターゲット間の距離の変化を判断する値です。

weakSelf.imageTracker = [weakSelf.wikitudeSDK.trackerManager createImageTrackerFromTargetCollectionResource:weakSelf.targetCollectionResource delegate:weakSelf configuration:^(WTImageTrackerConfiguration *imageTrackerConfiguration) {
    imageTrackerConfiguration.maximumNumberOfConcurrentlyTrackableTargets = 5;
}];

[weakSelf.imageTracker setDistanceChangedThreshold:10.0f];

これはWikitude SDK ネイティブAPIの設定なので、矩形の処理だけが必要になります。ほとんどの矩形処理は、Simple 2D Client Trackingのサンプルとまったく同じですが、唯一の違いは、StrokedRectangleインスタンスのすべて、またはディクショナリから最初にフェッチする必要がある変更のいずれかに変更を適用する必要があることです。同じ画像の複数のインスタンスが存在する可能性があるため、固有のキーが必要です。-getKeyForImageTarget:関数を使用して、nameとtrackingIdの値の組み合わせたWTImageTargetごとの固有のキーを作成します。
画像トラッカーが画像を認識すると、-imageTracker:didRecognizeImage:-callback関数が呼び出されます。その中でUIViewController認識されたターゲットの代表としてUIViewControllerを作成します。さらに、recognizedTargetの名前でrenderableRectangles辞書に追加する新しいStrokedRectangleインスタンスを作成します。

NSString* key = [self getKeyForImageTarget:recognizedTarget];

recognizedTarget.delegate = self;
[self.renderableRectangles setObject:[[StrokedRectangle alloc]init] forKey:key];

前に定義したように、-didRecognizeChangeBetweenImageTarget:andImageTarget:コールバック関数は、ターゲット間の距離が一定のしきい値を超えて変更されたときに呼び出されます。デモンストレーションの目的で、300.0のしきい値を設定し、矩形同士が近づきすぎた場合、矩形の色を赤に変更します。両方のターゲットが同じ画像のインスタンスである場合、それらの矩形の色を青に設定します。

- (void)didRecognizeChangeBetweenImageTarget:(nonnull WTImageTarget *)firstTarget andImageTarget:(nonnull WTImageTarget *)secondTarget
{
    UIColor *rectColor = [UIColor colorWithRed:1.0f green:0.58f blue:0.16f alpha:1.0f];

    if ( 300.f > [firstTarget distanceTo:secondTarget] )
    {
        if ( [firstTarget.name isEqualToString:secondTarget.name] )
        {
            rectColor = [UIColor blueColor];
        }
        else
        {
            rectColor = [UIColor redColor];
        }
    }

    NSString* firstKey = [self getKeyForImageTarget:firstTarget];
    NSString* secondKey = [self getKeyForImageTarget:secondTarget];
    [(StrokedRectangle *)[self.renderableRectangles objectForKey:firstKey] setColor:rectColor];
    [(StrokedRectangle *)[self.renderableRectangles objectForKey:secondKey] setColor:rectColor];
}

画像トラッキングの拡張

Simple 2D Client Trackingサンプルでトラッキングの拡張を有効にするには、トラッキングの拡張の対象を定義する文字列配列を指定する必要があります。下記では、ワイルドカードの*を設定して、このトラッカーのすべてのターゲットをトラッキングの拡張の対象としています。

weakSelf.imageTracker = [weakSelf.wikitudeSDK.trackerManager createImageTrackerFromTargetCollectionResource:weakSelf.targetCollectionResource delegate:weakSelf configuration:^(WTImageTrackerConfiguration *imageTrackerConfiguration) {
    imageTrackerConfiguration.extendedTargets = @[@"*"];
}];