Google 致力于为黑人社区推动种族平等。查看具体举措

配置选项

您可以配置每个 CameraX 用例,以控制用例操作的不同方面。

例如,对于图片拍摄用例,您可以设置目标宽高比和闪光灯模式。以下代码显示了一个示例:

Kotlin

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

Java

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

除配置选项之外,一些用例会公开 API 以便在创建后动态更改设置。如需了解各个用例的专属配置,请参阅实现预览分析图片图片拍摄

自动选择

CameraX 会根据运行您的应用的设备自动提供专用的功能。例如,如果您未指定分辨率或指定的分辨率不受支持,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() 中指定的用例自动确定最佳分辨率设置。请尽可能在单个 bindToLifecycle() 调用的单个会话中指定需要同时运行的所有用例。CameraX 会考虑设备支持的硬件级别以及设备专属变化(设备可能会超出或不满足可用的信息流配置),根据绑定的一组用例确定分辨率。这样做的目的是使应用可在各种设备上运行,同时最大限度地减少设备专属代码路径。

图片拍摄和图片分析用例的默认宽高比为 4:3。

用例具有一个可配置的宽高比,让应用可以根据界面设计指定所需的宽高比。CameraX 输出将会生成,以尽可能匹配设备支持的所请求宽高比。如果没有任何支持的完全匹配分辨率,则选择满足最多条件的分辨率。因此,应用决定了相机应如何在应用中显示,CameraX 则会确定最佳相机分辨率设置,以在不同设备上满足这一要求。

例如,应用可以执行以下任一操作:

  • 为用例指定 4:3 或 16:9 的目标分辨率
  • 指定自定义分辨率,CameraX 将尝试查找与其最接近的匹配项
  • ImageCapture 指定剪裁宽高比

CameraX 会自动选择内部 Camera2 界面分辨率。下表显示了这些分辨率:

用例 内部界面分辨率 输出数据分辨率
预览 宽高比:使目标与设置最相符的分辨率。 内部界面分辨率。提供元数据以允许 View 针对目标宽高比进行剪裁、缩放和旋转。
默认分辨率:最高预览分辨率,或与上述宽高比匹配的最高设备首选分辨率。
最大分辨率:预览大小,指的是与设备的屏幕分辨率或 1080p (1920x1080)(以较低者为准)匹配的最佳尺寸。
图片分析 宽高比:使目标与设置最相符的分辨率。 内部界面分辨率。
默认分辨率:默认目标分辨率设置为 640x480。同时调整目标分辨率和相应的宽高比会导致支持的最佳分辨率低于 1080p。
最大分辨率:CameraX 将其限制为 1080p。目标分辨率默认设置为 640x480;因此,如果您希望分辨率大于 640x480,必须使用 setTargetResolutionsetTargetAspectRatio 从支持的分辨率中选择最接近的一个。
图片拍摄 宽高比:最适合设置的宽高比。 内部界面分辨率。
默认分辨率:最高可用分辨率,或与上述宽高比匹配的最高设备首选分辨率。
最大分辨率StreamConfigurationMap.getOutputSizes 中 JPEG 格式的相机设备的最大输出分辨率

指定分辨率

使用 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();

您不能对同一个用例同时设置目标宽高比和目标分辨率。这样做会在构建配置对象时抛出 IllegalArgumentException

按照目标旋转角度旋转支持的大小后,请在坐标系中表示分辨率 Size。例如,自然屏幕方向为纵向并采用自然目标旋转角度的设备如果请求纵向图片,可指定 480x640;而同一设备旋转 90 度并以横向屏幕方向为目标后,可指定 640x480。

您可以为 ImageAnalysis 选择的最大可用分辨率为 1080p。对 ImageAnalysis 做出 1080p 的限制同时考虑了性能和画质两方面的因素,以便让用户获得合理的画质和流畅的输出流。

目标分辨率会尝试制定图片分辨率的下限。实际的图片分辨率是最接近的可用分辨率,其大小不小于相机实现确定的目标分辨率。但是,如果不存在等于或大于目标分辨率的分辨率,就会从小于目标分辨率的可用分辨率中选择最接近的一个。与提供的 Size 具有相同宽高比的分辨率,其优先级高于具有不同宽高比的分辨率。

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,请参阅下面列出的其他资源。

Codelab

  • CameraX 使用入门
  • 代码示例

  • 官方 CameraX 示例应用
  • 开发者社区

    Android CameraX 论坛