Analisis gambar

Kasus penggunaan analisis gambar memberi aplikasi Anda gambar yang dapat diakses CPU, yang memungkinkan Anda melakukan pemrosesan gambar, computer vision, atau inferensi machine learning. Aplikasi ini mengimplementasikan metode analyze() yang dijalankan di setiap frame.

Mode Operasi

Jika pipeline analisis aplikasi tidak dapat memenuhi persyaratan kecepatan frame CameraX, CameraX dapat dikonfigurasi untuk menghapus frame dengan salah satu cara berikut:

  • non-pemblokiran (default): Dalam mode ini, eksekutor selalu men-cache gambar terbaru ke buffering gambar (mirip dengan antrean dengan kedalaman satu) saat aplikasi menganalisis gambar sebelumnya. Jika CameraX menerima gambar baru sebelum aplikasi selesai memproses gambar sebelumnya, gambar baru akan disimpan ke buffering yang sama dan menimpa gambar sebelumnya. Perlu diperhatikan bahwa ImageAnalysis.Builder.setImageQueueDepth() tidak berpengaruh dalam skenario ini, dan konten buffering akan selalu ditimpa. Anda dapat mengaktifkan mode non-pemblokiran ini dengan memanggil setBackpressureStrategy() menggunakan STRATEGY_KEEP_ONLY_LATEST. Untuk informasi selengkapnya tentang implikasi eksekutor, lihat dokumentasi referensi untuk STRATEGY_KEEP_ONLY_LATEST.

  • pemblokiran: Dalam mode ini, eksekutor internal dapat menambahkan beberapa gambar ke antrean gambar internal dan mulai menghapus frame hanya saat antrean penuh. Pemblokiran terjadi di seluruh cakupan perangkat kamera: jika perangkat kamera memiliki beberapa kasus penggunaan terikat, kasus penggunaan tersebut semuanya akan diblokir saat CameraX memproses gambar ini. Misalnya, jika analisis pratinjau dan gambar terikat ke perangkat Kamera, pratinjau juga akan diblokir saat CameraX memproses gambar. Anda dapat mengaktifkan mode pemblokiran dengan meneruskan STRATEGY_BLOCK_PRODUCER ke setBackpressureStrategy(). Anda juga dapat mengonfigurasi kedalaman antrean gambar menggunakan ImageAnalysis.Builder.setImageQueueDepth().

Dengan analyzer berlatensi rendah dan berperforma tinggi saat total waktu untuk menganalisis gambar kurang dari durasi frame CameraX (misalnya, 16 md untuk 60 fps), kedua mode operasi memberikan pengalaman keseluruhan yang lancar. Mode pemblokiran masih dapat membantu dalam beberapa skenario, seperti saat menangani jitter sistem yang sangat singkat.

Dengan analyzer berlatensi tinggi dan berperforma tinggi, mode pemblokiran dengan antrean yang lebih panjang diperlukan untuk mengimbangi latensi. Namun, perlu diperhatikan bahwa aplikasi masih dapat memproses semua frame.

Dengan analyzer berlatensi tinggi dan memakan waktu (analyzer tidak dapat memproses semua frame), mode non-pemblokiran mungkin menjadi pilihan yang lebih tepat, karena frame harus dihapus untuk jalur analisis, tetapi kasus penggunaan terikat serentak lainnya masih dapat melihat semua frame.

Implementasi

Untuk menggunakan analisis gambar dalam aplikasi, ikuti langkah-langkah berikut:

Segera setelah pengikatan, CameraX akan mengirimkan gambar ke analyzer yang terdaftar. Setelah menyelesaikan analisis, panggil ImageAnalysis.clearAnalyzer() atau lepas kasus penggunaan ImageAnalysis untuk menghentikan analisis.

Membuat kasus penggunaan ImageAnalysis

ImageAnalysis menghubungkan analyzer (konsumen gambar) ke CameraX, yang merupakan penghasil gambar. Aplikasi dapat menggunakan ImageAnalysis.Builder untuk membuat objek ImageAnalysis. Dengan ImageAnalysis.Builder, aplikasi dapat mengonfigurasi hal berikut:

Aplikasi dapat menyetel resolusi atau rasio lebar tinggi, tetapi tidak keduanya. Resolusi output yang tepat bergantung pada ukuran (atau rasio lebar tinggi) dan kemampuan hardware yang diminta aplikasi, dan mungkin berbeda dengan ukuran atau rasio yang diminta. Untuk mengetahui informasi tentang algoritme pencocokan resolusi, lihat dokumentasi untuk setTargetResolution()

Aplikasi dapat mengonfigurasi piksel gambar output agar berada dalam ruang warna YUV (default) atau RGBA. Jika menyetel format output RGBA, CameraX akan mengonversi gambar secara internal dari ruang warna YUV ke RGBA dan memaketkan bit gambar ke ByteBuffer bidang pertama ImageProxy (dua bidang lainnya tidak digunakan) dengan urutan berikut:

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

Saat melakukan analisis gambar yang rumit dan perangkat tidak dapat mempertahankan kecepatan frame, Anda dapat mengonfigurasi CameraX untuk menghapus frame dengan strategi yang dijelaskan di bagian Mode Operasi dalam topik ini.

Membuat analyzer

Aplikasi dapat membuat analyzer dengan mengimplementasikan antarmuka ImageAnalysis.Analyzer dan mengganti analyze(ImageProxy image). Di setiap analyzer, aplikasi menerima ImageProxy, yang merupakan wrapper untuk Media.Image. Format gambar dapat dibuat kuerinya dengan ImageProxy.getFormat(). Formatnya adalah salah satu dari nilai berikut yang disediakan aplikasi dengan ImageAnalysis.Builder:

  • ImageFormat.RGBA_8888 jika aplikasi meminta OUTPUT_IMAGE_FORMAT_RGBA_8888.
  • ImageFormat.YUV_420_888 jika aplikasi meminta OUTPUT_IMAGE_FORMAT_YUV_420_888.

Lihat Membuat kasus penggunaan ImageAnalysis untuk mengetahui konfigurasi ruang warna dan tempat pengambilan byte piksel.

Di dalam analyzer, aplikasi harus melakukan hal berikut:

  1. Menganalisis frame tertentu secepat mungkin, yang sebaiknya dalam batas waktu kecepatan frame tertentu (misalnya, kurang dari 32 md untuk kasus 30 fps). Jika aplikasi tidak dapat menganalisis frame dengan cukup cepat, pertimbangkan salah satu mekanisme penghapusan frame yang didukung.
  2. Merilis ImageProxy ke CameraX dengan memanggil ImageProxy.close(). Perhatikan bahwa Anda tidak boleh memanggil fungsi close Media.Image yang digabungkan (Media.Image.close()).

Aplikasi dapat menggunakan Media.Image yang digabungkan dalam ImageProxy secara langsung. Namun, jangan memanggil Media.Image.close() pada gambar yang digabungkan karena hal itu akan mengganggu mekanisme berbagi gambar di dalam CameraX. Sebagai gantinya, gunakan ImageProxy.close() untuk merilis Media.Image utama ke CameraX.

Mengonfigurasi analyzer untuk ImageAnalysis

Setelah membuat analyzer, gunakan ImageAnalysis.setAnalyzer() untuk mendaftarkannya agar dapat memulai analisis. Setelah menyelesaikan analisis, gunakan ImageAnalysis.clearAnalyer() untuk menghapus analyzer yang terdaftar.

Hanya satu analyzer aktif yang dapat dikonfigurasi untuk analisis gambar. Memanggil ImageAnalysis.setAnalyzer() akan menggantikan analyzer yang terdaftar jika sudah ada. Aplikasi dapat menyetel analyzer baru kapan saja, sebelum atau setelah mengikat kasus penggunaan.

Mengikat ImageAnalysis ke Lifecycle

Sangat direkomendasikan untuk mengikat ImageAnalysis Anda ke siklus proses AndroidX yang ada dengan fungsi ProcessCameraProvider.bindToLifecycle(). Perhatikan bahwa fungsi bindToLifecycle() akan menampilkan perangkat Kamera yang dipilih, yang dapat digunakan untuk menyesuaikan setelan lanjutan seperti eksposur dan lainnya.

Contoh berikut menggabungkan semua langkah sebelumnya, yaitu mengikat kasus penggunaan ImageAnalysis dan Preview CameraX ke pemilik lifeCycle:

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);

Referensi lainnya

Untuk mempelajari lebih lanjut tentang CameraX, lihat referensi tambahan berikut.

Codelab

  • Mulai Menggunakan CameraX
  • Contoh kode

  • Aplikasi contoh CameraX resmi