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 mempermudah, 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 sebuah kamera, CameraX akan berperilaku seolah-olah kamera tersebut tidak ada. 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, yang memastikan thread utama tidak diblokir dan UI tetap sesuai. 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 akan digunakan melalui CameraXConfig.Builder.setCameraExecutor()
dan CameraXConfig.Builder.setSchedulerHandler()
.
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 lebar tinggi berdasarkan kemampuan perangkat. Kompromi ini mungkin 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 lebar tinggi tertentu.
- Perangkat memiliki preferensi "nearest mod16" untuk encoding JPEG atau video.
Lihat
SCALER_STREAM_CONFIGURATION_MAP
untuk mengetahui informasi selengkapnya.
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 mudah objek 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 akan 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 buffering 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 pandang, 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 pandang dan kasus
penggunaan terlampir. Biasanya, untuk mendapatkan efek WYSIWYG, Anda harus mengonfigurasi
area pandang berdasarkan kasus penggunaan pratinjau. Cara mudah untuk mendapatkan area pandang
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
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)
Resolusi kamera
Anda dapat mengizinkan CameraX menyetel resolusi gambar berdasarkan kombinasi kapabilitas perangkat, tingkat hardware yang didukung perangkat, kasus penggunaan, dan rasio lebar tinggi yang tersedia. Atau, Anda dapat menetapkan resolusi target spesifik atau rasio lebar tinggi 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 akan menentukan resolusi berdasarkan kumpulan kasus penggunaan dengan mempertimbangkan tingkat hardware yang didukung perangkat dan dengan memperhitungkan varian khusus perangkat (di mana perangkat mungkin melebihi atau tidak memenuhi konfigurasi aliran data yang tersedia).
Tujuannya adalah agar aplikasi dapat berjalan pada berbagai jenis perangkat sembari meminimalkan jalur kode khusus perangkat.
Rasio lebar tinggi default untuk kasus penggunaan pengambilan gambar dan analisis gambar adalah 4:3.
Kasus penggunaan memiliki rasio lebar tinggi yang dapat dikonfigurasi yang memungkinkan aplikasi untuk menentukan rasio lebar tinggi yang diinginkan berdasarkan desain UI. Output CameraX akan dihasilkan untuk mengimbangi rasio lebar tinggi 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 menentukan bagaimana 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 lebar tinggi pemangkasan untuk
ImageCapture
CameraX akan 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 View dapat dipangkas, diskala, dan dirotasi sesuai rasio lebar tinggi target. |
Resolusi default: Resolusi pratinjau tertinggi, atau resolusi tertinggi pilihan perangkat yang cocok dengan rasio lebar tinggi di atas. | ||
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 lebar tinggi 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 lebar tinggi di atas. | ||
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 lebar tinggi target dan resolusi target pada kasus penggunaan yang
sama. Melakukannya akan memunculkan IllegalArgumentException
saat membuat
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 sebenarnya akan menjadi resolusi terdekat yang tersedia dalam ukuran yang tidak lebih kecil dari resolusi target, seperti yang ditentukan oleh implementasi 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 lebar tinggi yang sama dengan Size
yang disediakan akan diberi prioritas lebih tinggi daripada resolusi rasio lebar tinggi yang berbeda.
CameraX akan menerapkan resolusi terbaik yang sesuai berdasarkan permintaan. Jika kebutuhan utamanya adalah memenuhi rasio lebar tinggi, 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.bindToLifecyle()
. 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 memastikan ruang pandang (FOV) diskalakan 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 may 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 mem-build 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 will be 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 pada kode di atas, startFocusAndMetering()
membutuhkan FocusMeteringAction
yang terdiri dari satu MeteringPoint
untuk area pengukuran AF/AE/AWB dan MeteringPoint lainnya 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 akan 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 meng-kueri 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 may 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