CameraX 所有用途都能進行選項設定,用來控制用途各個面向的操作。
舉例來說,開發人員可以設定拍照用途的目標長寬比和閃光燈模式。詳情請參閱以下程式碼範例:
Kotlin
val imageCapture = ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build()
Java
ImageCapture imageCapture = new ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build();
建立用途後,除了設定選項之外,某些用途也能提供 API,用來動態變更設定。如需個別用途的特定設定資訊,請參閱「導入預覽畫面」、「分析圖片」以及「拍照」。
CameraXConfig
CameraX 內部執行程式和處理常式已有預設設定,可輕鬆支援大部分的使用情境。不過,開發人員如有特殊需求,或想自訂這類設定,可使用 CameraXConfig
介面。
透過 CameraXConfig
可執行以下操作:
- 使用
setAvailableCameraLimiter()
改善開機延遲。 - 使用
setCameraExecutor()
將應用程式的執行者提供給 CameraX。 - 將預設排程器處理常式替換為
setSchedulerHandler()
。 - 使用
setMinimumLoggingLevel()
變更記錄等級。
拍攝模式
如要瞭解如何使用 CameraXConfig
,請參閱以下程序說明:
- 使用自訂設定來建立
CameraXConfig
物件。 - 在
Application
中實作CameraXConfig.Provider
介面,並在getCameraXConfig()
中傳回CameraXConfig
物件。 - 請根據此處說明,在
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 實作。
矩形裁剪
根據預設,矩形裁剪即為完整的緩衝區矩形。只要使用 ViewPort
和 UseCaseGroup
設定,開發人員可以自訂這項用途。將用途分組並設定可視區域後,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
,所以應用程式從 ImageAnalysis
和 ImageCapture
取得的資料,與使用者在 PreviewView
看到的畫面一致。在輸出緩衝區套用裁剪矩形和旋轉用途,所有用途的圖片會同步,但解析度可能不同。如要進一步瞭解如何套用轉換,請參閱「轉換輸出」。
相機選項
CameraX 會自動選擇最符合需求的鏡頭,以滿足應用程式的需求和用途。如果您想使用不同於 CameraX 預選的鏡頭,可以採取下列做法:
- 使用
CameraSelector.DEFAULT_FRONT_CAMERA
要求預設前置鏡頭。 - 使用
CameraSelector.DEFAULT_BACK_CAMERA
要求預設後置鏡頭。 - 使用
CameraSelector.Builder.addCameraFilter()
的CameraCharacteristics
篩選可用鏡頭清單。
要瞭解如何建立 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
可設定常見的相機用途。CameraInfo
可查詢這些常見用途的狀態。
以下是 CameraControl 支援的相機用途:
- 變焦
- 手電筒
- 對焦和測光 (觸控對焦)
- 曝光補償
取得 CameraControl 和 CameraInfo 的執行個體
使用 ProcessCameraProvider.bindToLifecyle()
傳回的 Camera
物件,並擷取 CameraControl
和 CameraInfo
執行個體。詳情請見以下程式碼範例:
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)
建立 MeteringPoint
。MeteringPoint
代表相機 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_AF
、FLAG_AE
、FLAG_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,請參閱下列其他資源。
程式碼研究室
程式碼範例