圖片分析

圖片分析用途可為您的應用程式提供方便 CPU 存取的圖片,以便執行圖片處理作業、電腦視覺或機器學習推論。應用程式會導入在每個影格上執行的 analyze() 方法。

如要瞭解如何整合 Google 的 ML Kit 與 CameraX 應用程式,請參閱「ML Kit 分析工具」一文。

運作模式

如果應用程式的分析管道無法達到 CameraX 的畫面更新率要求,您可以透過下列任一種方式將 CameraX 設定為捨棄影格:

  • 非封鎖 (預設):在此模式下,應用程式分析上一張圖片時,執行程式一律會將最新的圖片快取至圖片緩衝區 (類似深度為一的佇列)。如果 CameraX 在應用程式處理完成之前收到新的圖片,系統會將其儲存至同一個緩衝區,並覆寫先前的圖片。請注意,ImageAnalysis.Builder.setImageQueueDepth() 在 而且緩衝區內容一律會被覆寫。 您可以利用 STRATEGY_KEEP_ONLY_LATEST 呼叫 setBackpressureStrategy() 來啟動此非封鎖模式。如要進一步瞭解執行程式的影響,請參閱參考資料 說明文件 STRATEGY_KEEP_ONLY_LATEST

  • 封鎖:在此模式下,內部執行程式可將多張圖片加入內部圖片佇列,並且僅在佇列已滿時才捨棄影格。封鎖模式適用於整個相機裝置範圍:如果相機裝置有多個已繫結的用途,則在 CameraX 處理這些圖片時,這些用途均會遭到封鎖。舉例來說,如果預覽和圖片分析均繫結至某個相機裝置,那麼當 CameraX 處理圖片時,預覽也會一併遭到封鎖。您只要將 STRATEGY_BLOCK_PRODUCER敬上 到 setBackpressureStrategy()。 您也可以使用 ImageAnalysis.Builder.setImageQueueDepth() 設定圖片佇列深度。

如果使用低延遲度且高效能的工具,使分析圖片的總時間少於 CameraX 影格的時間 (例如 60fps 耗時 16 毫秒),則不論是上述何種操作模式,都能提供順暢的體驗。封鎖模式在某些情況下仍是很實用的,例如: 但在處理非常短的系統時基誤差

具備高延遲和高效能分析工具 封鎖模式具有 需要較長的佇列來彌補延遲時間但請注意,應用程式仍可以處理所有影格。

搭配使用高延遲和耗時的分析工具時 (分析工具無法處理所有影格),非封鎖模式可能較為適用,因為分析路徑必須捨棄影格,但其他並行的繫結用途仍能看到所有影格。

實作

如要在應用程式中使用圖片分析,請按照下列步驟操作:

繫結後,CameraX 會立即將圖片傳送至已註冊的分析工具。 完成分析後,請呼叫 ImageAnalysis.clearAnalyzer()敬上 取消繫結 ImageAnalysis 用途即可停止分析。

建構 ImageAnalysis 應用實例

ImageAnalysis 連線 將分析工具 (圖片使用者) 轉移至 CameraX,也就是圖片製作工具 應用程式可以使用 ImageAnalysis.Builder敬上 建構 ImageAnalysis 物件透過 ImageAnalysis.Builder, 應用程式可以設定下列項目:

應用程式可以設定解析度或長寬比,但無法設定 兩者。確切的輸出解析度取決於應用程式要求的大小 (或顯示比例) 及硬體功能,且可能會與要求的大小或比例不同。如需解析度比對演算法的相關資訊,請參閱: 相關說明文件 setTargetResolution()敬上

應用程式可將輸出圖片像素設為 YUV (預設值) 或 RGBA 色域設定 RGBA 輸出格式時,CameraX 會在內部執行 會將 YUV 轉換為 RGBA 色域,並將圖片位元封裝為 ByteBuffer敬上 擷取此物件 下列順序:

ImageProxy.getPlanes()[0].buffer[0]: alpha
ImageProxy.getPlanes()[0].buffer[1]: red
ImageProxy.getPlanes()[0].buffer[2]: green
ImageProxy.getPlanes()[0].buffer[3]: blue
...

執行複雜的圖片分析作業時,如果裝置無法達到畫面更新率,可以按照本文「操作模式」一節所述的做法設定 CameraX,以便捨棄影格。

建立分析工具

應用程式可透過實作 ImageAnalysis.Analyzer敬上 介面並覆寫設定 analyze(ImageProxy image)。 在每個分析工具中,應用程式會收到 ImageProxy,這是包裝函式 Media.Image 的程序。 您可以使用 ImageProxy.getFormat()。 格式是應用程式的下列其中一個值 提供 ImageAnalysis.Builder

  • ImageFormat.RGBA_8888 (如果應用程式要求 OUTPUT_IMAGE_FORMAT_RGBA_8888)。
  • ImageFormat.YUV_420_888 (如果應用程式要求 OUTPUT_IMAGE_FORMAT_YUV_420_888)。

請參閱「建構 ImageAnalysis 用途」瞭解色域設定,以及可以擷取像素位元組的位置。

在分析工具中,應用程式應執行以下操作:

  1. 最好在特定的畫面更新率時間限制內 (例如 30 fps 時不超過 32 毫秒),盡快分析特定影格。如果應用程式無法快速分析影格,請考慮使用其中一種支援的影格捨棄機制
  2. 呼叫即可將 ImageProxy 發布至 CameraX ImageProxy.close()。 請注意,您不應呼叫已包裝的 Media.Image 關閉函式 (Media.Image.close())。

應用程式可以直接在 ImageProxy 中使用已包裝的 Media.Image。 不要在已包裝的圖片上呼叫 Media.Image.close(),因為這可能會損毀 採用 CameraX 的圖片分享機制而是改用 ImageProxy.close() 將基礎 Media.Image 發布至 CameraX。

設定 ImageAnalysis 分析工具

建立分析工具後,請使用 ImageAnalysis.setAnalyzer()敬上 註冊即可開始分析分析完成後,請使用 ImageAnalysis.clearAnalyzer()敬上 移除已註冊的分析工具。

只能設定一個有效的分析工具進行圖片分析。撥號中 ImageAnalysis.setAnalyzer() 會取代已註冊的分析工具 (如有) 存在。在繫結用途前後,應用程式可以隨時設定新的分析工具。

將 ImageAnalysis 繫結至生命週期

強烈建議您將 ImageAnalysis 繫結至現有 AndroidX 生命週期和 ProcessCameraProvider.bindToLifecycle() 函式。請注意,bindToLifecycle() 函式會傳回所選值 Camera 裝置 (可使用) 可讓您微調進階設定 (例如曝光等)請參閱這份指南,進一步瞭解如何控制相機輸出。

以下範例結合了先前步驟中的所有元素 對 lifeCycle 擁有者的 CameraX ImageAnalysisPreview 用途:

Kotlin

val imageAnalysis = ImageAnalysis.Builder()
    // enable the following line if RGBA output is needed.
    // .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
    .setTargetResolution(Size(1280, 720))
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .build()
imageAnalysis.setAnalyzer(executor, ImageAnalysis.Analyzer { imageProxy ->
    val rotationDegrees = imageProxy.imageInfo.rotationDegrees
    // insert your code here.
    ...
    // after done, release the ImageProxy object
    imageProxy.close()
})

cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, imageAnalysis, preview)

Java

ImageAnalysis imageAnalysis =
    new ImageAnalysis.Builder()
        // enable the following line if RGBA output is needed.
        //.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
        .setTargetResolution(new Size(1280, 720))
        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
        .build();

imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
    @Override
    public void analyze(@NonNull ImageProxy imageProxy) {
        int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees();
            // insert your code here.
            ...
            // after done, release the ImageProxy object
            imageProxy.close();
        }
    });

cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, imageAnalysis, preview);

其他資源

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

程式碼研究室

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

  • CameraX 範例應用程式