CameraX 曝光補(bǔ)償 API 入門(mén)指南

image

在移動(dòng)端發(fā)展的過(guò)程中,相機(jī)設(shè)備對(duì)于推動(dòng)移動(dòng)設(shè)備創(chuàng)新起到了舉足輕重的作用,而相機(jī)曝光則是能夠拍攝出非凡品質(zhì)照片的關(guān)鍵要素。在本文中,我將為大家詳解移動(dòng)端開(kāi)發(fā)者在處理相機(jī)曝光時(shí)所遇到的挑戰(zhàn)。之后我會(huì)為大家介紹新的 CameraX 曝光補(bǔ)償 (Exposure Compensation) API 如何幫助開(kāi)發(fā)者應(yīng)對(duì)這些挑戰(zhàn),使快速拍攝高品質(zhì)照片變得更加簡(jiǎn)單。最后,我將為大家展示如何在您的應(yīng)用中使用該 API。

背景

在攝影中,曝光是決定最終相機(jī)所呈現(xiàn)圖像的最重要因素之一,因此大多數(shù)攝影師都極力將曝光調(diào)至最佳。自動(dòng)曝光 (AE) 模式在大多數(shù)常見(jiàn)拍攝場(chǎng)景下的效果都不錯(cuò),比如自動(dòng)快速拍照。然而在某些特定條件下,AE 模式會(huì)為了照片的整體質(zhì)量而做出一些妥協(xié),而這些妥協(xié)有時(shí)并不是您想要的。其中一個(gè)例子就是逆光,例如,在室內(nèi)朝向窗戶或者其它光源的位置拍攝,或者在室外拍攝,拍攝對(duì)象的后方剛好是太陽(yáng)。在這些拍攝場(chǎng)景中,AE 模式會(huì)因?yàn)槊髁恋谋尘?(照片中高亮的區(qū)域) 而對(duì)照片進(jìn)行適當(dāng)曝光,但是處于黑暗前景中的主體就會(huì)變得過(guò)于昏暗或者成為剪影效果。圖 1 展示的是在相同條件 (室內(nèi)逆光) 下使用不同曝光進(jìn)行拍攝的三張照片。

image

AE 對(duì)于照片的整體質(zhì)量控制得很好,但是更高的曝光確實(shí)能夠捕獲到 Android 公仔的更多畫(huà)面細(xì)節(jié)。

傳統(tǒng)操作中,攝影師通過(guò)調(diào)整如下三個(gè)參數(shù)來(lái)達(dá)到滿意的曝光:

  • 光圈: 鏡片的打開(kāi)程度,它控制相機(jī)的進(jìn)光量
  • 快門(mén)速度: 照片曝光的持續(xù)時(shí)間
  • ISO (國(guó)際標(biāo)準(zhǔn)化組織): 相機(jī)感光元件對(duì)捕獲光線的敏感程度

每個(gè)參數(shù)對(duì)于圖像都有特殊的作用: 光圈可以調(diào)整景深效果,快門(mén)速度可以虛化運(yùn)動(dòng)的過(guò)程或者定格運(yùn)動(dòng)的瞬間,而更高的 ISO 會(huì)增加圖像噪點(diǎn)。其中用到相當(dāng)精準(zhǔn)的數(shù)學(xué)計(jì)算,但是這些參數(shù)設(shè)置的不同組合可以獲得相同的整體曝光效果,以及在這個(gè)過(guò)程中獲得高水準(zhǔn)的完美曝光數(shù)值。為了輔助補(bǔ)償曝光,CameraX 實(shí)現(xiàn)了曝光補(bǔ)償 API。

實(shí)現(xiàn)曝光補(bǔ)償 API

曝光補(bǔ)償 API 根據(jù)生成的自動(dòng)曝光值,通過(guò)曝光補(bǔ)償指數(shù)調(diào)整曝光補(bǔ)償度。曝光補(bǔ)償指數(shù)可以為正值 (用于提高照片亮度) 或者負(fù)值 (降低照片亮度)。它將整體曝光范圍映射到補(bǔ)償指數(shù)的取值區(qū)間,并將曝光總量映射到 EV 步長(zhǎng)。相機(jī)設(shè)備內(nèi)部會(huì)根據(jù)曝光指數(shù)改變曝光,減少控制其它參數(shù)的操作并且達(dá)到同一效果。

以圖 1 為例,相機(jī)的默認(rèn)配置無(wú)法為我們希望對(duì)焦的主體提供足夠的亮度,所以我們可以使用正值指數(shù)的曝光補(bǔ)償配置來(lái)獲得兩倍或者四倍的曝光,從而突出主體。通過(guò)改變曝光補(bǔ)償指數(shù),相機(jī)內(nèi)部會(huì)控制快門(mén)速度、光圈和 ISO 以獲得合適的曝光。

要獲得補(bǔ)償指數(shù),CameraX 實(shí)現(xiàn)了以下內(nèi)容:

  1. CameraControl::setExposureCompensationIndex,用于設(shè)置新的曝光補(bǔ)償指數(shù)。

  2. ExposureState 用于曝光補(bǔ)償性能和當(dāng)前配置,包括:

  3. 支持調(diào)整補(bǔ)償

  4. 所支持的補(bǔ)償范圍

  5. 所支持的補(bǔ)償步長(zhǎng)

  6. 當(dāng)前補(bǔ)償指數(shù)值

我們來(lái)看看在 CameraX 應(yīng)用中如何使用 API 來(lái)創(chuàng)建曝光合適的照片。

使用曝光補(bǔ)償 API

要在應(yīng)用中使用曝光補(bǔ)償 API,您需要完成如下工作:

  • 查詢曝光補(bǔ)償范圍
  • 設(shè)置新的曝光補(bǔ)償指數(shù)
  • 當(dāng) CameraX 確認(rèn)后繼續(xù)后續(xù)操作

查詢曝光補(bǔ)償指數(shù)的范圍

曝光補(bǔ)償值的范圍依賴 相機(jī)設(shè)備的配置和硬件級(jí)別;應(yīng)用可以通過(guò) ExposureState 接口查詢所支持的取值范圍。

val camera = cameraProvider.bindToLifecycle( … )
val range = camera.cameraInfo.exposureState.exposureCompensationRange

設(shè)置新的曝光補(bǔ)償指數(shù)

如果照片顯得較暗,在相機(jī)原本的修正曝光基礎(chǔ)上設(shè)置一個(gè)正值的曝光補(bǔ)償指數(shù)來(lái)提高亮度;同理,如果照片顯得過(guò)亮,則設(shè)置一個(gè)負(fù)值。這可以通過(guò) setExposureCompensationIndex() 來(lái)實(shí)現(xiàn):

interface CameraControl {
    fun setExposureCompensationIndex(value: Int): ListenableFuture<Int!>
}

默認(rèn)情況下,曝光補(bǔ)償指數(shù)的值從 "0" 開(kāi)始,新的指數(shù)值必須在相機(jī)設(shè)備所支持的范圍內(nèi)變化。否則 CameraX 會(huì)拋出 IllegalArgument 錯(cuò)誤。請(qǐng)注意如果相機(jī)設(shè)備不支持曝光補(bǔ)償調(diào)節(jié),CameraX 所返回支持的取值范圍是 [0,0]。

舉個(gè)例子,下述代碼中當(dāng)用戶點(diǎn)擊了 UI 中的按鈕會(huì)提高曝光補(bǔ)償指數(shù)直到曝光指數(shù)達(dá)到所支持的最大值為止:

var exposureIndex = 0
val camera = cameraProvider.bindToLifecycle(
    lifecycleOwner,
    getCameraSelector(),
    preview,
    imageCapture,
)

evButton.setOnClickListener {
    val range = camera.cameraInfo.exposureState.exposureCompensationRange
    if (range.contains(exposureIndex + 1)) {
        camera.cameraControl.setExposureCompensationIndex(++exposureIndex)
        val ev = camera.cameraInfo.exposureState.exposureCompensationStep.toFloat() * exposureIndex
        Log.i("CameraXLog", "EV: $ev")
    }
}

setExposureCompensationIndex()async 函數(shù),每個(gè)相機(jī)只能響應(yīng)一個(gè)未處理的請(qǐng)求。如果應(yīng)用在之前的調(diào)用未被響應(yīng)之前再次調(diào)用 setExposureCompensationIndex(),新的調(diào)用請(qǐng)求就會(huì)替代之前的請(qǐng)求,而之前的請(qǐng)求會(huì)被取消并拋出 OperationCanceledException。通常,新的指數(shù)值會(huì)被迅速啟用,輸出流的曝光會(huì)隨著 綁定用例 變化。如果應(yīng)用需要知道特定請(qǐng)求的準(zhǔn)確執(zhí)行時(shí)間和結(jié)果,可以在函數(shù)返回的 ListenableFuture<Int> 之上注冊(cè)監(jiān)聽(tīng)器。

關(guān)聯(lián)補(bǔ)償指數(shù)和曝光值 (EV)

曝光值 (EV) 是一個(gè)用于表示曝光補(bǔ)償?shù)墓庹斩炔町惖亩攘繂挝弧?1 EV 表示兩倍光照,+2 EV 是四倍光照,依此類(lèi)推。應(yīng)用可以將相同的曝光值應(yīng)用到各種相機(jī),甚至不同的設(shè)備,來(lái)獲得相似的曝光,但是應(yīng)用不應(yīng)該針對(duì)相同的目標(biāo)效果直接使用相同的指數(shù)值,因?yàn)槊總€(gè)指數(shù)值是相機(jī)的專(zhuān)屬值。

補(bǔ)償 API 中,曝光值是通過(guò)如下公式進(jìn)行計(jì)算的:

曝光值 (EV) = exposure_compensation_index * compensation_step

上述公式中提到的 compensation_step 是曝光值可被修改的最小單位。請(qǐng)注意 compensation_step 也依賴相機(jī)設(shè)備。應(yīng)用可以通過(guò) ExposureState 查詢相機(jī)的 compensation_step,并且可以按照下面所示計(jì)算曝光值:

val camera = cameraProvider.bindToLifecycle( … )
val exposureValue = camera.cameraInfo.exposureState.exposureCompensationStep.toFloat() * exposureIndex

例如: exposure_compensation_index 等于 6,compensation_step 等于 ?,那么曝光補(bǔ)償計(jì)算為 +2 EV,也就是兩倍的默認(rèn)曝光值。

compensation_step 的 step_size 取值通常為 ? 或者 ?,較少情況下,有些設(shè)備可能會(huì)支持 1 或者甚至 ?。所能支持的最大曝光值一般是 2 EV 或者 3 EV。

CameraX 曝光補(bǔ)償 API 的可用性

曝光補(bǔ)償 API 是在 android.camera:camera-core:1.0.0-beta09 中首次以實(shí)驗(yàn)方式發(fā)布。

該 API 在版本 android.camera:camera-core:1.1.0-alpha06 中完成了實(shí)驗(yàn)階段,成為正式版本 CameraX API 的一部分。

要獲得最新的發(fā)布版本,請(qǐng)查閱 官方 CameraX 版本說(shuō)明。

總結(jié)

GitHub 上可以找到 CameraX 曝光補(bǔ)償?shù)氖纠a。結(jié)合 CameraX API 的其它部分,曝光補(bǔ)償 API 可以幫助開(kāi)發(fā)者實(shí)現(xiàn)富有創(chuàng)意的 Android 相機(jī)應(yīng)用,并在移動(dòng)應(yīng)用的海洋中脫穎而出。如果您有興趣了解更多關(guān)于 CameraX 的內(nèi)容,請(qǐng)參閱 官方文檔,如果希望能夠持續(xù)獲得 CameraX 的最新進(jìn)展,可以加入 CameraX 討論組。歡迎大家提出寶貴意見(jiàn),可以在 CameraX 討論組 中和我們交流,或者創(chuàng)建 CameraX issues 提交您遇到的問(wèn)題。

相關(guān)閱讀

歡迎您 點(diǎn)擊這里 向我們提交反饋,或分享您喜歡的內(nèi)容、發(fā)現(xiàn)的問(wèn)題。您的反饋對(duì)我們非常重要,感謝您的支持!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容