구성 옵션

각 CameraX 사용 사례를 구성하여 사용 사례 작업의 여러 측면을 제어할 수 있습니다.

예를 들어 이미지 캡처 사용 사례에서는 타겟 가로세로 비율과 플래시 모드를 설정할 수 있습니다. 다음 코드가 한 가지 예입니다.

Kotlin

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

자바

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

어떤 사용 사례에서는 구성 옵션 외에도 사용 사례 작성 후 설정을 동적으로 변경하기 위해 API를 노출합니다. 개별 사용 사례에 적용되는 구성에 관한 정보는 미리보기 구현, 이미지 분석이미지 캡처를 참조하세요.

자동 선택

CameraX는 앱이 실행되는 기기에 적합한 기능을 자동으로 제공합니다. 예를 들어 CameraX는 해상도를 지정하지 않거나 지정한 해상도가 지원되지 않는 경우 사용할 최적의 해상도를 자동으로 결정합니다. 이 모든 작업은 라이브러리에서 처리되므로 기기별 코드를 작성할 필요가 없습니다.

CameraX의 목표는 카메라 세션을 성공적으로 초기화하는 것입니다. 즉, CameraX는 기기 기능에 따라 해상도 및 가로세로 비율을 절충합니다. 이러한 절충은 다음과 같은 이유로 발생할 수 있습니다.

  • 요청된 해상도를 기기에서 지원하지 않습니다.
  • 올바르게 작동하려면 특정 해상도가 필요한 레거시 기기와 같이 기기에 호환성 문제가 있습니다.
  • 특정 형식을 특정 가로세로 비율에서만 사용할 수 있는 기기가 있습니다.
  • 기기에서 JPEG 또는 동영상 인코딩의 경우 'nearest 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()
}

자바

@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 구현에 따라 다릅니다.

자르기 rect

기본적으로 자르기 rect는 전체 버퍼 rect입니다. ViewPortUseCaseGroup을 사용하여 이를 맞춤설정할 수 있습니다. CameraX는 사용 사례를 그룹화하고 표시 영역을 설정하여 그룹 내 모든 사용 사례의 자르기 rect가 카메라 센서의 동일한 영역을 가리키게 합니다.

다음 코드 스니펫은 이 두 가지 클래스를 사용하는 방법을 보여줍니다.

Kotlin

val viewPort =  ViewPort.Builder(Rational(width, height), display.rotation).build()
val useCaseGroup = UseCaseGroup.Builder()
    .addUseCase(preview)
    .addUseCase(imageAnalysis)
    .addUseCase(imageCapture)
    .setViewPort(viewPort)
    .build()
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup)

자바

ViewPort viewPort = new ViewPort.Builder(
         new Rational(width, height),
         getDisplay().getRotation()).build();
UseCaseGroup useCaseGroup = new UseCaseGroup.Builder()
    .addUseCase(preview)
    .addUseCase(imageAnalysis)
    .addUseCase(imageCapture)
    .setViewPort(viewPort)
    .build();
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup);

ViewPort는 최종 사용자에게 표시되는 버퍼 rect를 정의합니다. 그런 다음 CameraX는 표시 영역의 속성과 연결된 사용 사례를 기반으로 최대한 큰 자르기 rect를 계산합니다. 일반적으로 WYSIWYG 효과를 얻으려면 미리보기 사용 사례에 따라 표시 영역을 구성해야 합니다. 표시 영역을 구성하는 간단한 방법은 PreviewView를 사용하는 것입니다.

다음 코드 스니펫은 ViewPort 객체를 가져오는 방법을 보여줍니다.

Kotlin

val viewport = findViewById<PreviewView>(R.id.preview_view).viewPort

자바

ViewPort viewPort = ((PreviewView)findViewById(R.id.preview_view)).getViewPort();

앞의 예에서 PreviewView의 조정 유형이 기본값(FILL_CENTER)으로 설정되었다고 가정하면 앱이 ImageAnalysisImageCapture에서 가져오는 것이 PreviewView에 최종 사용자에게 표시되는 것과 일치합니다. 자르기 rect 및 회전을 출력 버퍼에 적용하면 모든 사용 사례의 이미지는 동일하지만 해상도가 다를 수 있습니다. 변환 정보를 적용하는 방법에 관한 자세한 내용은 출력 변환을 참고하세요.

카메라 해상도

기기 기능, 기기의 지원되는 하드웨어 수준, 사용 사례 및 제공된 가로세로 비율의 조합을 바탕으로 CameraX가 이미지 해상도를 설정하도록 선택할 수 있습니다. 또는 해당 구성을 지원하는 사용 사례에 특정 타겟 해상도 또는 특정 가로세로 비율을 설정할 수 있습니다.

자동 해상도

CameraX는 cameraProcessProvider.bindToLifecycle()에 지정된 사용 사례를 바탕으로 최적의 해상도 설정을 자동으로 결정할 수 있습니다. 가능한 한 단일 bindToLifecycle() 호출로 단일 세션에서 동시에 실행하는 데 필요한 모든 사용 사례를 지정하세요. CameraX는 기기의 지원되는 하드웨어 수준과 기기별 변동(기기가 사용 가능한 스트림 구성을 충족 또는 충족하지 않는지 여부)을 고려하여 결합된 사용 사례 집합을 바탕으로 해상도를 결정합니다. 애플리케이션이 다양한 기기에서 실행되도록 하면서 기기별 코드 경로를 최소화하는 것이 목적입니다.

이미지 캡처 및 이미지 분석 사용 사례의 기본 가로세로 비율은 4:3입니다.

사용 사례에는 애플리케이션이 UI 디자인에 따라 원하는 가로세로 비율을 지정할 수 있게 하는 구성 가능한 가로세로 비율이 있습니다. 기기에서 지원하는 비율에 최대한 가깝게 요청된 가로세로 비율과 일치하도록 CameraX 출력이 생성됩니다. 정확히 일치하는 지원 해상도가 없는 경우 가장 많은 조건을 충족하는 해상도가 선택됩니다. 따라서 애플리케이션이 앱에서 카메라가 표시되는 방식을 지정하고, CameraX는 여러 기기에서 이 조건을 충족하기 위한 최적의 카메라 해상도 설정을 선택합니다.

예를 들어 앱에서 할 수 있는 작업은 다음과 같습니다.

  • 사용 사례의 타겟 해상도를 4:3 또는 16:9로 지정
  • 맞춤 해상도 지정. CameraX가 그에 가장 근접한 값을 찾으려고 시도함
  • ImageCapture의 자르기 가로세로 비율 지정

CameraX는 자동으로 내부 Camera2 표면 해상도를 선택합니다. 다음 표에서는 해상도를 보여줍니다.

사용 사례 내부 표면 해상도 출력 데이터 해상도
미리보기 가로세로 비율: 설정에 가장 잘 맞는 해상도 내부 표면 해상도 View에서 타겟 가로세로 비율에 따라 자르고 조정하고 회전할 수 있도록 메타데이터가 제공됩니다.
기본 해상도: 가장 높은 미리보기 해상도 또는 위의 가로세로 비율과 일치하는 가장 높은 기기 최적 해상도
최대 해상도: 미리보기 크기로, 기기의 화면 해상도에 맞는 최적의 크기 또는 1080p(1920x1080) 중 더 작은 크기
이미지 분석 가로세로 비율: 설정에 가장 잘 맞는 해상도 내부 표면 해상도
기본 해상도: 기본 타겟 해상도 설정은 640x480입니다. 타겟 해상도와 이에 해당하는 가로세로 비율을 모두 조정하면 가장 잘 지원되는 해상도로 설정됩니다.
최대 해상도: StreamConfigurationMap.getOutputSizes()에서 가져온 카메라 기기의 YUV_420_888 형식 최대 출력 해상도. 타겟 해상도는 기본적으로 640x480으로 설정되므로 640x480보다 큰 해상도를 원하는 경우 setTargetResolution()setTargetAspectRatio()를 사용하여 지원되는 해상도 중 가장 가까운 해상도를 가져와야 합니다.
이미지 캡처 가로세로 비율: 설정에 가장 잘 맞는 가로세로 비율 내부 표면 해상도
기본 해상도: 사용 가능한 가장 높은 해상도 또는 위의 가로세로 비율과 일치하는 가장 높은 기기 최적 해상도
최대 해상도: 카메라 기기의 최대 출력 해상도(JPEG 형식). StreamConfigurationMap.getOutputSizes()를 사용하여 가져올 수 있습니다.

해상도 지정

다음 코드 샘플에서와 같이 setTargetResolution(Size resolution) 메서드를 사용하여 사용 사례를 빌드할 때 특정 해상도를 설정할 수 있습니다.

Kotlin

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

자바

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

동일한 사용 사례에 타겟 가로세로 비율과 타겟 해상도를 모두 설정할 수는 없습니다. 그렇게 하면 config 객체를 빌드할 때 IllegalArgumentException이 발생합니다.

지원되는 크기를 타겟 회전으로 회전한 후 좌표계에서 해상도 Size를 지정합니다. 예를 들어 자연스러운 세로 방향을 갖는 기기가 자연스러운 타겟 회전에서 세로 이미지를 요청하는 경우 480x640을 지정할 수 있습니다. 동일한 기기가 90도 회전하고 가로 방향을 타겟팅하는 경우에는 640x480을 지정할 수 있습니다.

타겟 해상도는 이미지 해상도에 최소 범위를 설정하려고 합니다. 실제 이미지 해상도의 크기는 사용 가능한 해상도 중 가장 근접한 해상도이며, 이 크기는 카메라 구현에 의해 결정되는 타겟 해상도보다 작지 않습니다. 하지만 타겟 해상도와 같거나 그보다 큰 해상도가 없으면 타겟 해상도보다 작은 사용 가능한 해상도 가운데 가장 근접한 해상도가 선택됩니다. 제공된 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()

자바

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

탭하여 포커스 맞추기를 실행하려면 MeteringPointFactory, MeteringPoint, MeteringMode, FocusMeteringAction을 사용합니다.

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)

자바

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 토론방