2022 年 10 月 18 日に開催される Firebase Summit に、直接会場で、またはオンラインでご参加ください。Firebase を使用してアプリ開発を加速させ、自信を持ってアプリをリリースし、簡単にスケールする方法をご紹介します。 今すぐ申し込む

AppleプラットフォームでFirebaseAuthとFunctionsを使用して、CloudVisionで画像内のテキストを安全に認識します

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

アプリから Google Cloud API を呼び出すには、承認を処理し、API キーなどの秘密の値を保護する中間 REST API を作成する必要があります。次に、モバイル アプリでコードを記述して、この中間サービスを認証し、通信する必要があります。

この REST API を作成する 1 つの方法は、Firebase Authentication and Functions を使用することです。これにより、Google Cloud API へのマネージド サーバーレス ゲートウェイが提供されます。このゲートウェイは、認証を処理し、ビルド済みの SDK を使用してモバイル アプリから呼び出すことができます。

このガイドでは、この手法を使用してアプリから Cloud Vision API を呼び出す方法を示します。この方法では、すべての認証済みユーザーが Cloud プロジェクトを介して Cloud Vision の有料サービスにアクセスできるようになるため、先に進む前に、この認証メカニズムがユースケースに十分かどうかを検討してください。

あなたが始める前に

プロジェクトを構成する

アプリに Firebase をまだ追加していない場合は、スタート ガイドの手順に従って追加してください。

Swift Package Manager を使用して、Firebase の依存関係をインストールおよび管理します。

  1. Xcode で、アプリ プロジェクトを開いた状態で、 File > Add Packagesに移動します。
  2. プロンプトが表示されたら、Firebase Apple プラットフォーム SDK リポジトリを追加します。
  3.   https://github.com/firebase/firebase-ios-sdk
  4. Firebase ML ライブラリを選択します。
  5. 完了すると、Xcode はバックグラウンドで依存関係の解決とダウンロードを自動的に開始します。

次に、アプリ内セットアップを実行します。

  1. アプリで、Firebase をインポートします。

    迅速

    import FirebaseMLModelDownloader

    Objective-C

    @import FirebaseMLModelDownloader;

さらにいくつかの構成手順を実行すると、準備が整います。

  1. プロジェクトでクラウドベースの API をまだ有効にしていない場合は、ここで有効にします。

    1. Firebase コンソールのFirebase ML API ページを開きます。
    2. プロジェクトを Blaze 料金プランにまだアップグレードしていない場合は、[アップグレード] をクリックしてアップグレードします。 (プロジェクトが Blaze プランに含まれていない場合にのみ、アップグレードするように求められます。)

      Blaze レベルのプロジェクトのみがクラウドベースの API を使用できます。

    3. クラウドベースの API がまだ有効になっていない場合は、[クラウドベースの API を有効にする] をクリックします。
  2. Cloud Vision API へのアクセスを禁止するように、既存の Firebase API キーを構成します。
    1. Cloud コンソールの資格情報ページを開きます。
    2. リスト内の API キーごとに編集ビューを開き、[キーの制限] セクションで、Cloud Vision API を除く使用可能なすべての API をリストに追加します。

呼び出し可能な関数をデプロイする

次に、アプリと Cloud Vision API をブリッジするために使用する Cloud Function をデプロイします。 functions-samplesリポジトリには、使用できる例が含まれています。

デフォルトでは、この関数を介して Cloud Vision API にアクセスすると、アプリの認証済みユーザーのみが Cloud Vision API にアクセスできます。さまざまな要件に合わせて関数を変更できます。

関数をデプロイするには:

  1. functions-samples リポジトリを複製またはダウンロードし、 vision-annotate-imageディレクトリに変更します:
    git clone https://github.com/firebase/functions-samples
    cd vision-annotate-image
    
  2. 依存関係のインストール:
    cd functions
    npm install
    cd ..
    
  3. Firebase CLI がない場合は、インストールします。
  4. vision-annotate-imageディレクトリで Firebase プロジェクトを初期化します。プロンプトが表示されたら、リストからプロジェクトを選択します。
    firebase init
  5. 関数をデプロイします:
    firebase deploy --only functions:annotateImage

アプリに Firebase Auth を追加する

上記でデプロイされた呼び出し可能関数は、アプリの認証されていないユーザーからのリクエストを拒否します。まだ行っていない場合は、アプリに Firebase Auth を追加する必要があります。

アプリに必要な依存関係を追加する

Swift Package Manager を使用して Cloud Functions for Firebase ライブラリをインストールします。

これで、画像内のテキストの認識を開始する準備が整いました。

1. 入力画像を準備する

Cloud Vision を呼び出すには、画像を base64 でエンコードされた文字列としてフォーマットする必要があります。 UIImageを処理するには:

迅速

guard let imageData = uiImage.jpegData(compressionQuality: 1.0f) else { return }
let base64encodedImage = imageData.base64EncodedString()

Objective-C

NSData *imageData = UIImageJPEGRepresentation(uiImage, 1.0f);
NSString *base64encodedImage =
  [imageData base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];

2. callable 関数を呼び出してテキストを認識する

画像内のランドマークを認識するには、 JSON Cloud Vision リクエストを渡して呼び出し可能な関数を呼び出します。

  1. まず、Cloud Functions のインスタンスを初期化します。

    迅速

    lazy var functions = Functions.functions()
    

    Objective-C

    @property(strong, nonatomic) FIRFunctions *functions;
    
  2. リクエストを作成します。 Cloud Vision API は、 TEXT_DETECTIONDOCUMENT_TEXT_DETECTIONの 2種類のテキスト検出をサポートしています。 2 つのユース ケースの違いについては、 Cloud Vision OCR ドキュメントを参照してください。

    迅速

    let requestData = [
      "image": ["content": base64encodedImage],
      "features": ["type": "TEXT_DETECTION"],
      "imageContext": ["languageHints": ["en"]]
    ]
    

    Objective-C

    NSDictionary *requestData = @{
      @"image": @{@"content": base64encodedImage},
      @"features": @{@"type": @"TEXT_DETECTION"},
      @"imageContext": @{@"languageHints": @[@"en"]}
    };
    
  3. 最後に、関数を呼び出します。

    迅速

    functions.httpsCallable("annotateImage").call(requestData) { (result, error) in
      if let error = error as NSError? {
        if error.domain == FunctionsErrorDomain {
          let code = FunctionsErrorCode(rawValue: error.code)
          let message = error.localizedDescription
          let details = error.userInfo[FunctionsErrorDetailsKey]
        }
        // ...
      }
      // Function completed succesfully
    }
    

    Objective-C

    [[_functions HTTPSCallableWithName:@"annotateImage"]
                              callWithObject:requestData
                                  completion:^(FIRHTTPSCallableResult * _Nullable result, NSError * _Nullable error) {
            if (error) {
              if (error.domain == FIRFunctionsErrorDomain) {
                FIRFunctionsErrorCode code = error.code;
                NSString *message = error.localizedDescription;
                NSObject *details = error.userInfo[FIRFunctionsErrorDetailsKey];
              }
              // ...
            }
            // Function completed succesfully
            // Get information about labeled objects
    
          }];
    

3. 認識されたテキストのブロックからテキストを抽出する

テキスト認識操作が成功すると、タスクの結果でBatchAnnotateImagesResponseの JSON 応答が返されます。テキスト注釈はfullTextAnnotationオブジェクトにあります。

認識されたテキストをtextフィールドの文字列として取得できます。例えば:

迅速

guard let annotation = (result?.data as? [String: Any])?["fullTextAnnotation"] as? [String: Any] else { return }
print("%nComplete annotation:")
let text = annotation["text"] as? String ?? ""
print("%n\(text)")

Objective-C

NSDictionary *annotation = result.data[@"fullTextAnnotation"];
if (!annotation) { return; }
NSLog(@"\nComplete annotation:");
NSLog(@"\n%@", annotation[@"text"]);

画像の領域に固有の情報を取得することもできます。 blockparagraphword 、およびsymbolごとに、領域で認識されたテキストと領域の境界座標を取得できます。例えば:

迅速

guard let pages = annotation["pages"] as? [[String: Any]] else { return }
for page in pages {
var pageText = ""
guard let blocks = page["blocks"] as? [[String: Any]] else { continue }
for block in blocks {
    var blockText = ""
    guard let paragraphs = block["paragraphs"] as? [[String: Any]] else { continue }
    for paragraph in paragraphs {
    var paragraphText = ""
    guard let words = paragraph["words"] as? [[String: Any]] else { continue }
    for word in words {
        var wordText = ""
        guard let symbols = word["symbols"] as? [[String: Any]] else { continue }
        for symbol in symbols {
        let text = symbol["text"] as? String ?? ""
        let confidence = symbol["confidence"] as? Float ?? 0.0
        wordText += text
        print("Symbol text: \(text) (confidence: \(confidence)%n")
        }
        let confidence = word["confidence"] as? Float ?? 0.0
        print("Word text: \(wordText) (confidence: \(confidence)%n%n")
        let boundingBox = word["boundingBox"] as? [Float] ?? [0.0, 0.0, 0.0, 0.0]
        print("Word bounding box: \(boundingBox.description)%n")
        paragraphText += wordText
    }
    print("%nParagraph: %n\(paragraphText)%n")
    let boundingBox = paragraph["boundingBox"] as? [Float] ?? [0.0, 0.0, 0.0, 0.0]
    print("Paragraph bounding box: \(boundingBox)%n")
    let confidence = paragraph["confidence"] as? Float ?? 0.0
    print("Paragraph Confidence: \(confidence)%n")
    blockText += paragraphText
    }
    pageText += blockText
}

Objective-C

for (NSDictionary *page in annotation[@"pages"]) {
  NSMutableString *pageText = [NSMutableString new];
  for (NSDictionary *block in page[@"blocks"]) {
    NSMutableString *blockText = [NSMutableString new];
    for (NSDictionary *paragraph in block[@"paragraphs"]) {
      NSMutableString *paragraphText = [NSMutableString new];
      for (NSDictionary *word in paragraph[@"words"]) {
        NSMutableString *wordText = [NSMutableString new];
        for (NSDictionary *symbol in word[@"symbols"]) {
          NSString *text = symbol[@"text"];
          [wordText appendString:text];
          NSLog(@"Symbol text: %@ (confidence: %@\n", text, symbol[@"confidence"]);
        }
        NSLog(@"Word text: %@ (confidence: %@\n\n", wordText, word[@"confidence"]);
        NSLog(@"Word bounding box: %@\n", word[@"boundingBox"]);
        [paragraphText appendString:wordText];
      }
      NSLog(@"\nParagraph: \n%@\n", paragraphText);
      NSLog(@"Paragraph bounding box: %@\n", paragraph[@"boundingBox"]);
      NSLog(@"Paragraph Confidence: %@\n", paragraph[@"confidence"]);
      [blockText appendString:paragraphText];
    }
    [pageText appendString:blockText];
  }
}