Anda mengonfigurasi setiap kasus penggunaan CameraX untuk mengontrol berbagai aspek operasi kasus penggunaan.
Misalnya, pada kasus penggunaan pengambilan gambar, Anda dapat menentukan rasio lebar tinggi target dan mode flash. Kode berikut menampilkan satu contoh:
Kotlin
val imageCapture = ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build()
Java
ImageCapture imageCapture = new ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build();
Selain opsi konfigurasi, beberapa kasus penggunaan mengekspos API untuk secara dinamis mengubah setelan setelah kasus penggunaan dibuat. Untuk informasi tentang konfigurasi yang berlaku khusus bagi kasus penggunaan tertentu, lihat Mengimplementasikan pratinjau, Menganalisis gambar, dan Mengambil foto.
CameraXConfig
Untuk kemudahan, CameraX memiliki konfigurasi default seperti eksekutor dan pengendali
internal yang cocok untuk sebagian besar skenario penggunaan. Namun, jika aplikasi Anda
memiliki persyaratan khusus atau lebih memilih untuk menyesuaikan konfigurasi
tersebut, CameraXConfig
adalah antarmuka untuk tujuan tersebut.
Dengan CameraXConfig
, aplikasi dapat melakukan hal berikut:
- Mengoptimalkan latensi pengaktifan dengan
setAvailableCameraLimiter()
. - Memberikan eksekutor aplikasi untuk CameraX dengan
setCameraExecutor()
. - Mengganti pengendali penjadwal default dengan
setSchedulerHandler()
. - Mengubah level logging dengan
setMinimumLoggingLevel()
.
Model Penggunaan
Prosedur berikut menjelaskan cara menggunakan CameraXConfig
:
- Membuat objek
CameraXConfig
dengan konfigurasi yang disesuaikan. - Mengimplementasikan antarmuka
CameraXConfig.Provider
diApplication
, dan menampilkan objekCameraXConfig
Anda digetCameraXConfig()
. - Menambahkan class
Application
ke fileAndroidManifest.xml
, seperti yang dijelaskan di sini.
Misalnya, contoh kode berikut membatasi logging CameraX hanya untuk pesan error:
Kotlin
class CameraApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setMinimumLoggingLevel(Log.ERROR).build() } }
Simpan salinan lokal objek CameraXConfig
jika aplikasi Anda perlu mengetahui
konfigurasi CameraX setelah menyetelnya.
Pembatas Kamera
Selama pemanggilan
ProcessCameraProvider.getInstance()
pertama,
CameraX menguraikan dan mengirim kueri karakteristik kamera yang tersedia di
perangkat. Karena CameraX perlu berkomunikasi dengan komponen hardware, proses
ini dapat memakan waktu yang tidak singkat untuk setiap kamera, terutama pada
perangkat kelas bawah. Jika aplikasi Anda hanya menggunakan kamera tertentu pada perangkat,
seperti kamera depan default, Anda bisa menyetel CameraX untuk mengabaikan kamera lain
sehingga dapat mengurangi latensi pengaktifan untuk kamera yang digunakan aplikasi.
Jika CameraSelector
yang diteruskan
ke
CameraXConfig.Builder.setAvailableCamerasLimiter()
memfilter kamera, CameraX akan berperilaku seolah-olah kamera tersebut tidak ada Google. Misalnya,
kode berikut membatasi aplikasi untuk hanya menggunakan kamera belakang
default perangkat:
Kotlin
class MainApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setAvailableCamerasLimiter(CameraSelector.DEFAULT_BACK_CAMERA) .build() } }
Thread
Banyak API platform tempat CameraX dibuat memerlukan pemblokiran
komunikasi antar-proses (IPC) dengan hardware yang terkadang memerlukan waktu ratusan milidetik untuk merespons. Karena alasan ini, CameraX hanya memanggil API ini dari
thread latar belakang sehingga thread utama tidak diblokir dan UI
tetap berjalan. CameraX mengelola thread latar belakang ini secara internal sehingga perilaku ini
terlihat transparan. Namun, beberapa aplikasi memerlukan kontrol thread
yang ketat. CameraXConfig
memungkinkan aplikasi menetapkan thread latar belakang
yang digunakan melalui
CameraXConfig.Builder.setCameraExecutor()
dan
CameraXConfig.Builder.setSchedulerHandler()
Google.
Eksekutor Kamera
Eksekutor kamera digunakan untuk semua panggilan API platform Kamera internal, serta
untuk callback dari API ini. CameraX mengalokasikan dan mengelola
Executor
internal untuk melakukan tugas ini.
Namun, jika aplikasi Anda memerlukan kontrol thread yang lebih ketat, gunakan
CameraXConfig.Builder.setCameraExecutor()
.
Pengendali Penjadwal
Pengendali penjadwal digunakan untuk menjadwalkan tugas internal pada interval tetap,
seperti mencoba kembali membuka kamera saat tidak tersedia. Pengendali ini tidak
menjalankan tugas, dan hanya mengirimkannya ke eksekutor kamera. Pengendali ini
juga terkadang digunakan di platform API lama yang memerlukan
Handler
untuk callback. Dalam hal ini,
callback masih hanya dikirim langsung ke eksekutor kamera. CameraX
mengalokasikan dan mengelola
HandlerThread
internal untuk melakukan tugas ini,
tetapi Anda dapat menggantinya dengan CameraXConfig.Builder.setSchedulerHandler()
.
Logging
Logging CameraX memungkinkan aplikasi memfilter pesan logcat karena ini adalah praktik yang baik untuk menghindari pesan panjang dalam kode produksi. CameraX mendukung empat level logging, dari yang paling panjang hingga yang paling berat:
Log.DEBUG
(default)Log.INFO
Log.WARN
Log.ERROR
Lihat dokumentasi Log Android
untuk deskripsi mendetail tentang level log ini. Gunakan
CameraXConfig.Builder.setMinimumLoggingLevel(int)
untuk menetapkan level logging yang sesuai bagi aplikasi.
Pemilihan otomatis
CameraX otomatis menyediakan fungsionalitas yang berlaku khusus untuk perangkat yang menjalankan aplikasi Anda. Misalnya, CameraX akan otomatis menentukan resolusi terbaik yang akan digunakan jika Anda tidak menentukan resolusi, atau jika resolusi yang Anda tentukan tidak didukung. Semua ini ditangani oleh library sehingga Anda tidak perlu menuliskan kode khusus perangkat.
Sasaran CameraX adalah menginisialisasi sesi kamera dengan sukses. Ini berarti CameraX menerima resolusi dan rasio aspek berdasarkan kemampuan perangkat. Kompromi ini bisa terjadi karena:
- Perangkat tidak mendukung resolusi yang diminta.
- Perangkat memiliki masalah kompatibilitas, seperti perangkat lama yang memerlukan resolusi tertentu agar dapat beroperasi dengan benar.
- Pada beberapa perangkat, format tertentu hanya tersedia pada rasio aspek tertentu.
- Perangkat memiliki preferensi "nearest mod16" untuk encoding JPEG atau
video. Untuk mengetahui informasi selengkapnya, lihat
SCALER_STREAM_CONFIGURATION_MAP
.
Meskipun CameraX membuat dan mengelola sesi, Anda harus selalu memeriksa ukuran gambar yang ditampilkan pada output kasus penggunaan dalam kode Anda dan menyesuaikannya.
Rotasi
Secara default, rotasi kamera disetel agar mengikuti rotasi tampilan default selama pembuatan kasus penggunaan. Dalam kasus default ini, CameraX menghasilkan output yang memungkinkan aplikasi mencocokkan dengan apa yang ingin Anda lihat di pratinjau. Anda dapat mengubah rotasi ke nilai kustom untuk mendukung perangkat multi-tampilan dengan meneruskan orientasi tampilan saat ini saat mengonfigurasi objek kasus penggunaan, atau secara dinamis setelah objek selesai dibuat.
Aplikasi Anda dapat menetapkan rotasi target menggunakan setelan konfigurasi. Kemudian, perangkat dapat memperbarui setelan rotasi menggunakan metode dari API kasus penggunaan (seperti ImageAnalysis.setTargetRotation()
), bahkan saat siklus proses sedang berjalan. Anda dapat menggunakan cara ini saat aplikasi
terkunci ke mode potret sehingga konfigurasi ulang tidak diperlukan saat rotasi
terjadi, tetapi kasus penggunaan pengambilan foto atau analisis gambar perlu informasi
rotasi saat ini dari perangkat. Misalnya, kemampuan mendeteksi rotasi mungkin diperlukan
sehingga
wajah diorientasikan dengan tepat untuk deteksi wajah, atau foto disetel ke mode lanskap
atau potret.
Data untuk gambar yang diambil dapat disimpan tanpa informasi rotasi. Data Exif berisi informasi rotasi sehingga aplikasi galeri dapat menampilkan gambar dalam orientasi yang benar setelah disimpan.
Untuk menampilkan data pratinjau dengan orientasi yang benar, Anda dapat menggunakan output
metadata dari
Preview.PreviewOutput()
untuk membuat transformasi.
Contoh kode berikut menunjukkan cara menentukan rotasi pada peristiwa orientasi:
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(); }
Berdasarkan rotasi yang ditetapkan, setiap kasus penggunaan merotasi data gambar secara langsung atau memberikan metadata rotasi kepada pemakai data gambar yang tidak dirotasi.
- Preview: Output metadata disediakan sehingga rotasi resolusi target diketahui menggunakan
Preview.getTargetRotation()
. - ImageAnalysis: Output metadata disediakan sehingga koordinat buffer gambar diketahui relatif terhadap koordinat tampilan.
- ImageCapture: Metadata Exif gambar, buffering, atau buffering beserta metadata akan diubah untuk mencatat setelan rotasi. Nilai yang diubah bergantung pada implementasi HAL.
Crop rect
Secara default, crop rect merupakan rect buffer penuh. Anda dapat menyesuaikannya dengan
ViewPort
dan
UseCaseGroup
. Dengan mengelompokkan kasus penggunaan dan menyetel area tampilan, CameraX menjamin bahwa crop rect semua
kasus penggunaan dalam grup mengarah ke area yang sama di sensor kamera.
Cuplikan kode berikut menunjukkan cara menggunakan kedua class ini:
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
menentukan rect buffer yang terlihat oleh pengguna akhir. Kemudian CameraX menghitung
kemungkinan crop rect terbesar berdasarkan properti area tampilan dan kasus
penggunaan terlampir. Biasanya, untuk mendapatkan efek WYSIWYG, Anda dapat mengonfigurasi
area tampilan berdasarkan kasus penggunaan pratinjau. Cara mudah untuk mendapatkan area tampilan
adalah dengan menggunakan PreviewView
.
Cuplikan kode berikut menunjukkan cara mendapatkan objek ViewPort
:
Kotlin
val viewport = findViewById<PreviewView>(R.id.preview_view).viewPort
Java
ViewPort viewPort = ((PreviewView)findViewById(R.id.preview_view)).getViewPort();
Pada contoh sebelumnya, objek yang didapat aplikasi dari ImageAnalysis
dan
ImageCapture
cocok dengan yang dilihat pengguna akhir dalam PreviewView
, dengan asumsi
jenis skala PreviewView
ditetapkan ke default, FILL_CENTER
. Setelah menerapkan crop rect dan rotasi ke buffering output, gambar dari semua kasus
penggunaan akan tetap sama, meskipun mungkin dengan resolusi yang berbeda. Untuk
mengetahui informasi selengkapnya tentang cara menerapkan info transformasi, lihat mentransformasi
output.
Pemilihan kamera
CameraX otomatis memilih perangkat kamera terbaik untuk persyaratan dan kasus penggunaan aplikasi Anda. Jika Anda ingin menggunakan perangkat selain yang dipilih untuk Anda, ada beberapa opsi:
- Minta kamera depan default dengan
CameraSelector.DEFAULT_FRONT_CAMERA
. - Minta kamera belakang default dengan
CameraSelector.DEFAULT_BACK_CAMERA
. - Filter daftar perangkat yang tersedia menurut
CameraCharacteristics
denganCameraSelector.Builder.addCameraFilter()
.
Contoh kode berikut menggambarkan cara membuat CameraSelector
untuk
memengaruhi pemilihan perangkat:
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)
Memilih beberapa kamera secara bersamaan
Mulai CameraX 1.3, Anda juga dapat memilih beberapa kamera secara serentak. Misalnya, Anda dapat mengikat ke kamera depan dan belakang untuk mengambil foto atau merekam video dari kedua perspektif secara bersamaan.
Saat menggunakan fitur Kamera Serentak, perangkat dapat mengoperasikan dua kamera
dengan lensa menghadap berbeda secara bersamaan, atau mengoperasikan dua kamera belakang
secara bersamaan. Blok kode berikut menunjukkan cara menetapkan dua kamera saat
memanggil bindToLifecycle
, dan cara mendapatkan kedua objek Kamera dari objek
ConcurrentCamera
yang ditampilkan.
Kotlin
// Build ConcurrentCameraConfig val primary = ConcurrentCamera.SingleCameraConfig( primaryCameraSelector, useCaseGroup, lifecycleOwner ) val secondary = ConcurrentCamera.SingleCameraConfig( secondaryCameraSelector, useCaseGroup, lifecycleOwner ) val concurrentCamera = cameraProvider.bindToLifecycle( listOf(primary, secondary) ) val primaryCamera = concurrentCamera.cameras[0] val secondaryCamera = concurrentCamera.cameras[1]
Java
// Build ConcurrentCameraConfig SingleCameraConfig primary = new SingleCameraConfig( primaryCameraSelector, useCaseGroup, lifecycleOwner ); SingleCameraConfig secondary = new SingleCameraConfig( primaryCameraSelector, useCaseGroup, lifecycleOwner ); ConcurrentCamera concurrentCamera = mCameraProvider.bindToLifecycle(Arrays.asList(primary, secondary)); Camera primaryCamera = concurrentCamera.getCameras().get(0); Camera secondaryCamera = concurrentCamera.getCameras().get(1);
Resolusi kamera
Anda dapat mengizinkan CameraX menyetel resolusi gambar berdasarkan kombinasi kapabilitas perangkat, tingkat hardware yang didukung perangkat, kasus penggunaan, dan rasio aspek yang tersedia. Cara lain, Anda dapat menetapkan resolusi target spesifik atau rasio aspek spesifik dalam kasus penggunaan yang mendukung konfigurasi tersebut.
Resolusi otomatis
CameraX dapat otomatis menentukan setelan resolusi terbaik berdasarkan kasus penggunaan yang ditentukan di cameraProcessProvider.bindToLifecycle()
. Jika
memungkinkan, tentukan semua kasus penggunaan yang diperlukan untuk dijalankan secara bersamaan dalam satu
sesi dalam satu panggilan bindToLifecycle()
. CameraX menentukan resolusi
berdasarkan kumpulan kasus penggunaan dengan mempertimbangkan tingkat hardware yang didukung
perangkat dan dengan memperhitungkan varian khusus perangkat (saat perangkat
melebihi atau tidak memenuhi konfigurasi streaming
tersedia).
Tujuannya agar aplikasi dapat berjalan pada berbagai jenis perangkat sembari
meminimalkan jalur kode khusus perangkat.
Rasio aspek default untuk kasus penggunaan pengambilan gambar dan analisis gambar adalah 4:3.
Kasus penggunaan memiliki rasio aspek yang dapat dikonfigurasi yang memungkinkan aplikasi menentukan rasio aspek yang diinginkan berdasarkan desain UI. Output CameraX dihasilkan untuk dicocokkan dengan rasio aspek yang diminta, yang sedekat mungkin dengan yang didukung perangkat. Jika tidak ada resolusi yang sama persis dengan yang didukung, resolusi yang memenuhi sebagian besar kondisi akan dipilih. Dengan begitu, aplikasi akan menentukan cara kamera ditampilkan pada aplikasi, dan CameraX menentukan setelan resolusi kamera terbaik untuk memenuhi kondisi itu di perangkat berbeda.
Misalnya, aplikasi dapat melakukan salah satu hal berikut:
- Menentukan resolusi target sebesar 4:3 atau 16:9 untuk kasus penggunaan
- Menentukan resolusi khusus yang akan digunakan CameraX untuk menemukan kecocokan terdekat
- Menentukan rasio aspek pemangkasan untuk
ImageCapture
CameraX memilih resolusi permukaan Camera2 internal secara otomatis. Tabel berikut menampilkan berbagai resolusi:
Kasus penggunaan | Resolusi permukaan internal | Resolusi data output |
---|---|---|
Pratinjau | Rasio Lebar Tinggi: Resolusi yang paling sesuai untuk target berdasarkan setelan. | Resolusi permukaan internal. Metadata disediakan agar Tampilan dapat dipangkas, diskalakan, dan dirotasi sesuai rasio aspek target. |
Resolusi default: Resolusi pratinjau tertinggi, atau resolusi tertinggi pilihan perangkat yang cocok dengan rasio aspek Pratinjau. | ||
Resolusi maksimum: Ukuran pratinjau, menunjukkan ukuran yang paling cocok dengan resolusi layar perangkat, atau dengan 1080p (1920x1080), mana pun yang lebih kecil. | ||
Analisis gambar | Rasio lebar tinggi: Resolusi yang paling sesuai untuk target berdasarkan setelan. | Resolusi permukaan internal. |
Resolusi default: Setelan resolusi target default adalah 640x480. Menyesuaikan resolusi target dan rasio aspek yang terkait akan menghasilkan resolusi terbaik yang didukung. | ||
Resolusi maksimum: Resolusi output maksimum perangkat kamera dari format
YUV_420_888 yang diambil dari
StreamConfigurationMap.getOutputSizes() .
Resolusi target disetel ke 640x480 secara default sehingga jika ingin resolusi lebih besar dari 640x480, Anda harus menggunakan
setTargetResolution()
dan
setTargetAspectRatio()
untuk mendapatkan yang terdekat dari resolusi yang didukung.
|
||
Pengambilan gambar | Rasio lebar tinggi: Rasio lebar tinggi yang paling sesuai dengan setelan. | Resolusi permukaan internal. |
Resolusi default: Resolusi tertinggi yang tersedia, atau resolusi tertinggi pilihan perangkat yang cocok dengan rasio aspek ImageCapture. | ||
Resolusi maksimum: Resolusi output maksimum perangkat kamera dalam
format JPEG. Gunakan
StreamConfigurationMap.getOutputSizes()
untuk mengambilnya.
|
Menentukan resolusi
Anda dapat menentukan resolusi tertentu saat membuat kasus penggunaan menggunakan metode setTargetResolution(Size resolution)
, seperti yang ditunjukkan dalam contoh kode berikut:
Kotlin
val imageAnalysis = ImageAnalysis.Builder() .setTargetResolution(Size(1280, 720)) .build()
Java
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder() .setTargetResolution(new Size(1280, 720)) .build();
Anda tidak dapat menetapkan rasio aspek target dan resolusi target pada kasus penggunaan yang
sama. Tindakan ini akan memunculkan IllegalArgumentException
saat mem-build objek
konfigurasi.
Nyatakan Size
resolusi dalam bingkai koordinat
setelah memutar ukuran yang didukung oleh rotasi target. Misalnya,
perangkat yang memiliki orientasi alami potret dengan rotasi target alami yang meminta
gambar potret dapat menetapkan 480x640, dan perangkat yang sama, diputar 90 derajat serta
menargetkan orientasi lanskap dapat menetapkan 640x480.
Resolusi target berupaya menetapkan batas minimum untuk resolusi gambar. Resolusi gambar yang sebenarnya adalah ukuran terdekat yang tersedia, yang tidak lebih kecil dari resolusi target, seperti yang ditentukan oleh penerapan Kamera.
Namun, jika tidak ada resolusi yang sama dengan atau
lebih besar dari resolusi target, resolusi terdekat yang tersedia yang lebih kecil dari
resolusi target akan dipilih. Resolusi dengan rasio aspek
yang sama dengan Size
yang disediakan akan diberi prioritas lebih tinggi daripada resolusi rasio aspek yang
berbeda.
CameraX menerapkan resolusi terbaik yang sesuai berdasarkan permintaan. Jika
kebutuhan utamanya adalah memenuhi rasio aspek, cukup tentukan setTargetAspectRatio
,
dan CameraX akan menentukan resolusi spesifik yang sesuai berdasarkan perangkatnya.
Jika kebutuhan utama aplikasi adalah menentukan resolusi agar pemrosesan gambar
lebih efisien (misalnya gambar kecil atau sedang berdasarkan
kemampuan pemrosesan perangkat), gunakan setTargetResolution(Size resolution)
.
Jika aplikasi Anda memerlukan resolusi yang sama persis, lihat tabel dalam createCaptureSession()
untuk menentukan resolusi maksimum yang didukung oleh setiap tingkat hardware. Untuk memeriksa resolusi spesifik yang didukung oleh perangkat saat ini, lihat StreamConfigurationMap.getOutputSizes(int)
.
Jika aplikasi Anda berjalan di Android 10 atau yang lebih baru, Anda dapat menggunakan
isSessionConfigurationSupported()
untuk memverifikasi SessionConfiguration
spesifik.
Mengontrol output kamera
Selain memungkinkan Anda mengonfigurasi output kamera sesuai kebutuhan untuk setiap kasus penggunaan individual, CameraX juga menerapkan antarmuka berikut untuk mendukung operasi kamera yang umum pada semua kasus penggunaan terikat:
CameraControl
memungkinkan Anda mengonfigurasi fitur kamera umum.CameraInfo
memungkinkan Anda meng-kueri status fitur kamera umum tersebut.
Berikut adalah fitur kamera yang didukung dengan CameraControl:
- Zoom
- Flash
- Fokus dan Pengukuran (ketuk untuk memfokuskan)
- Exposure Compensation
Mendapatkan instance CameraControl dan CameraInfo
Ambil instance CameraControl
dan CameraInfo
menggunakan objek
Camera
yang ditampilkan oleh
ProcessCameraProvider.bindToLifecycle()
.
Kode berikut menampilkan contoh:
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()
Misalnya, Anda dapat mengirimkan operasi zoom dan operasi CameraControl
lainnya setelah
memanggil bindToLifecycle()
. Setelah Anda menghentikan atau menghancurkan aktivitas yang digunakan untuk mengikat
instance kamera, CameraControl
tidak dapat lagi menjalankan operasi dan
menampilkan ListenableFuture
yang gagal.
Zoom
CameraControl menawarkan dua metode untuk mengubah tingkat zoom:
setZoomRatio()
menyetel zoom berdasarkan rasio zoom.Rasio harus berada dalam rentang
CameraInfo.getZoomState().getValue().getMinZoomRatio()
danCameraInfo.getZoomState().getValue().getMaxZoomRatio()
. Jika tidak, fungsi akan menampilkanListenableFuture
yang gagal.setLinearZoom()
menyetel zoom saat ini dengan nilai zoom linier yang berkisar dari 0 hingga 1,0.Keuntungan zoom linier adalah membuat ruang pandang (FOV) berskala dengan perubahan zoom. Ini membuatnya cocok untuk digunakan dengan tampilan
Slider
.
CameraInfo.getZoomState()
menampilkan LiveData dari status zoom saat ini. Nilainya berubah saat kamera
diinisialisasi atau jika tingkat zoom disetel menggunakan setZoomRatio()
atau
setLinearZoom()
. Memanggil salah satu metode akan menetapkan nilai yang mendukung
ZoomState.getZoomRatio()
dan
ZoomState.getLinearZoom()
.
Hal ini berguna jika Anda ingin menampilkan teks rasio zoom di samping penggeser.
Cukup amati ZoomState
LiveData
untuk memperbarui keduanya tanpa perlu melakukan
konversi.
ListenableFuture
yang ditampilkan oleh kedua API menawarkan opsi bagi aplikasi
untuk diberi tahu kapan permintaan berulang dengan nilai zoom yang ditentukan
selesai. Selain itu, jika Anda menetapkan nilai zoom baru saat operasi sebelumnya masih
dijalankan, ListenableFuture
operasi zoom sebelumnya akan langsung
gagal.
Flash
CameraControl.enableTorch(boolean)
mengaktifkan atau menonaktifkan flash (juga dikenal sebagai senter).
CameraInfo.getTorchState()
dapat digunakan untuk meng-kueri status flash saat ini. Anda dapat memeriksa nilai yang ditampilkan
oleh CameraInfo.hasFlashUnit()
untuk menentukan apakah flash tersedia. Jika tidak, memanggil
CameraControl.enableTorch(boolean)
akan menyebabkan ListenableFuture
yang
ditampilkan segera selesai dengan hasil yang gagal dan menyetel status flash ke
TorchState.OFF
.
Saat diaktifkan, flash akan tetap aktif selama pengambilan foto dan video
terlepas dari setelan flashMode. flashMode
di
ImageCapture
hanya berfungsi jika flash dinonaktifkan.
Fokus dan Pengukuran
CameraControl.startFocusAndMetering()
memicu fokus otomatis dan pengukuran eksposur dengan menyetel area pengukuran AF/AE/AWB
berdasarkan FocusMeteringAction yang ditentukan. Ini sering digunakan untuk mengimplementasikan fitur “ketuk
untuk fokus” di banyak aplikasi kamera.
MeteringPoint
Untuk memulai, buat
MeteringPoint
menggunakan
MeteringPointFactory.createPoint(float x, float y, float
size)
.
MeteringPoint
mewakili satu titik pada kamera
Surface
. Ini disimpan dalam bentuk yang dinormalkan
sehingga dapat dengan mudah dikonversi ke koordinat sensor untuk menentukan
area AF/AE/AWB.
Ukuran MeteringPoint
berkisar dari 0 hingga 1 dengan ukuran default
0,15f. Saat memanggil MeteringPointFactory.createPoint(float x, float y, float
size)
, CameraX akan membuat area persegi panjang yang berpusat pada (x, y)
untuk
size
yang disediakan.
Kode berikut menunjukkan cara membuat 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 might 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 dan FocusMeteringAction
Untuk memanggil
startFocusAndMetering()
,
aplikasi harus membangun
FocusMeteringAction
,
yang terdiri dari satu atau beberapa MeteringPoints
dengan kombinasi mode
pengukuran opsional dari
FLAG_AF
,
FLAG_AE
,
FLAG_AWB
. Kode
berikut menunjukkan penggunaan ini:
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 is 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)
Seperti yang ditunjukkan dalam kode sebelumnya,
startFocusAndMetering()
mengambil FocusMeteringAction
yang terdiri dari satu MeteringPoint
untuk area pengukuran
AF/AE/AWB dan satu lagi MeteringPoint hanya untuk AF dan AE.
Secara internal, CameraX mengonversinya menjadi MeteringRectangles
Camera2 dan menyetel parameter
CONTROL_AF_REGIONS
/
CONTROL_AE_REGIONS
/
CONTROL_AWB_REGIONS
yang sesuai ke permintaan pengambilan.
Karena tidak semua perangkat mendukung AF/AE/AWB dan beberapa area, CameraX mengeksekusi
FocusMeteringAction
dengan upaya terbaik. CameraX menggunakan jumlah maksimum
MeteringPoint yang didukung, sesuai urutan penambahan titik. Semua
MeteringPoint ditambahkan setelah jumlah maksimum diabaikan. Misalnya, jika
FocusMeteringAction
dilengkapi dengan 3 MeteringPoint di platform yang hanya mendukung
2 MeteringPoint, hanya 2 MeteringPoint pertama yang akan digunakan. MeteringPoint
terakhir
akan diabaikan oleh CameraX.
Exposure Compensation
Exposure compensation berguna saat aplikasi perlu meningkatkan nilai eksposur (EV) di luar hasil output eksposur otomatis (AE). Nilai exposure compensation digabungkan dengan cara berikut untuk menentukan eksposur yang diperlukan untuk kondisi gambar saat ini:
Exposure = ExposureCompensationIndex * ExposureCompensationStep
CameraX menyediakan
fungsi Camera.CameraControl.setExposureCompensationIndex()
untuk menetapkan exposure compensation sebagai nilai indeks.
Nilai indeks positif membuat gambar lebih cerah, sedangkan nilai negatif meredupkan
gambar. Aplikasi dapat mengkueri rentang yang didukung oleh
CameraInfo.ExposureState.exposureCompensationRange()
yang dijelaskan di bagian berikutnya. Jika nilainya didukung, ListenableFuture
yang ditampilkan
akan selesai saat nilai berhasil diaktifkan dalam
permintaan pengambilan; jika indeks yang ditentukan berada di luar rentang yang didukung,
setExposureCompensationIndex()
akan menyebabkan ListenableFuture
yang ditampilkan segera selesai dengan hasil yang gagal.
CameraX hanya menyimpan permintaan setExposureCompensationIndex()
terbaru yang belum diproses, dan memanggil fungsi beberapa kali sebelum permintaan
sebelumnya menyebabkan eksekusi dibatalkan.
Cuplikan berikut menetapkan indeks exposure compensation dan mendaftarkan callback saat permintaan perubahan eksposur telah dijalankan:
Kotlin
camera.cameraControl.setExposureCompensationIndex(exposureCompensationIndex) .addListener({ // Get the current exposure compensation index, it might 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()
mengambilExposureState
saat ini, termasuk:- Kemampuan dukungan kontrol exposure compensation.
- Indeks exposure compensation saat ini.
- Rentang indeks exposure compensation.
- Langkah exposure compensation yang digunakan dalam penghitungan nilai exposure compensation.
Misalnya, kode berikut menginisialisasi setelan untuk eksposur
SeekBar
dengan nilai ExposureState
saat ini:
Kotlin
val exposureState = camera.cameraInfo.exposureState binding.seekBar.apply { isEnabled = exposureState.isExposureCompensationSupported max = exposureState.exposureCompensationRange.upper min = exposureState.exposureCompensationRange.lower progress = exposureState.exposureCompensationIndex }
Referensi lainnya
Untuk mempelajari CameraX lebih lanjut, lihat referensi tambahan berikut.
Codelab
Contoh kode