ML Kit を使用して画像内のテキストを認識する(Android)

ML Kit を使用すると、端末モデルまたはクラウドモデルで画像内のテキストを認識できます。それぞれのアプローチの利点については、概要をご覧ください。

この API の使用例については、GitHub の ML Kit クイックスタート サンプルを参照するか、Codelab を試してみてください。

準備

  1. まだアプリに Firebase を追加していない場合は、スタートガイドの手順に沿って追加してください。
  2. アプリレベルの build.gradle ファイルに ML Kit の依存関係を含めます。
    dependencies {
      // ...
    
      implementation 'com.google.firebase:firebase-ml-vision:16.0.0'
    }
    
  3. 省略可能、ただし推奨: 端末用 API を使用する場合は、アプリが Play ストアからインストールされたら自動で ML モデルを端末にダウンロードするようにアプリを構成します。

    この構成を行うには、アプリの AndroidManifest.xml ファイルに次の宣言を追加します。

    <application ...>
      ...
      <meta-data
          android:name="com.google.firebase.ml.vision.DEPENDENCIES"
          android:value="text" />
      <!-- To use multiple models: android:value="text,model2,model3" -->
    </application>
    
    インストール時点でのモデルのダウンロードを有効にしない場合は、端末上の検出器の初回実行時にモデルがダウンロードされます。ダウンロードが完了する前にリクエストしても結果は生成されません。
  4. クラウドベースのモデルを使用するが、プロジェクトを Blaze プランにアップグレードしていない場合は、Firebase コンソールでアップグレードしてください。Blaze レベルのプロジェクトのみが Cloud Vision API を使用できます。
  5. クラウドベース モデルを使用する場合は、Cloud Vision API も有効にします。
    1. Cloud Console API ライブラリで Cloud Vision API を開きます。
    2. ページ上部のメニューで Firebase プロジェクトが選択されていることを確認します。
    3. API がまだ有効になっていない場合は、[有効にする] をクリックします。
    端末モデルのみを使用する場合は、この手順を省略できます。

これで、端末モデルまたはクラウドベース モデルを使用して画像内のテキストを認識する準備ができました。


端末上でのテキスト認識

端末上でのテキスト認識モデルを使用するには、後述のテキスト検出ツールを実行します。

1. テキスト検出ツールを実行する

画像内のテキストを認識するには FirebaseVisionImage オブジェクトを作成します。このオブジェクトは、Bitmapmedia.ImageByteBuffer、バイト配列、端末上のファイルのいずれかから作成できます。次に、FirebaseVisionImage オブジェクトを FirebaseVisionTextDetectordetectInImage メソッドに渡します。

  1. 画像から FirebaseVisionImage オブジェクトを作成します。

    • FirebaseVisionImage オブジェクトを Bitmap オブジェクトから作成するコードは、以下のとおりです。
      FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
      Bitmap オブジェクトによって表される画像は、これ以上回転させる必要がないように、正しい向きになっている必要があります。
    • FirebaseVisionImage オブジェクトを media.Image オブジェクトから作成するには(端末のカメラから画像をキャプチャする場合など)、端末の回転と搭載されたカメラセンサーの向きの両方を補正するために、まず画像の回転角度を決定します。
      private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
      static {
          ORIENTATIONS.append(Surface.ROTATION_0, 90);
          ORIENTATIONS.append(Surface.ROTATION_90, 0);
          ORIENTATIONS.append(Surface.ROTATION_180, 270);
          ORIENTATIONS.append(Surface.ROTATION_270, 180);
      }
      
      /**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      private int getRotationCompensation(String cameraId, Activity activity, Context context)
              throws CameraAccessException {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
          int rotationCompensation = ORIENTATIONS.get(deviceRotation);
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
          int sensorOrientation = cameraManager
                  .getCameraCharacteristics(cameraId)
                  .get(CameraCharacteristics.SENSOR_ORIENTATION);
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360;
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          int result;
          switch (rotationCompensation) {
              case 0:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  break;
              case 90:
                  result = FirebaseVisionImageMetadata.ROTATION_90;
                  break;
              case 180:
                  result = FirebaseVisionImageMetadata.ROTATION_180;
                  break;
              case 270:
                  result = FirebaseVisionImageMetadata.ROTATION_270;
                  break;
              default:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  Log.e(TAG, "Bad rotation value: " + rotationCompensation);
          }
          return result;
      }

      次に、media.Image オブジェクトと回転値を FirebaseVisionImage.fromMediaImage() に渡します。

      FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
    • FirebaseVisionImage オブジェクトを ByteBuffer またはバイト配列から作成するには、前述のようにまず画像の回転を計算します。

      次に、画像の高さ、幅、カラー エンコーディング形式、回転を含む FirebaseVisionImageMetadata オブジェクトを作成します。

      FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
              .setWidth(1280)
              .setHeight(720)
              .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
              .setRotation(rotation)
              .build();

      バッファまたは配列、およびメタデータ オブジェクトを使用して、FirebaseVisionImage オブジェクトを作成します。

      FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata);
      // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
      
    • FirebaseVisionImage オブジェクトをファイルから作成するには、アプリケーション コンテキストとファイルの URI を FirebaseVisionImage.fromFilePath() に渡します。
      FirebaseVisionImage image;
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri);
      } catch (IOException e) {
          e.printStackTrace();
      }

  2. FirebaseVisionTextDetector のインスタンスを取得します。

    FirebaseVisionTextDetector detector = FirebaseVision.getInstance()
            .getVisionTextDetector();

  3. 最後に、画像を detectInImage メソッドに渡します。

    Task<FirebaseVisionText> result =
            detector.detectInImage(image)
                    .addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() {
                        @Override
                        public void onSuccess(FirebaseVisionText firebaseVisionText) {
                            // Task completed successfully
                            // ...
                        }
                    })
                    .addOnFailureListener(
                            new OnFailureListener() {
                                @Override
                                public void onFailure(@NonNull Exception e) {
                                    // Task failed with an exception
                                    // ...
                                }
                            });

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

テキスト認識オペレーションが成功すると、FirebaseVisionText オブジェクトが成功リスナーに渡されます。このオブジェクトから、認識されたテキスト ブロック、画像上のブロックの境界、ブロックに含まれるテキストを取得できます。また、各ブロックについて、そのブロックを構成するテキスト行と、各テキスト行を構成する文字や句読点などの要素を取得できます。

for (FirebaseVisionText.Block block: firebaseVisionText.getBlocks()) {
    Rect boundingBox = block.getBoundingBox();
    Point[] cornerPoints = block.getCornerPoints();
    String text = block.getText();

    for (FirebaseVisionText.Line line: block.getLines()) {
        // ...
        for (FirebaseVisionText.Element element: line.getElements()) {
            // ...
        }
    }
}

クラウドでのテキスト認識

クラウドベースのテキスト認識モデルを使用するには、後述のテキスト検出ツールを構成し、実行します。

1. テキスト検出ツールを構成する

デフォルトでは、Cloud 検出ツールは STABLE バージョンのモデルを使用して、最大 10 件の結果を返します。この設定を変更したい場合には、FirebaseVisionCloudDetectorOptions オブジェクトを使用して設定し直します。

たとえば、デフォルト設定を両方とも変更するには、次の例のように FirebaseVisionCloudDetectorOptions オブジェクトをビルドします。

FirebaseVisionCloudDetectorOptions options =
    new FirebaseVisionCloudDetectorOptions.Builder()
        .setModelType(FirebaseVisionCloudDetectorOptions.LATEST_MODEL)
        .setMaxResults(15)
        .build();

デフォルト設定を使用するには、次の手順で FirebaseVisionCloudDetectorOptions.DEFAULT を使用します。

2. テキスト検出ツールを実行する

画像内のテキストを認識するには FirebaseVisionImage オブジェクトを作成します。このオブジェクトは、Bitmapmedia.ImageByteBuffer、バイト配列、端末上のファイルのいずれかから作成できます。次に、FirebaseVisionImage オブジェクトを FirebaseVisionCloudTextDetector に渡します。画像がドキュメントである場合は、このオブジェクトを FirebaseVisionCloudDocumentTextDetectordetectInImage メソッドに渡します。

  1. 画像から FirebaseVisionImage オブジェクトを作成します。

    • FirebaseVisionImage オブジェクトを Bitmap オブジェクトから作成するコードは、以下のとおりです。
      FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
      Bitmap オブジェクトによって表される画像は、これ以上回転させる必要がないように、正しい向きになっている必要があります。
    • FirebaseVisionImage オブジェクトを media.Image オブジェクトから作成するには(端末のカメラから画像をキャプチャする場合など)、端末の回転と搭載されたカメラセンサーの向きの両方を補正するために、まず画像の回転角度を決定します。
      private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
      static {
          ORIENTATIONS.append(Surface.ROTATION_0, 90);
          ORIENTATIONS.append(Surface.ROTATION_90, 0);
          ORIENTATIONS.append(Surface.ROTATION_180, 270);
          ORIENTATIONS.append(Surface.ROTATION_270, 180);
      }
      
      /**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      private int getRotationCompensation(String cameraId, Activity activity, Context context)
              throws CameraAccessException {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
          int rotationCompensation = ORIENTATIONS.get(deviceRotation);
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
          int sensorOrientation = cameraManager
                  .getCameraCharacteristics(cameraId)
                  .get(CameraCharacteristics.SENSOR_ORIENTATION);
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360;
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          int result;
          switch (rotationCompensation) {
              case 0:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  break;
              case 90:
                  result = FirebaseVisionImageMetadata.ROTATION_90;
                  break;
              case 180:
                  result = FirebaseVisionImageMetadata.ROTATION_180;
                  break;
              case 270:
                  result = FirebaseVisionImageMetadata.ROTATION_270;
                  break;
              default:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  Log.e(TAG, "Bad rotation value: " + rotationCompensation);
          }
          return result;
      }

      次に、media.Image オブジェクトと回転値を FirebaseVisionImage.fromMediaImage() に渡します。

      FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
    • FirebaseVisionImage オブジェクトを ByteBuffer またはバイト配列から作成するには、前述のようにまず画像の回転を計算します。

      次に、画像の高さ、幅、カラー エンコーディング形式、回転を含む FirebaseVisionImageMetadata オブジェクトを作成します。

      FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
              .setWidth(1280)
              .setHeight(720)
              .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
              .setRotation(rotation)
              .build();

      バッファまたは配列、およびメタデータ オブジェクトを使用して、FirebaseVisionImage オブジェクトを作成します。

      FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata);
      // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
      
    • FirebaseVisionImage オブジェクトをファイルから作成するには、アプリケーション コンテキストとファイルの URI を FirebaseVisionImage.fromFilePath() に渡します。
      FirebaseVisionImage image;
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri);
      } catch (IOException e) {
          e.printStackTrace();
      }

  2. FirebaseVisionCloudTextDetector または FirebaseVisionCloudDocumentTextDetector のインスタンスを取得します。

    FirebaseVisionCloudTextDetector detector = FirebaseVision.getInstance()
            .getVisionCloudTextDetector();
    // Or, to change the default settings:
    // FirebaseVisionCloudTextDetector detector = FirebaseVision.getInstance()
    //         .getVisionCloudTextDetector(options);

  3. 最後に、画像を detectInImage メソッドに渡します。

    Task<FirebaseVisionCloudText> result = detector.detectInImage(image)
            .addOnSuccessListener(new OnSuccessListener<FirebaseVisionCloudText>() {
                @Override
                public void onSuccess(FirebaseVisionCloudText firebaseVisionCloudText) {
                    // Task completed successfully
                    // ...
                }
            })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    // Task failed with an exception
                    // ...
                }
            });

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

テキスト認識オペレーションが成功すると、FirebaseVisionCloudText オブジェクトが成功リスナーに渡されます。このオブジェクトには、画像から認識されたテキストが含まれています。

また、テキストの構造に関する情報も取得できます。テキストは、ページ、ブロック、段落、語、記号で構成されます。各構成単位について、ディメンションやその中に含まれる言語などの情報を取得できます。

例:

String recognizedText = firebaseVisionCloudText.getText();

for (FirebaseVisionCloudText.Page page: firebaseVisionCloudText.getPages()) {
    List<FirebaseVisionCloudText.DetectedLanguage> languages =
            page.getTextProperty().getDetectedLanguages();
    int height = page.getHeight();
    int width = page.getWidth();
    float confidence = page.getConfidence();

    for (FirebaseVisionCloudText.Block block: page.getBlocks()) {
        Rect boundingBox = block.getBoundingBox();
        List<FirebaseVisionCloudText.DetectedLanguage> blockLanguages =
                block.getTextProperty().getDetectedLanguages();
        float blockConfidence = block.getConfidence();
        // And so on: Paragraph, Word, Symbol
    }
}

フィードバックを送信...

ご不明な点がありましたら、Google のサポートページをご覧ください。