設定選項

CameraX 所有用途都能進行選項設定,用來控制用途各個面向的操作。

舉例來說,開發人員可以設定拍照用途的目標長寬比和閃光燈模式。詳情請參閱以下程式碼範例:

Kotlin

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

Java

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

建立用途後,除了設定選項之外,某些用途也能提供 API,用來動態變更設定。如需個別用途的特定設定資訊,請參閱「導入預覽畫面」「分析圖片」以及「拍照」

CameraXConfig

CameraX 內部執行程式和處理常式已有預設設定,可輕鬆支援大部分的使用情境。不過,開發人員如有特殊需求,或想自訂這類設定,可使用 CameraXConfig 介面。

透過 CameraXConfig 可執行以下操作:

拍攝模式

如要瞭解如何使用 CameraXConfig,請參閱以下程序說明:

  1. 使用自訂設定來建立 CameraXConfig 物件。
  2. Application 中實作 CameraXConfig.Provider 介面,並在 getCameraXConfig() 中傳回 CameraXConfig 物件。
  3. 請根據此處說明,在 AndroidManifest.xml 檔案新增 Application 類別。

如要 CameraX 只記錄錯誤訊息,請參閱下列程式碼範例:

Kotlin

class CameraApplication : Application(), CameraXConfig.Provider {
   override fun getCameraXConfig(): CameraXConfig {
       return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig())
           .setMinimumLoggingLevel(Log.ERROR).build()
   }
}

如果應用程式需要知道 CameraX 設定,請在完成設定後,於本機保留一份 CameraXConfig 物件副本。

相機限制器

首次叫用 ProcessCameraProvider.getInstance() 時,CameraX 會列舉並查詢裝置相機的可用用途。由於 CameraX 需要與硬體元件進行通訊,只要是相機都需要不少時間才能完成,尤其低階裝置更是如此。如果應用程式僅使用裝置上的特定鏡頭 (例如預設前置鏡頭),您可以將 CameraX 設為忽略其他鏡頭,藉此縮短應用程式所用相機的啟動延遲時間。

只要將 CameraSelector 傳至 CameraXConfig.Builder.setAvailableCamerasLimiter(),以篩除某個鏡頭,CameraX 就會忽略它。如要限制應用程式僅使用裝置的預設後置鏡頭,請參閱以下程式碼範例:

Kotlin

class MainApplication : Application(), CameraXConfig.Provider {
   override fun getCameraXConfig(): CameraXConfig {
       return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig())
              .setAvailableCamerasLimiter(CameraSelector.DEFAULT_BACK_CAMERA)
              .build()
   }
}

會話串

許多建構 CameraX 的平台 API 都需要封鎖與硬體之間的處理序間通訊 (IPC),而這類通訊有時可能需要數百毫秒的回應時間。因此,CameraX 只從背景執行緒呼叫這些 API,進而保障主要執行緒不會遭到封鎖,同時使用者介面也能順暢運作。為了讓這類通訊保持透明,CameraX 只會在內部管理這些背景會話串。不過,部分應用程式需要嚴格控管會話串。CameraXConfig 讓應用程式可透過 CameraXConfig.Builder.setCameraExecutor()CameraXConfig.Builder.setSchedulerHandler() 設定會用到的背景會話串。

相機執行程式

相機執行程式適用於所有內部 Camera Platform API 呼叫及回呼。CameraX 負責分配和管理內部 Executor,以執行這些工作。如有需要,使用 CameraXConfig.Builder.setCameraExecutor() 可執行更嚴格的執行緒控管。

排程器處理常式

排程器處理常式以固定時間間隔排定內部工作,例如在相機無法使用時進行重試。這個處理常式不執行工作,只會分派工作給相機執行程式。有時舊版 API 會使用 Handler 進行回呼。這種情況,回呼就會直接派給相機執行程式。CameraX 負責分配和管理內部 HandlerThread 以執行這些工作,但開發人員也可以使用 CameraXConfig.Builder.setSchedulerHandler() 覆寫 CameraX 的工作。

記錄

為了避免在實際工作環境程式碼中產生詳細訊息,最佳做法是透過 CameraX 記錄,讓應用程式過濾 Logcat 訊息。CameraX 依據最詳細到最嚴重的區別,提供四個記錄等級:

  • Log.DEBUG (預設)
  • Log.INFO
  • Log.WARN
  • Log.ERROR

如需這些記錄層級的詳細說明,請參閱「Android 記錄說明文件」。請使用 CameraXConfig.Builder.setMinimumLoggingLevel(int) 為應用程式設定適當的記錄等級。

自動選取

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.getTargetRotation() 得知目標解析度的旋轉設定。
  • ImageAnalysis:提供中繼資料輸出,以得知對應螢幕座標的圖片緩衝區座標。
  • ImageCapture:應用程式會擇一修改圖片的 Exif 中繼資料或緩衝區資料,或兩者皆修改,進而顯示旋轉設定。修改值取決於 HAL 實作。

矩形裁剪

根據預設,矩形裁剪即為完整的緩衝區矩形。只要使用 ViewPortUseCaseGroup 設定,開發人員可以自訂這項用途。將用途分組並設定可視區域後,CameraX 即可確保群組中所有用途的矩形裁剪均指向相機感應器的相同區域。

要瞭解如何使用這兩個類別,請參閱下列程式碼範例:

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)

Java

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 會定義向使用者顯示的緩衝矩形。然後 CameraX 會根據可視區域的屬性和附加用途,計算最大可裁剪的矩形。如要達到所見即所得效果,請根據預覽用途設定可視區域。使用 PreviewView,即可輕鬆取得可視區域。

如要取得 ViewPort 物件,請參閱以下程式碼範例:

Kotlin

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

Java

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

上述範例假設 PreviewView 調整類型預設設定為 FILL_CENTER,所以應用程式從 ImageAnalysisImageCapture 取得的資料,與使用者在 PreviewView 看到的畫面一致。在輸出緩衝區套用裁剪矩形和旋轉用途,所有用途的圖片會同步,但解析度可能不同。如要進一步瞭解如何套用轉換,請參閱「轉換輸出」

相機選項

CameraX 會自動選擇最符合需求的鏡頭,以滿足應用程式的需求和用途。如果您想使用不同於 CameraX 預選的鏡頭,可以採取下列做法:

要瞭解如何建立 CameraSelector 來影響裝置選擇,請見以下程式碼範例說明:

Kotlin

fun selectExternalOrBestCamera(provider: ProcessCameraProvider):CameraSelector? {
   val cam2Infos = provider.availableCameraInfos.map {
       Camera2CameraInfo.from(it)
   }.sortedByDescending {
       // HARDWARE_LEVEL is Int type, with the order of:
       // LEGACY < LIMITED < FULL < LEVEL_3 < EXTERNAL
       it.getCameraCharacteristic(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)
   }

   return when {
       cam2Infos.isNotEmpty() -> {
           CameraSelector.Builder()
               .addCameraFilter {
                   it.filter { camInfo ->
                       // cam2Infos[0] is either EXTERNAL or best built-in camera
                       val thisCamId = Camera2CameraInfo.from(camInfo).cameraId
                       thisCamId == cam2Infos[0].cameraId
                   }
               }.build()
       }
       else -> null
    }
}

// create a CameraSelector for the USB camera (or highest level internal camera)
val selector = selectExternalOrBestCamera(processCameraProvider)
processCameraProvider.bindToLifecycle(this, selector, preview, analysis)

相機解析度

您可以選擇讓 CameraX 根據裝置功能、支援的硬體等級、用途和提供的長寬比來設定圖片解析度。或者在支援該設定的用途中,設置特定目標解析度或長寬比。

自動解析度

根據 cameraProcessProvider.bindToLifecycle() 的指定用途,CameraX 即可自動判斷最佳解析度設定。在單一 bindToLifecycle() 呼叫的單一工作階段中,請盡可能指定需同時執行的全部用途。CameraX 會考量裝置支援的硬體等級,和所涵蓋的裝置專屬變異數 (裝置可能超過或不符合可用的串流設定),並根據用途組合來決定解析度。這麼做是為了讓應用程式能在各種裝置上運作,同時盡量減少裝置專屬的程式碼路徑。

圖片拍攝和圖片分析用途的預設長寬比為 4:3。

用途提供可設定的長寬比,讓應用程式能依據 UI 設計指定所需比例。CameraX 的輸出內容會盡可能配合裝置所支援的顯示比例。如果無法完全配合,則系統會選取最能滿足所選條件的解析度。因此,應用程式會指定相機在應用程式中的顯示方式,而 CameraX 則會判斷最佳的相機解析度設定,以符合不同裝置的需求。

舉例來說,應用程式可以執行下列任一操作:

  • 根據用途指定 4:3 或 16:9 的目標解析度
  • 指定自訂解析度,CameraX 會找出最符合的項目
  • 指定 ImageCapture 的裁剪長寬比

CameraX 會自動選擇內部的 Camera2 途徑解析度。下表列出所有解析度:

用途 內部介面解析度 輸出資料解析度
預覽 長寬比:讓目標符合設定的最佳解析度。 內部介面解析度使用提供的中繼資料,讓「檢視畫面」可根據目標長寬比進行裁剪、縮放及旋轉。
預設解析度:為最高預覽解析度,或符合上述最大長寬比的裝置慣用解析度。
最大解析度:為預覽尺寸,指的是符合裝置螢幕解析度或 1080p (1920x1080) 的最佳尺寸,以較小者為準。
圖片分析 長寬比:讓目標符合設定的最佳解析度。 內部介面解析度。
預設解析度:預設的目標解析度設定為 640x480。同時調整目標解析度和對應的長寬比,即可得出支援效果最佳的解析度。
最大解析度:相機裝置輸出的最大解析度,為 YUV_420_888 格式 (擷取自 StreamConfigurationMap.getOutputSizes())。目標解析度預設為 640x480,因此如需大於預設的解析度,就必須使用 setTargetResolution()setTargetAspectRatio(),以取得最接近的支援解析度。
相片拍攝 長寬比:最符合設定的長寬比。 內部介面解析度。
預設解析度:為最高解析度,或符合上述長寬比的裝置慣用解析度。
最高解析度:相機裝置的最大輸出解析度 (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();

請勿同時針對同一用途設定目標長寬比和目標解析度。這樣做會導致建立設定物件時,擲回 IllegalArgumentException

根據目標旋轉角度旋轉支援的大小後,請在座標架構中表示解析度 Size。舉例來說,如果裝置的自然螢幕方向為直向,並且採用自然目標旋轉角度,便可在要求直向圖片時指定 480x640 解析度;而相同的裝置旋轉 90 度並以橫向螢幕方向為目標時,則可指定 640x480。

目標解析度會設立圖片解析度的下限。實際圖片解析度將是最接近目標的可用解析度,其大小取決於相機的實作情形。不過,如果沒有可用解析度等於或大於目標解析度,就會選擇小於目標的最接近可用解析度。Size 的相同長寬比解析度會優於長寬比不同的解析度。

CameraX 會根據要求套用最合適的解析度。如果主需求是滿足長寬比,則只需指定 setTargetAspectRatio,CameraX 就會根據裝置選擇適合的解析度。如果應用程式主需求是為了提高圖片處理效率才指定解析度,比如根據裝置處理能力來處理小型或中型圖片,這種情形則使用 setTargetResolution(Size resolution)

如果應用程式需要確切解析度,請參閱 createCaptureSession() 中的資料表,以判斷各個硬體層級所支援的最高解析度。如要查看目前裝置所支援的特定解析度,請參閱 StreamConfigurationMap.getOutputSizes(int) 一文。

如果應用程式是在 Android 10 或以上版本中運作,即可透過 isSessionConfigurationSupported() 驗證特定的 SessionConfiguration

控制相機輸出內容

除了依個別用途的需求來設定相機輸出內容,CameraX 還能實作以下介面,以便支援所有繫結用途共用的相機作業:

以下是 CameraControl 支援的相機用途:

  • 變焦
  • 手電筒
  • 對焦和測光 (觸控對焦)
  • 曝光補償

取得 CameraControl 和 CameraInfo 的執行個體

使用 ProcessCameraProvider.bindToLifecyle() 傳回的 Camera 物件,並擷取 CameraControlCameraInfo 執行個體。詳情請見以下程式碼範例:

Kotlin

val camera = processCameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)

// For performing operations that affect all outputs.
val cameraControl = camera.cameraControl
// For querying information and states.
val cameraInfo = camera.cameraInfo

Java

Camera camera = processCameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)

// For performing operations that affect all outputs.
CameraControl cameraControl = camera.getCameraControl()
// For querying information and states.
CameraInfo cameraInfo = camera.getCameraInfo()

舉例來說,只要呼叫 bindToLifecycle(),就可以進行變焦和其他 CameraControl 操作。停用或刪除用於繫結相機例項的活動之後,CameraControl 就無法繼續執行作業,並且會傳回失敗的 ListenableFuture

變焦

CameraControl 提供兩個可以更改變焦等級的方法如下:

  • setZoomRatio() 會根據縮放比例設定變焦。

    比例必須介於 CameraInfo.getZoomState().getValue().getMinZoomRatio()CameraInfo.getZoomState().getValue().getMaxZoomRatio() 之間。否則,函式會傳回失敗的 ListenableFuture

  • setLinearZoom() 可使用 0 到 1.0 的線性變焦值,來設定目前的縮放比例。

    線性變焦的優點在於能保證視野 (FOV) 會隨著變焦改變而縮放。因此非常適合用於 Slider 檢視畫面。

CameraInfo.getZoomState() 會傳回目前變焦狀態的 LiveData。在相機初始化或變焦等級設為 setZoomRatio()setLinearZoom() 時,則該值會隨之變更。任意呼叫其中一種方法,都會傳回 ZoomState.getZoomRatio()ZoomState.getLinearZoom() 的值。若想在滑桿旁邊顯示變焦比例文字,這個方法就能派上用場。只要查看 ZoomState LiveData,即可同時更新兩者,無需轉換。

在完成重複要求的指定變焦值時,這兩個 API 傳回的 ListenableFuture 可讓應用程式選擇收到通知。此外,如果先前變焦作業尚未完成,而您設定了新變焦值,先前變焦作業的 ListenableFuture 會立即失敗。

手電筒

CameraControl.enableTorch(boolean) 會啟用或停用手電筒 (也稱為閃光燈)。

如需查詢目前的手電筒狀態,可使用 CameraInfo.getTorchState()。透過 CameraInfo.hasFlashUnit() 傳回的值,即可確認是否有可用的手電筒。如果沒有,呼叫 CameraControl.enableTorch(boolean) 會導致傳回的 ListenableFuture 失敗,同時將手電筒狀態設為 TorchState.OFF

啟用手電筒後,無論閃光燈模式為何,在拍攝期間,手電筒都會保持開啟。只有停用手電筒時,ImageCapture 中的 flashMode 才生效。

對焦與測光

CameraControl.startFocusAndMetering() 會根據指定的 FocusmeteringAction 設定 AF/AE/AWB 測光區域,藉此觸發自動對焦和曝光計算用途。許多相機應用程式經常會導入「觸控對焦」用途。

MeteringPoint

首先,請使用 MeteringPointFactory.createPoint(float x, float y, float size) 建立 MeteringPointMeteringPoint 代表相機 Surface 上的單一點。該點資料會以正規化格式儲存,因此可輕鬆轉換為感應器座標,進而指定 AF/AE/AWB 區域。

MeteringPoint 的範圍在 0 到 1,預設大小為 0.15f。如要呼叫 MeteringPointFactory.createPoint(float x, float y, float size) 時,CameraX 會根據提供 的size,以 (x, y) 為中心點建立矩形區域。

要瞭解如何建立 MeteringPoint,請參閱以下程式碼範例:

Kotlin

// Use PreviewView.getMeteringPointFactory if PreviewView is used for preview.
previewView.setOnTouchListener((view, motionEvent) ->  {
val meteringPoint = previewView.meteringPointFactory
    .createPoint(motionEvent.x, motionEvent.y)
…
}

// Use DisplayOrientedMeteringPointFactory if SurfaceView / TextureView is used for
// preview. Please note that if the preview is scaled or cropped in the View,
// it’s the application's responsibility to transform the coordinates properly
// so that the width and height of this factory represents the full Preview FOV.
// And the (x,y) passed to create MeteringPoint may need to be adjusted with
// the offsets.
val meteringPointFactory = DisplayOrientedMeteringPointFactory(
     surfaceView.display,
     camera.cameraInfo,
     surfaceView.width,
     surfaceView.height
)

// Use SurfaceOrientedMeteringPointFactory if the point is specified in
// ImageAnalysis ImageProxy.
val meteringPointFactory = SurfaceOrientedMeteringPointFactory(
     imageWidth,
     imageHeight,
     imageAnalysis)

startFocusAndmetering 和 FocusmeteringAction

如要叫用 startFocusAndMetering(),應用程式必須建立 FocusMeteringAction,其中包含一或多個 MeteringPoints,由 FLAG_AFFLAG_AEFLAG_AWB 選用測光模式組合而成。詳情請參閱以下程式碼範例:

Kotlin

val meteringPoint1 = meteringPointFactory.createPoint(x1, x1)
val meteringPoint2 = meteringPointFactory.createPoint(x2, y2)
val action = FocusMeteringAction.Builder(meteringPoint1) // default AF|AE|AWB
      // Optionally add meteringPoint2 for AF/AE.
      .addPoint(meteringPoint2, FLAG_AF | FLAG_AE)
      // The action will be canceled in 3 seconds (if not set, default is 5s).
      .setAutoCancelDuration(3, TimeUnit.SECONDS)
      .build()

val result = cameraControl.startFocusAndMetering(action)
// Adds listener to the ListenableFuture if you need to know the focusMetering result.
result.addListener({
   // result.get().isFocusSuccessful returns if the auto focus is successful or not.
}, ContextCompat.getMainExecutor(this)

如以上程式碼所示,startFocusAndMetering() 使用 FocusMeteringAction,其中包含AF/AE/AWB 測光區域的一個 MeteringPoint,以及另一個 AF 和 AE 專用的 MeteringPoint。

CameraX 會在內部將其轉換為 Camera2 MeteringRectangles,並設定對應的 CONTROL_AF_REGIONS / CONTROL_AE_REGIONS / CONTROL_AWB_REGIONS 參數來擷取要求。

由於並非每部裝置都支援 AF/AE/AWB 和多個測光區域,因此 CameraX 會盡可能執行 FocusMeteringAction。CameraX 會盡可能全數使用加入的 MeteringPoints,並按照加入的順序排列。在加入所有 MeteringPoints 之後,超出數量限制的 MeteringPoints 將遭到 CameraX 忽略。比方說,如果 FocusMeteringAction 在支援 2 個 MeteringPoints 的平台上提供了 3 個 MeteringPoints,只有前 2 個 MeteringPoints 會用到。CameraX 會忽略最後一個 MeteringPoint

曝光補償

如果需要在自動曝光 (AE) 輸出結果之外微調曝光值 (EV),就很適合使用曝光補償。系統會使用下列方式結合曝光補償值,並以目前圖片條件為準,判斷需要的曝光量:

Exposure = ExposureCompensationIndex * ExposureCompensationStep

CameraX 提供 Camera.CameraControl.setExposureCompensationIndex() 函式,可將曝光補償設為索引值。

正索引值會使圖片看起來更明亮,而負值則會讓圖片便暗。如需知道支援的索引值範圍,可使用下節所述的 CameraInfo.ExposureState.exposureCompensationRange() 進行查詢。如果某個索引值在支援範圍內,那麼當拍攝要求成功啟用該值時,傳回的 ListenableFuture 會順利完成;如果指定的索引值超出支援範圍,setExposureCompensationIndex() 則會導致傳回的 ListenableFuture 立即完成,並且傳回失敗的結果。

CameraX 只會保留最新未處理的 setExposureCompensationIndex() 要求,如果還沒有執行前面要求,且多次呼叫該函式,會導致要求遭到取消。

如要設定曝光補償索引值,並記錄執行曝光變更要求時的回呼,請參閱以下程式碼範例:

Kotlin

camera.cameraControl.setExposureCompensationIndex(exposureCompensationIndex)
   .addListener({
      // Get the current exposure compensation index, it may be
      // different from the asked value in case this request was
      // canceled by a newer setting request.
      val currentExposureIndex = camera.cameraInfo.exposureState.exposureCompensationIndex
      …
   }, mainExecutor)
  • Camera.CameraInfo.getExposureState() 會擷取目前的 ExposureState,包括:

    • 曝光補償控制項的可支援性。
    • 目前的曝光補償索引值。
    • 曝光補償索引值範圍。
    • 曝光補償值的計算方式中所用的曝光補償步驟。

如要使用最新的 ExposureState 值,以初始化以下曝光 SeekBar 的設定,詳情請參閱以下程式碼範例:

Kotlin

val exposureState = camera.cameraInfo.exposureState
binding.seekBar.apply {
   isEnabled = exposureState.isExposureCompensationSupported
   max = exposureState.exposureCompensationRange.upper
   min = exposureState.exposureCompensationRange.lower
   progress = exposureState.exposureCompensationIndex
}

其他資源

如要進一步瞭解 CameraX,請參閱下列其他資源。

程式碼研究室

  • 開始使用 CameraX
  • 程式碼範例

  • CameraX 範例應用程式
  • 開發人員社群

    Android CameraX 討論群組