6 月 3 日の「#Android11: The Beta Launch Show」にぜひご参加ください。

構成オプション

CameraX ユースケースを個別に構成すると、ユースケースのさまざまな処理を制御できます。

たとえば、画像キャプチャ ユースケースでは、ターゲット アスペクト比とフラッシュ モードを設定できます。次のコードはその一例を示しています。

Kotlin

    val imageCapture = ImageCapture.Builder()
        .setFlashMode(...)
        .setTargetAspectRatio(...)
        .build()
    

Java

    ImageCapture imageCapture =
        new ImageCapture.Builder()
            .setFlashMode(...)
            .setTargetAspectRatio(...)
            .build();
    

一部のユースケースでは、構成オプションに加えて、ユースケースの作成後に設定を動的に変更する API も公開されています。 個々のユースケースに固有の構成については、プレビューを実装する画像を解析する画像キャプチャをご覧ください。

自動選択

CameraX は、アプリが実行されているデバイスに固有の機能を自動的に提供します。たとえば、解像度が指定されていない場合や、指定された解像度がサポートされていない場合、使用する最適な解像度を自動的に決定します。これらはすべてライブラリによって処理されるため、デバイス固有のコードを記述する必要はありません。

CameraX の目標は、カメラ セッションを正常に初期化することです。そのために、CameraX はデバイス機能に基づいて解像度とアスペクト比を低下させることがあります。これは、次の理由で発生する可能性があります。

  • デバイスが要求される解像度をサポートしていません。
  • デバイスに互換性の問題があります。たとえば、古いデバイスの中には、正常に動作するために特定の解像度を必要とするものがあります。
  • 一部のデバイスでは、特定のアスペクト比でのみ使用可能な特定の形式があります。
  • デバイスでは、JPEG または動画エンコードについて「mod16 に最も近い」値が優先されます。詳しくは、SCALER_STREAM_CONFIGURATION_MAP をご覧ください。

CameraX はセッションを作成して管理しますが、コードのユースケース出力で返される画像サイズを常に確認し、それに応じて調整する必要があります。

回転

カメラの回転はデフォルトでは、ユースケースの作成時にデフォルトのディスプレイの回転と一致するように設定されます。このデフォルトのケースでは、CameraX は、ユーザーが期待する画像をアプリのプレビューで簡単に作成できるように出力を生成します。マルチディスプレイ デバイスに対応するため、回転をカスタム値に変更できます。そのためには、ユースケース オブジェクトの構成時に、またはユースケース オブジェクトの作成後に動的に、現在のディスプレイの向きを渡します。

アプリは、構成設定を使用してターゲットの回転を設定できます。その後、ライフサイクルが実行状態であっても、ユースケース API のメソッド(ImageAnalysis.setTargetRotation() など)を使用して回転設定を更新できます。この方法は、アプリが縦向きにロックされている(そのため、回転時に再構成が行われない)場合に使用できます。ただし、写真または解析ユースケースがデバイスの現在の回転を認識できることが必要です。たとえば、顔の向きを正しく検出する場合や、写真を横向きまたは縦向きに設定する場合は、回転の認識が必要になります。

キャプチャした画像のデータは、回転情報なしで保存されることがあります。EXIF データには回転情報が含まれるため、保存後にギャラリー アプリは画像を正しい向きで表示できます。

プレビュー データを正しい向きで表示するには、Preview.PreviewOutput() のメタデータ出力を使用して変換を作成します。

次のコードサンプルは、向きのイベントで回転を設定する方法を示しています。

Kotlin

    override fun onCreate() {
        val imageCapture = ImageCapture.Builder().build()

        val orientationEventListener = object : OrientationEventListener(this as Context) {
            override fun onOrientationChanged(orientation : Int) {
                // Monitors orientation values to determine the target rotation value
                val rotation : Int = when (orientation) {
                    in 45..134 -> Surface.ROTATION_270
                    in 135..224 -> Surface.ROTATION_180
                    in 225..314 -> Surface.ROTATION_90
                    else -> Surface.ROTATION_0
                }

                imageCapture.targetRotation = rotation
            }
        }
        orientationEventListener.enable()
    }
    

Java

    @Override
    public void onCreate() {
        ImageCapture imageCapture = new ImageCapture.Builder().build();

        OrientationEventListener orientationEventListener = new OrientationEventListener((Context)this) {
           @Override
           public void onOrientationChanged(int orientation) {
               int rotation;

               // Monitors orientation values to determine the target rotation value
               if (orientation >= 45 && orientation < 135) {
                   rotation = Surface.ROTATION_270;
               } else if (orientation >= 135 && orientation < 225) {
                   rotation = Surface.ROTATION_180;
               } else if (orientation >= 225 && orientation < 315) {
                   rotation = Surface.ROTATION_90;
               } else {
                   rotation = Surface.ROTATION_0;
               }

               imageCapture.setTargetRotation(rotation);
           }
        };

        orientationEventListener.enable();
    }
    

以下の各ユースケースは、設定された回転に基づいて、画像データを直接回転させるか、または回転されていない画像データの回転メタデータをユーザーに提供します。

  • Preview: Preview.getTargetRotation() によりターゲット解像度の回転を認識できるようなメタデータ出力が提供されます。
  • ImageAnalysis: 画像バッファ座標と表示座標の相対関係を認識できるようなメタデータ出力が提供されます。
  • ImageCapture: 画像の EXIF メタデータまたはバッファ、あるいはメタデータとバッファの両方が変更され、回転設定が記録されます。変更される値は HAL 実装によって異なります。

カメラの解像度

デバイスの機能、デバイスがサポートするハードウェア レベル、ユースケース、指定されたアスペクト比の組み合わせに基づいて CameraX が画像解像度を設定するように選択できます。または、特定のターゲット解像度または特定のアスペクト比を、その構成をサポートするユースケースに設定することもできます。

自動解像度

CameraX は、cameraProcessProvider.bindToLifecycle() で指定されたユースケースに基づいて最適な解像度設定を自動的に決定します。可能であれば、1 回の bindToLifecycle() 呼び出しの 1 つのセッションで同時に実行するために必要なすべてのユースケースを指定してください。CameraX は、デバイスがサポートするハードウェア レベルや、デバイスの特徴(デバイスが使用可能なストリーム構成の限度を超えているか対応していない場合があります)を考慮して、バインドされているユースケースのセットに基づいて解像度を決定します。これは、デバイス固有のコードパスを最小限に抑えつつ、アプリをさまざまなデバイスで実行できるようにするためです。

画像キャプチャ ユースケースと画像解析ユースケースのデフォルトのアスペクト比は 4:3 です。

UI の設計に基づいてアプリで目的のアスペクト比を指定できるようにするために、ユースケースでアスペクト比を設定できるようになっています。CameraX の出力は、リクエストされたアスペクト比とデバイスがサポートするアスペクト比ができる限り一致するように生成されます。完全に一致する解像度がサポートされていない場合、条件に最も近い解像度が選択されます。このようにして、アプリは、アプリ内におけるカメラのアスペクト比を決定し、CameraX は、各デバイスでそのアスペクト比に適合する最適なカメラ解像度設定を決定します。

たとえば、アプリは以下の操作をいずれも実行できます。

  • ユースケースのターゲット解像度を 4:3 または 16:9 に指定する
  • カスタム解像度を指定する(CameraX はこれに最も近い解像度を探します)
  • ImageCapture の切り抜きのアスペクト比を指定する

CameraX は内部の Camera2 サーフェス解像度を自動的に選択します。次の表にその解像度を示します。

ユースケース 内部のサーフェス解像度 出力データの解像度
プレビュー アスペクト比: 設定目標に最も適合する解像度。 内部のサーフェス解像度。ターゲット アスペクト比に合わせて、クロップ、サイズ変更、回転をビューが行えるようなメタデータが提供されます。
デフォルトの解像度: プレビューの最大解像度、または上記のアスペクト比に適合するデバイス推奨の最大解像度。
最大解像度: プレビュー サイズ。つまり、デバイスの画面解像度に最適なサイズまたは 1080p(1920x1080)のいずれか小さいほうのサイズ。
画像解析 アスペクト比: 設定目標に最も適合する解像度。 内部のサーフェス解像度。
デフォルトの解像度: ターゲット解像度のデフォルト設定は 640x480 です。ターゲット解像度と、対応するアスペクト比の両方を調整することで、1080p 未満のサポートされる最適な解像度に設定されます。
最大解像度: CameraX によって 1080p に制限されています。ターゲット解像度はデフォルトで 640x480 に設定されているため、640x480 より大きい解像度が必要な場合は、setTargetResolutionsetTargetAspectRatio を使用して、サポートされている解像度の中から最も近いものを選択します。
画像キャプチャ アスペクト比: 設定に最も適合するアスペクト比。 内部のサーフェス解像度。
デフォルトの解像度: 使用可能な最大解像度、または上記のアスペクト比に適合するデバイス推奨の最大解像度。
最大解像度: JPEG 形式に対するカメラデバイスの最大出力解像度(StreamConfigurationMap.getOutputSizes

解像度を指定する

次のコードサンプルに示すように、ユースケースをビルドする際に setTargetResolution(Size resolution) メソッドを使用して特定の解像度を設定できます。

Kotlin

    val imageAnalysis = ImageAnalysis.Builder()
        .setTargetResolution(Size(1280, 720))
        .build()
    

Java

    ImageAnalysis imageAnalysis =
      new ImageAnalysis.Builder()
        .setTargetResolution(new Size(1280, 720))
        .build();
    

指定した解像度に基づいて、具体的なターゲット アスペクト比を設定できます。ターゲット アスペクト比は解像度の選択に影響を及ぼします。ターゲット解像度に適合するターゲット アスペクト比を設定することにより、解像度が選択されます。解像度の選択では、デバイスの機能や他にアタッチされているユースケースが考慮されます。

リクエストとまったく同じ解像度とアスペクト比を設定できない場合は、リクエストより大きい解像度で最も近いものが選択されます。選択できる解像度がない場合は、640x480 に戻されます。

CameraX はリクエストに基づいて最適な解像度を適用します。アスペクト比の要件を満たすことが最も重要である場合は、setTargetAspectRatio のみを指定します。CameraX は、デバイスに応じた適切な解像度を決定します。アプリの画像処理を効率化することが最も重要で、そのために解像度を指定する必要がある場合(たとえば、デバイスの処理能力に応じて小規模または中規模サイズの画像を使用する場合)は、setTargetResolution(Size resolution) を使用します。

アプリで正確な解像度が必要な場合は、createCaptureSession の表で、各ハードウェア レベルでサポートされている最大解像度を確認してください。現行のデバイスでサポートされている解像度を確認するには、StreamConfigurationMap.getOutputSizes(int) をご覧ください。

Android 10 以上でアプリを実行している場合は、isSessionConfigurationSupported を使用して特定の SessionConfiguration を確認できます。

フォーカスの制御

CameraControl API は「タップしてフォーカス」機能を提供します。まず、次のコードに示すように、CameraControl オブジェクトを取得します。

Kotlin

    val camera = processCameraProvider.bindToLifecycle(...)
    val cameraControl = camera.getCameraControl()
    

Java

    Camera camera = processCameraProvider.bindToLifecycle(...);
    CameraControl cameraControl = camera.getCameraControl();
    

タップしてフォーカスを実行するには、MeteringPointFactoryMeteringPointMeteringModeFocusMeteringAction を次のように使用します。

Kotlin

    val factory = SurfaceOrientedMeteringPointFactory(width, height)
    val point = factory.createPoint(x, y)
    val action = FocusMeteringAction.Builder(point, FocusMeteringAction.FLAG_AF)
        .addPoint(point2, FocusMeteringAction.FLAG_AE) // could have many
        // auto calling cancelFocusAndMetering in 5 seconds
        .setAutoCancelDuration(5, TimeUnit.SECONDS)
        .build()

    val future = cameraControl.startFocusAndMetering(action)
    future.addListener( Runnable {
        val result = future.get()
        // process the result
    } , executor)
    

Java

    MeteringPointFactory factory = new SurfaceOrientedMeteringPointFactory(width, height);
    MeteringPoint point = factory.createPoint(x, y);
    FocusMeteringAction action = new FocusMeteringAction.Builder(point, FocusMeteringAction.FLAG_AF)
            .addPoint(point2, FocusMeteringAction.FLAG_AE) // could have many
            // auto calling cancelFocusAndMetering in 5 seconds
            .setAutoCancelDuration(5, TimeUnit.SECONDS)
            .build();

    ListenableFuture future = cameraControl.startFocusAndMetering(action)
    future.addListener( () -> {
        try {
            FocusMeteringResult result = future.get();
            // process the result
        } catch (Exception e) {
        }
    } , executor);
    

参考情報

CameraX について詳しくは、以下の参考情報をご確認ください。

コードラボ

  • CameraX のスタートガイド
  • コードサンプル

  • CameraX の公式サンプルアプリ
  • デベロッパー コミュニティ

    Android CameraX ディスカッション グループ