使用 CameraX Extensions API 將特效應用到照片上

Android CameraX 的設計旨在幫助您簡化相機應用的開發工作。隨着對 CameraX 不斷的開發,相機應用的開發者們向我們展示了他們的激情和熱忱,當前的 API 中已經融入了許多很棒的創意,例如值得稱讚的 CameraX Extensions API。最近我們採納了開發者社區的意見,對擴展進行了重構,如今有了新的 ExtensionsManager,您只需兩行代碼就可以使用這些擴展!本文將介紹如何在您的應用中使用 Extensions API。

CameraX Extensions

Android 設備配備了強大的相機,製造商們投入了大量精力將衆多前沿的功能特性或特效融入這些相機設備中。過去,這些強大的功能只能由設備的原生相機應用提供。如今,憑藉 CameraX Extensions API,第三方開發者可以通過一個通用的、簡單的接口來訪問這些強大的相機功能。

CameraX Extensions 涵蓋的內容

1.0.0 版本的 CameraX Extensions 包括一些最常見的內置相機特效:

  • BOKEH (焦外成像): 在人像模式下拍攝照片時,讓前景人物更清晰。
  • HDR (高動態範圍): 拍照時使用不同的自動曝光 (AE) 配置,以獲得最佳效果。
  • NIGHT (夜間): 在低照度環境下 (通常是在夜間) 捕獲最佳靜態圖像。
  • FACE RETOUCH (臉部照片修復): 拍攝靜態圖像時,修飾臉部膚色、輪廓等。
  • AUTO (自動): 根據周圍的景色自動調整最終圖像。

讓我們來看幾組在 Android 手機上拍攝的照片,拍照時分別啓用和禁用了由 CameraX Extensions API 提供的特效。

BOKEH 模式的例子

HDR 模式的例子

NIGHT 模式例子

視覺上的差異是很明顯的。您可以使用 CameraX Extensions API 在您自己的應用中實現這些圖像的效果。

現在讓我們看看如何將 CameraX 的 API 集成到您的應用中。

Extensions API

在現有的 CameraX 應用中,首先您可以引入 camera-extensions Jetpack 庫來添加 CameraX Extensions:

dependencies {
    // 與 Extensions 庫版本號相匹配的 CameraX 核心庫
    implementation 'androidx.camera:camera-core:1.1.0-alpha08'
    implementation 'androidx.camera:camera-camera2:1.1.0-alpha08'
    implementation 'androidx.camera:camera-lifecycle:1.1.0-alpha08'

    // CameraX Extensions 庫
    implementation 'androidx.camera:camera-extensions:1.0.0-alpha28'

    // 其他依賴項
    implementation('androidx.concurrent:concurrent-futures-ktx:1.1.0')
        …
}

接下來,通過以下步驟集成 Extensions:

  1. 獲取 ExtensionsManager 實例。
  2. 檢查目標設備是否支持需要用到的擴展模式;
  3. 獲取一個啓用擴展的 CameraSelector;
  4. 使用啓用擴展的 CameraSelector 調用 bindToLifecycle

獲取 ExtensionsManager 實例

第一步是用擴展庫的 getInstance(Context) API 獲得一個 ExtensionsManager 實例。這個 API 返回一個 ListenableFuture,我們可以在 Kotlin 掛起函數中使用 await() 來獲取結果以避免阻塞主線程。(注意: 在 ListenableFuture 上使用 await() 須引入 androidx.concurrent:concurrent-futures-ktx: 1.1.0 依賴項。)

// 創建擴展管理器(使用 Jetpack Concurrent 庫)
val extensionsManager =  ExtensionsManager.getInstance(context).await()

通過 ExtensionsManager,您可以確定設備是否支持某一特定的擴展模式,併爲其獲取一個啓用擴展的 CameraSelector。請注意以下幾點:

  • ExtensionsManager 是一個進程範圍的全局資源: 一個進程中只存在一個 ExtensionsManager 實例。
  • ExtensionsManager 始終存在: 無論底層設備是否支持擴展,CameraX 都提供一個有效的 ExtensionsManager 實例。

檢查擴展模式可用性

通過 ExtensionsManager,使用 isExtensionAvailable(CameraProvider, CameraSelector, int) 函數檢查擴展的可用性: 如果設備上存在任何經由 CameraSelector 過濾的相機支持所查詢的擴展,則返回 true,否則返回 false。

// 獲取相機設備來檢查是否支持擴展
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

// 檢查是否支持 BOKEH
 if (extensionsManager.isExtensionAvailable(
    cameraProvider,
    cameraSelector,
    ExtensionMode.BOKEH
   )) {
   ...
}

獲取啓用擴展的 CameraSelector

一旦您確認了設備支持該擴展模式,就可以用 getExtensionEnabledCameraSelector(CameraProvider, CameraSelector, int) 函數獲取一個啓用擴展的 CameraSelector。此函數返回啓用擴展的 CameraSelector,其包含關於指定擴展模式的所有詳細信息。

val bokehCameraSelector = extensionsManager
                          .getExtensionEnabledCameraSelector(
                              cameraProvider, cameraSelector, ExtensionMode.BOKEH)

使用啓用擴展的 CameraSelector 調用 bindToLifecycle()

最後一步是使用 bindToLifecycle() 將您的用例與啓用擴展的 CameraSelector 綁定。使用啓用擴展的 CameraSelector 如同使用普通的 CameraSelector 一樣,例如使用 DEFAULT_BACK_CAMERADEFAULT_FRONT_CAMERA。當使用啓用擴展的 CameraSelector綁定用例時,CameraX 會直接在相機上啓用指定的擴展模式。例如,當綁定到 Preview 時,擴展效果被應用到預覽中,或者應用到由所綁定的 ImageCapture 所捕獲的圖像上。

// 將開啓了 BOKEH 的相機選擇器綁定到用例上
val imageCapture = ImageCapture.Builder().build()
val preview = Preview.Builder().build()
cameraProvider.bindToLifecycle(
                lifecycleOwner,
                bokehCameraSelector,
                imageCapture,
                preview
            )

使用 Extensions API 的樣例代碼

Extensions API 示例的完整代碼如下:

fun onCreate() {
    lifecycleScope.launch {
        // 創建 cameraProvider
        val cameraProvider = ProcessCameraProvider.getInstance(context).await() 

        // 創建 extensionsManager(使用 Jetpack Concurrent 庫)
        val extensionsManager = 
                ExtensionsManager.getInstance(context).await()

        // 獲取相機設備來檢查是否支持擴展        
        val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

        // 檢查是否支持 BOKEH
        if (extensionsManager.isExtensionAvailable(
                cameraProvider,
                cameraSelector,
                ExtensionMode.BOKEH
            )) {
            // 在啓用不同擴展模式之前解除所有用例的綁定
            cameraProvider.unbindAll()

            // 獲取啓用了 BOKEH 的相機選擇器
            val bokehCameraSelector = extensionsManager
                    .getExtensionEnabledCameraSelector(
                cameraProvider,
                cameraSelector,
                ExtensionMode.BOKEH
            )

            // 將開啓了 BOKEH 的相機選擇器綁定到用例上
            val imageCapture = ImageCapture.Builder().build()
            val preview = Preview.Builder().build()
            cameraProvider.bindToLifecycle(
                lifecycleOwner,
                bokehCameraSelector,
                imageCapture,
                preview
            )
        }
    }
}

Extensions API 對核心模塊的依賴

CameraX Extensions API 是在 camera-extensions 庫中實現的,並且它依賴 CameraX 核心模塊 (core、camera2 和 lifecycle)。使用 CameraX Extensions 時,請務必使用與您正在使用的 CameraX 核心模塊 相同的發佈包 中的版本。例如,要使用 camera-extensions:1.0.0-alpha28,則您必須在應用的依賴列表中包含 1.0.0-alpha08 版本的 camera-lifecyclecamera-corecamera-camera2,因爲它們是於 2021 年 8 月 18 日在同一軟件包中發佈的。

支持擴展的設備

爲了能使用 CameraX Extensions API,設備製造商需要實現 CameraX Vendor Extensions 接口。您可以在 CameraX 設備頁面 上找到支持 CameraX Extensions API 的部分設備列表。請注意,這不是一個詳盡的列表。如果您的設備被列出,但可用性檢查返回了 false,您可能需要將您的設備更新到製造商的最新 ROM 版本。

除了支持擴展的設備列表外,從 Android 12 開始,您還可以通過檢查 Android 屬性 ro.camerax.extensions.enabled 來確定設備是否支持 CameraX Extensions。

移除舊版 Extensions API

2019 年 8 月發佈的舊版 Extensions API 現已廢棄。這個舊版的 Extensions API 提供了擴展器類,需要將擴展相關的配置應用到每個 Preview 和 ImageCapture 用例上。舊版的擴展器設計可能會導致開發人員忘記要在 Preview 或 ImageCapture 上啓用擴展模式,並可能導致非預期的行爲。

新的 CameraX Extensions 庫在 1.0.0-alpha26 中引入。較新的 Extensions API 將擴展綁定從用例切換到目標相機,使用起來更加方便。請務必遷移以利用新的 Extensions API。

我們特別感謝那些幫助實現 CameraX Extensions API 的出色的 Android 相機開發者和設備製造商!如果您想了解 CameraX 的最新進展,請加入 Android CameraX 討論組

更多信息

歡迎您 點擊這裏 向我們提交反饋,或分享您喜歡的內容、發現的問題。您的反饋對我們非常重要,感謝您的支持!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章