Bạn định cấu hình từng trường hợp sử dụng CameraX để kiểm soát các chương trình thành phần khác nhau của thao tác trong trường hợp sử dụng.
Ví dụ: Với trường hợp sử dụng tính năng chụp ảnh, bạn có thể đặt tỷ lệ khung hình mục tiêu và chế độ flash. Mã sau đây cho thấy một ví dụ:
Kotlin
val imageCapture = ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build()
Java
ImageCapture imageCapture = new ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build();
Ngoài các lựa chọn về cấu hình, một số trường hợp sử dụng còn cho phép các API linh động thay đổi chế độ cài đặt sau khi trường hợp sử dụng đã được tạo. Để biết thông tin về cấu hình cụ thể cho từng trường hợp sử dụng, hãy xem mục Triển khai bản xem trước, Phân tích hình ảnh và Chụp ảnh.
CameraXConfig
Để dễ sử dụng, CameraX có cấu hình mặc định như các bộ thực thi (executor) và bộ xử lý (handler) nội bộ phù hợp với hầu hết các tình huống sử dụng. Tuy nhiên, nếu ứng dụng của bạn có yêu cầu đặc biệt hoặc muốn tuỳ chỉnh các cấu hình đó, thì CameraXConfig
là giao diện phục vụ mục đích đó.
Với CameraXConfig
, ứng dụng sẽ có khả năng:
- Tối ưu hoá độ trễ khởi động bằng
setAvailableCameraLimiter()
. - Cung cấp bộ thực thi của ứng dụng cho CameraX bằng
setCameraExecutor()
. - Thay thế bộ xử lý trình lập lịch biểu mặc định bằng
setSchedulerHandler()
. - Thay đổi cấp độ ghi nhật ký bằng
setMinimumLoggingLevel()
.
Mô hình sử dụng
Quy trình sau đây mô tả cách sử dụng CameraXConfig
:
- Tạo đối tượng
CameraXConfig
có các cấu hình tuỳ chỉnh của bạn. - Triển khai giao diện
CameraXConfig.Provider
trongApplication
và trả về đối tượngCameraXConfig
tronggetCameraXConfig()
. - Thêm lớp
Application
vào tệpAndroidManifest.xml
, như được mô tả tại đây.
Ví dụ: Mã mẫu sau đây giới hạn phạm vi ghi nhật ký của CameraX chỉ ở thông báo lỗi:
Kotlin
class CameraApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setMinimumLoggingLevel(Log.ERROR).build() } }
Giữ một bản sao cục bộ của đối tượng CameraXConfig
nếu ứng dụng của bạn cần biết cấu hình CameraX sau khi đặt.
Trình giới hạn camera
Trong lần gọi ProcessCameraProvider.getInstance()
đầu tiên, CameraX liệt kê và truy vấn các đặc điểm của camera có trên thiết bị. Vì CameraX cần giao tiếp với các thành phần phần cứng, nên quá trình này có thể làm mỗi camera mất một lượng thời gian không nhỏ, đặc biệt là trên các thiết bị cấp thấp. Nếu ứng dụng của bạn chỉ dùng các camera cụ thể trên thiết bị, chẳng hạn như camera trước mặc định, thì bạn có thể thiết lập cho CameraX bỏ qua các camera khác, nhờ đó giúp giảm độ trễ khởi động cho các camera mà ứng dụng của bạn dùng.
Nếu CameraSelector
truyền đến CameraXConfig.Builder.setAvailableCamerasLimiter()
lọc ra một camera, thì CameraX sẽ hoạt động như thể không có camera đó. Ví dụ: Mã sau đây giới hạn ứng dụng chỉ dùng camera sau mặc định của thiết bị:
Kotlin
class MainApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setAvailableCamerasLimiter(CameraSelector.DEFAULT_BACK_CAMERA) .build() } }
Luồng
Nhiều API nền tảng là cơ sở xây dựng CameraX yêu cầu chặn giao tiếp liên quy trình (IPC) bằng phần cứng. Quá trình này đôi khi có thể mất hàng trăm mili giây để phản hồi. Do đó, CameraX chỉ gọi những API này từ các luồng trong nền để luồng chính không bị chặn và giao diện người dùng vẫn linh hoạt. CameraX quản lý nội bộ các luồng trong nền này để hoạt động này xuất hiện minh bạch. Tuy nhiên, một số ứng dụng yêu cầu kiểm soát nghiêm ngặt các luồng. CameraXConfig
cho phép ứng dụng đặt các luồng trong nền được dùng thông qua CameraXConfig.Builder.setCameraExecutor()
và CameraXConfig.Builder.setSchedulerHandler()
.
Bộ thực thi camera
Bộ thực thi camera được dùng cho mọi lệnh gọi API nền tảng Camera nội bộ, cũng như cho các lệnh gọi lại từ những API này. CameraX phân bổ và quản lý một Executor
nội bộ để thực hiện những nhiệm vụ này.
Tuy nhiên, nếu ứng dụng của bạn yêu cầu kiểm soát luồng nghiêm ngặt hơn, hãy dùng CameraXConfig.Builder.setCameraExecutor()
.
Bộ xử lý trình lập lịch biểu
Bộ xử lý trình lập lịch biểu dùng để lên lịch các nhiệm vụ nội bộ trong những khoảng thời gian cố định, chẳng hạn như thử mở lại camera khi camera không dùng được. Bộ xử lý này không thực thi các tác vụ mà chỉ gửi chúng đến bộ thực thi camera. Đôi khi, bộ xử lý này cũng được dùng trên các nền tảng API cũ yêu cầu phải có Handler
để gọi lại. Trong những trường hợp này, lệnh gọi lại vẫn chỉ được gửi trực tiếp đến bộ thực thi camera. CameraX phân bổ và quản lý một HandlerThread
nội bộ để thực hiện những nhiệm vụ này, nhưng bạn có thể ghi đè bằng CameraXConfig.Builder.setSchedulerHandler()
.
Ghi nhật ký
Tính năng ghi nhật ký CameraX cho phép các ứng dụng lọc thông báo logcat vì điều này có thể giúp bạn tránh được các thông báo chi tiết trong mã phát hành chính thức. CameraX hỗ trợ 4 cấp độ ghi nhật ký, từ chi tiết nhất đến nghiêm trọng nhất:
Log.DEBUG
(mặc định)Log.INFO
Log.WARN
Log.ERROR
Tham khảo tài liệu về Nhật ký Android để biết thông tin mô tả chi tiết về các cấp độ nhật ký này. Dùng CameraXConfig.Builder.setMinimumLoggingLevel(int)
để đặt cấp độ ghi nhật ký thích hợp cho ứng dụng của bạn.
Tự động chọn
CameraX tự động cung cấp chức năng dành riêng cho thiết bị mà ứng dụng của bạn đang chạy. Ví dụ: CameraX sẽ tự động xác định độ phân giải tốt nhất để sử dụng nếu bạn không chỉ định độ phân giải hoặc nếu độ phân giải mà bạn chỉ định không được hỗ trợ. Tất cả những việc này đều do thư viện xử lý, giúp bạn không cần ghi mã dành riêng cho thiết bị.
Mục tiêu của CameraX là khởi chạy thành công một phiên camera. Nói cách khác, CameraX sẽ điều chỉnh độ phân giải và tỷ lệ khung hình dựa trên tính năng của thiết bị. Quá trình điều chỉnh có thể diễn ra vì:
- Thiết bị không hỗ trợ độ phân giải mà bạn yêu cầu.
- Thiết bị gặp các vấn đề về khả năng tương thích, chẳng hạn như các thiết bị cũ yêu cầu độ phân giải nhất định thì mới hoạt động chính xác.
- Một số thiết bị chỉ có một số định dạng theo tỷ lệ khung hình nhất định.
- Thiết bị có lựa chọn ưu tiên "nearest mod16" (mod16 gần nhất) để mã hoá tệp JPEG hoặc video. Để biết thêm thông tin, hãy xem
SCALER_STREAM_CONFIGURATION_MAP
.
Mặc dù CameraX tạo và quản lý phiên nhưng hãy luôn kiểm tra kích thước hình ảnh được trả về ở dữ liệu đầu ra của trường hợp sử dụng trong mã và điều chỉnh sao cho phù hợp.
Chế độ xoay
Theo mặc định, chế độ xoay của camera được đặt để khớp với chế độ xoay của màn hình mặc định trong khi tạo trường hợp sử dụng. Trong trường hợp mặc định này, CameraX sẽ tạo ra các kết quả đầu ra để cho phép ứng dụng khớp với những gì bạn muốn thấy trong bản xem trước. Bạn có thể thay đổi chế độ xoay thành một giá trị tuỳ chỉnh để hỗ trợ các thiết bị nhiều màn hình bằng cách truyền hướng màn hình hiện tại khi định cấu hình các đối tượng trường hợp sử dụng hoặc truyền linh động sau khi tạo các đối tượng đó.
Ứng dụng của bạn có thể đặt chế độ xoay mục tiêu thông qua các chế độ cài đặt cấu hình. Khi đó, ứng dụng có thể cập nhật chế độ cài đặt xoay bằng cách sử dụng các phương thức trong API trường hợp sử dụng (chẳng hạn như ImageAnalysis.setTargetRotation()
), ngay cả khi vòng đời ở trạng thái đang chạy. Bạn có thể sử dụng tính năng này khi ứng dụng bị khoá ở chế độ chân dung, do đó không có hoạt động định cấu hình lại nào diễn ra khi xoay, nhưng trường hợp sử dụng ảnh hoặc phân tích cần biết về chế độ xoay hiện tại của thiết bị. Ví dụ: Ứng dụng có thể cần nhận biết chế độ xoay để các khuôn mặt được đặt đúng hướng giúp phát hiện khuôn mặt hoặc ảnh được đặt ở chế độ ngang hoặc chân dung.
Dữ liệu cho hình ảnh đã chụp có thể được lưu trữ mà không có thông tin về chế độ xoay. Dữ liệu Exif chứa thông tin về chế độ xoay để các ứng dụng thư viện có thể hiển thị hình ảnh theo đúng hướng sau khi lưu.
Để hiển thị dữ liệu xem trước theo đúng hướng, bạn có thể sử dụng đầu ra siêu dữ liệu từ Preview.PreviewOutput()
để tạo ra sự biến đổi.
Mã mẫu sau đây cho biết cách cài đặt chế độ xoay trên một sự kiện (event) hướng:
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(); }
Dựa trên chế độ xoay đã đặt, mỗi trường hợp sử dụng sẽ trực tiếp xoay dữ liệu hình ảnh hoặc cung cấp siêu dữ liệu về chế độ xoay cho người dùng dữ liệu hình ảnh không xoay.
- Xem trước: Đầu ra siêu dữ liệu được cung cấp để xác định chế độ xoay độ phân giải mục tiêu bằng cách sử dụng
Preview.getTargetRotation()
. - ImageAnalysis: Đầu ra siêu dữ liệu được cung cấp để xác định toạ độ vùng đệm hình ảnh so với toạ độ màn hình hiển thị.
- ImageCapture: Siêu dữ liệu, vùng đệm Exif hình ảnh hoặc cả vùng đệm và siêu dữ liệu sẽ được thay đổi để ghi chú lại cách cài đặt chế độ xoay. Giá trị thay đổi tuỳ thuộc vào việc triển khai HAL (Lớp trừu tượng phần cứng).
Kích cỡ khuôn hình chữ nhật cắt ảnh
Theo mặc định, kích cỡ khuôn hình chữ nhật cắt ảnh là kích cỡ khuôn hình chữ nhật vùng đệm đầy đủ. Bạn có thể tuỳ chỉnh kích cỡ khuôn hình chữ nhật cắt ảnh bằng
ViewPort
và
UseCaseGroup
. Bằng cách nhóm các trường hợp sử dụng và cài đặt khung nhìn, CameraX đảm bảo rằng kích cỡ khuôn hình chữ nhật cắt ảnh của tất cả các trường hợp sử dụng trong nhóm đó trỏ đến cùng một khu vực trong cảm biến của camera.
Đoạn mã sau đây cho thấy cách sử dụng hai lớp này:
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
xác định kích cỡ khuôn hình chữ nhật vùng đệm mà người dùng cuối nhìn thấy. Sau đó, CameraX tính toán kích cỡ khuôn hình chữ nhật cắt ảnh lớn nhất có thể dựa trên các thuộc tính của khung nhìn và các trường hợp sử dụng đính kèm. Thông thường, để đạt được hiệu ứng WYSIWYG, bạn có thể định cấu hình khung nhìn dựa trên trường hợp sử dụng xem trước. Một cách đơn giản để tải khung nhìn là sử dụng PreviewView
.
Các đoạn mã sau đây cho thấy cách tải đối tượng ViewPort
:
Kotlin
val viewport = findViewById<PreviewView>(R.id.preview_view).viewPort
Java
ViewPort viewPort = ((PreviewView)findViewById(R.id.preview_view)).getViewPort();
Trong ví dụ trước, kết quả ứng dụng nhận được từ ImageAnalysis
và ImageCapture
khớp với kết quả mà người dùng cuối nhìn thấy trong PreviewView
, giả sử loại tỷ lệ của PreviewView
được đặt thành giá trị mặc định, FILL_CENTER
. Sau khi áp dụng kích cỡ khuôn hình chữ nhật cắt ảnh và chế độ xoay cho vùng đệm đầu ra, hình ảnh trong tất cả các trường hợp sử dụng sẽ giống nhau, mặc dù có thể có độ phân giải khác nhau. Để biết thêm thông tin về cách áp dụng thông tin biến đổi, hãy xem đầu ra biến đổi.
Lựa chọn camera
CameraX tự động lựa chọn thiết bị camera phù hợp nhất với các trường hợp sử dụng và yêu cầu của ứng dụng. Nếu muốn sử dụng một thiết bị khác với thiết bị được chọn cho mình, bạn có một số lựa chọn:
- Yêu cầu camera mặt trước mặc định bằng
CameraSelector.DEFAULT_FRONT_CAMERA
. - Yêu cầu camera mặt sau mặc định bằng
CameraSelector.DEFAULT_BACK_CAMERA
. - Lọc danh sách các thiết bị có sẵn theo
CameraCharacteristics
của thiết bị bằngCameraSelector.Builder.addCameraFilter()
.
Mã mẫu sau đây minh hoạ cách tạo một CameraSelector
để tác động đến việc lựa chọn thiết bị:
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)
Chọn đồng thời nhiều camera
Kể từ CameraX 1.3, bạn cũng có thể chọn đồng thời nhiều camera. Ví dụ: bạn có thể liên kết với camera trước và sau để chụp ảnh hoặc quay video đồng thời từ cả hai góc nhìn.
Khi dùng tính năng Camera đồng thời, thiết bị có thể vận hành cùng lúc 2 camera trước và sau hoặc 2 camera sau. Khối mã sau đây cho biết cách đặt 2 camera khi gọi bindToLifecycle
và cách lấy cả hai đối tượng Camera từ đối tượng ConcurrentCamera
được trả về.
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);
Độ phân giải của camera
Bạn có thể chọn cho phép CameraX đặt độ phân giải hình ảnh dựa trên tổ hợp tính năng của thiết bị, cấp độ phần cứng được hỗ trợ của thiết bị, trường hợp sử dụng và tỷ lệ khung hình được cung cấp. Ngoài ra, bạn có thể đặt độ phân giải mục tiêu cụ thể hoặc tỷ lệ khung hình cụ thể trong các trường hợp sử dụng hỗ trợ cấu hình đó.
Độ phân giải tự động
CameraX có thể tự động xác định các chế độ cài đặt độ phân giải tốt nhất dựa trên các trường hợp sử dụng được chỉ định trong cameraProcessProvider.bindToLifecycle()
. Bất cứ khi nào có thể, hãy chỉ định tất cả các trường hợp sử dụng cần thiết để chạy đồng thời trong một phiên duy nhất ở một lệnh gọi bindToLifecycle()
duy nhất. CameraX sẽ xác định độ phân giải dựa trên nhóm trường hợp sử dụng bị ràng buộc bằng cách xem xét cấp độ phần cứng được hỗ trợ của thiết bị và tính đến phương sai dành riêng cho thiết bị (trong đó thiết bị có thể vượt quá hoặc không đáp ứng cấu hình luồng có sẵn).
Mục đích là để ứng dụng chạy trên nhiều loại thiết bị, đồng thời giảm thiểu các đường dẫn mã dành riêng cho thiết bị.
Tỷ lệ khung hình mặc định cho các trường hợp sử dụng tính năng chụp ảnh và phân tích hình ảnh là 4:3.
Các trường hợp sử dụng có tỷ lệ khung hình có thể định cấu hình để cho phép ứng dụng chỉ định tỷ lệ khung hình mong muốn dựa trên thiết kế giao diện người dùng. Đầu ra CameraX được tạo để khớp với tỷ lệ khung hình theo yêu cầu ở mức tối đa mà thiết bị hỗ trợ. Nếu không có độ phân giải khớp chính xác được hỗ trợ, thì độ phân giải đáp ứng nhiều điều kiện nhất sẽ được chọn. Do đó, ứng dụng sẽ chỉ ra cách camera xuất hiện trong ứng dụng và CameraX xác định chế độ cài đặt độ phân giải tốt nhất cho camera để đáp ứng điều đó trên các thiết bị khác nhau.
Ví dụ: Một ứng dụng có thể thực hiện bất kỳ thao tác nào sau đây:
- Chỉ định độ phân giải mục tiêu là 4:3 hoặc 16:9 cho một trường hợp sử dụng
- Chỉ định độ phân giải tuỳ chỉnh mà CameraX cố gắng tìm kết quả khớp nhất
- Chỉ định tỷ lệ khung hình cắt ảnh cho
ImageCapture
CameraX tự động chọn độ phân giải bề mặt Camera2 bên trong. Bảng sau đây trình bày các độ phân giải:
Trường hợp sử dụng | Độ phân giải bề mặt bên trong | Độ phân giải dữ liệu đầu ra |
---|---|---|
Xem trước | Tỷ lệ khung hình: Độ phân giải giúp mục tiêu phù hợp nhất với chế độ cài đặt. | Độ phân giải bề mặt bên trong. Siêu dữ liệu được cung cấp để cho phép Khung hiển thị cắt, điều chỉnh theo tỷ lệ và xoay để đạt được tỷ lệ khung hình mục tiêu. |
Độ phân giải mặc định: Độ phân giải cao nhất của bản xem trước hoặc độ phân giải cao nhất mà thiết bị ưu tiên khớp với tỷ lệ khung hình của Bản xem trước. | ||
Độ phân giải tối đa: Kích thước bản xem trước, tức là kích thước phù hợp nhất với độ phân giải màn hình của thiết bị hoặc với độ phân giải 1080p (1920x1080), tuỳ theo kích thước nào nhỏ hơn. | ||
Phân tích hình ảnh | Tỷ lệ khung hình: Độ phân giải giúp mục tiêu phù hợp nhất với chế độ cài đặt. | Độ phân giải bề mặt bên trong. |
Độ phân giải mặc định: Chế độ cài đặt độ phân giải mục tiêu mặc định là 640x480. Việc điều chỉnh cả độ phân giải mục tiêu và tỷ lệ khung hình tương ứng sẽ dẫn đến độ phân giải được hỗ trợ tốt nhất. | ||
Độ phân giải tối đa: Độ phân giải đầu ra tối đa của thiết bị camera ở định dạng YUV_420_888 được lấy từ StreamConfigurationMap.getOutputSizes() .
Theo mặc định, độ phân giải mục tiêu được đặt là 640x480, nên nếu muốn có độ phân giải lớn hơn 640x480, bạn phải sử dụng setTargetResolution() và setTargetAspectRatio() để lấy giá trị gần nhất trong số các độ phân giải được hỗ trợ.
|
||
Chụp ảnh | Tỷ lệ khung hình: Tỷ lệ khung hình phù hợp nhất với chế độ cài đặt. | Độ phân giải bề mặt bên trong. |
Độ phân giải mặc định: Độ phân giải cao nhất hiện có hoặc độ phân giải cao nhất mà thiết bị ưu tiên khớp với tỷ lệ khung hình của ImageCapture. | ||
Độ phân giải tối đa: Độ phân giải đầu ra tối đa của thiết bị camera ở định dạng JPEG. Sử dụng StreamConfigurationMap.getOutputSizes() để truy xuất dữ liệu này.
|
Chỉ định độ phân giải
Bạn có thể đặt độ phân giải cụ thể khi xây dựng các trường hợp sử dụng bằng cách sử dụng phương thức setTargetResolution(Size resolution)
, như trong mã mẫu sau đây:
Kotlin
val imageAnalysis = ImageAnalysis.Builder() .setTargetResolution(Size(1280, 720)) .build()
Java
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder() .setTargetResolution(new Size(1280, 720)) .build();
Bạn không thể đặt cả tỷ lệ khung hình mục tiêu và độ phân giải mục tiêu cho cùng một trường hợp sử dụng. Thao tác này sẽ gửi một IllegalArgumentException
khi tạo đối tượng cấu hình.
Nêu rõ độ phân giải Size
trong khung toạ độ sau khi xoay các kích thước được hỗ trợ bằng chế độ xoay mục tiêu. Ví dụ: Một thiết bị có hướng mặc định theo chiều dọc đang xoay mục tiêu mặc định cần hình ảnh dọc có thể chỉ định 480x640, thiết bị tương tự được xoay 90 độ và nhắm mục tiêu đến hướng ngang có thể chỉ định 640x480.
Độ phân giải mục tiêu cố gắng thiết lập một giới hạn tối thiểu cho độ phân giải hình ảnh. Độ phân giải hình ảnh thực tế là độ phân giải có sẵn gần nhất về kích thước không nhỏ hơn độ phân giải mục tiêu, như được xác định trong quá trình triển khai Máy ảnh.
Tuy nhiên, nếu không có độ phân giải nào bằng hoặc lớn hơn độ phân giải mục tiêu, thì độ phân giải có sẵn gần nhất nhỏ hơn độ phân giải mục tiêu sẽ được chọn. Các độ phân giải có cùng tỷ lệ khung hình Size
được cung cấp sẽ được ưu tiên hơn so với các độ phân giải có nhiều tỷ lệ khung hình.
Dựa trên yêu cầu, CameraX áp dụng độ phân giải phù hợp nhất. Nếu nhu cầu chính là để đáp ứng tỷ lệ khung hình, thì chỉ xác định setTargetAspectRatio
, còn CameraX sẽ xác định độ phân giải cụ thể phù hợp với thiết bị.
Nếu nhu cầu chính của ứng dụng là chỉ định độ phân giải để xử lý hình ảnh hiệu quả hơn (ví dụ: hình ảnh cỡ nhỏ hoặc cỡ trung dựa trên tính năng xử lý của thiết bị), thì sử dụng setTargetResolution(Size resolution)
.
Nếu ứng dụng của bạn yêu cầu độ phân giải chính xác thì hãy xem bảng trong createCaptureSession()
để xác định độ phân giải tối đa được hỗ trợ theo từng cấp độ phần cứng. Để kiểm tra các độ phân giải cụ thể mà thiết bị hiện tại hỗ trợ, xem StreamConfigurationMap.getOutputSizes(int)
.
Nếu ứng dụng của bạn đang chạy trên Android 10 trở lên, bạn có thể sử dụng isSessionConfigurationSupported()
để xác minh một SessionConfiguration
cụ thể.
Kiểm soát đầu ra của camera
Ngoài việc cho phép bạn định cấu hình đầu ra của camera theo nhu cầu cho từng trường hợp sử dụng, CameraX còn triển khai các giao diện sau đây để hỗ trợ các thao tác của camera phổ biến cho tất cả các trường hợp sử dụng ràng buộc:
CameraControl
cho phép bạn định cấu hình các tính năng phổ biến của camera.CameraInfo
cho phép bạn truy vấn trạng thái của những tính năng phổ biến đó của camera.
Sau đây là các tính năng camera được hỗ trợ với CameraControl:
- Zoom (thu phóng)
- Đèn pin
- Lấy nét và đo sáng (nhấn để lấy nét)
- Bù phơi sáng
Nhận thực thể của CameraControl và CameraInfo
Truy xuất các thực thể của CameraControl
và CameraInfo
bằng cách sử dụng đối tượng Camera
do ProcessCameraProvider.bindToLifecycle()
trả về.
Mã sau đây cho thấy một ví dụ:
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()
Ví dụ: Bạn có thể gửi thao tác thu phóng và các thao tác CameraControl
khác sau khi gọi bindToLifecycle()
. Sau khi bạn dừng hoặc huỷ bỏ hoạt động dùng để liên kết thực thể camera, CameraControl
sẽ không thực thi được các thao tác nữa và trả về một ListenableFuture
không thành công.
Zoom (thu phóng)
CameraControl cung cấp 2 phương thức thay đổi mức thu phóng:
setZoomRatio()
đặt mức thu phóng theo tỷ lệ thu phóng.Tỷ lệ này phải nằm trong phạm vi từ
CameraInfo.getZoomState().getValue().getMinZoomRatio()
đếnCameraInfo.getZoomState().getValue().getMaxZoomRatio()
. Nếu không, hàm sẽ trả vềListenableFuture
không thành công.setLinearZoom()
đặt mức thu phóng hiện tại với giá trị thu phóng tuyến tính trong khoảng từ 0 đến 1.Ưu điểm của tính năng thu phóng tuyến tính là giúp mở rộng phạm vi của trường nhìn (FOV) với sự thay đổi về mức thu phóng. Nhờ vậy mà đây là tính năng lý tưởng để sử dụng với chế độ xem
Slider
.
CameraInfo.getZoomState()
trả về một LiveData của trạng thái thu phóng hiện tại. Giá trị thay đổi khi camera được khởi chạy hoặc nếu mức thu phóng được đặt bằng setZoomRatio()
hoặc setLinearZoom()
. Khi gọi một trong hai phương thức, bạn sẽ đặt giá trị hỗ trợ ZoomState.getZoomRatio()
và ZoomState.getLinearZoom()
.
Việc này rất hữu ích nếu bạn muốn hiển thị văn bản tỷ lệ thu phóng cùng với thanh trượt.
Chỉ cần quan sát ZoomState
LiveData
để cập nhật cả hai mà không cần thực hiện chuyển đổi.
ListenableFuture
mà cả hai API trả về đều cung cấp cho ứng dụng tuỳ chọn nhận thông báo khi hoàn tất yêu cầu lặp lại với giá trị thu phóng được chỉ định. Ngoài ra, nếu bạn đặt một giá trị thu phóng mới trong khi thao tác trước đó vẫn đang thực thi, ListenableFuture
của thao tác thu phóng trước đó sẽ ngay lập tức bị lỗi.
Đèn pin
CameraControl.enableTorch(boolean)
bật hoặc tắt đèn pin (còn gọi là đèn flash).
Bạn có thể dùng CameraInfo.getTorchState()
để truy vấn trạng thái đèn pin hiện tại. Bạn có thể kiểm tra giá trị được CameraInfo.hasFlashUnit()
trả về để xác định xem có đèn pin hay không. Nếu không, thao tác gọi CameraControl.enableTorch(boolean)
khiến ListenableFuture
được trả về ngay lập tức hoàn tất với kết quả không thành công và đặt trạng thái đèn pin thành TorchState.OFF
.
Khi được bật, đèn pin sẽ vẫn duy trì trạng thái bật trong khi chụp ảnh và quay video bất kể chế độ cài đặt flashMode. flashMode
trong ImageCapture
chỉ hoạt động khi đèn pin tắt.
Lấy nét và đo sáng
CameraControl.startFocusAndMetering()
kích hoạt chế độ tự động lấy nét và đo độ phơi sáng bằng cách đặt vùng đo sáng AF/AE/AWB dựa trên FocusMeteringAction đã cho. Tính năng này thường dùng để triển khai tính năng "tap to focus" (nhấn để lấy nét) trong nhiều ứng dụng camera.
MeteringPoint
Để bắt đầu, hãy tạo một MeteringPoint
bằng MeteringPointFactory.createPoint(float x, float y, float
size)
.
MeteringPoint
đại diện cho một điểm duy nhất trên camera Surface
. Điểm này được lưu trữ ở dạng chuẩn hoá để có thể dễ dàng chuyển đổi sang toạ độ cảm biến nhằm chỉ định vùng AF/AE/AWB.
Kích thước của MeteringPoint
dao động từ 0 đến 1, với kích thước mặc định là 0,15f. Khi gọi MeteringPointFactory.createPoint(float x, float y, float
size)
, CameraX sẽ tạo một vùng hình chữ nhật có tâm tại (x, y)
cho size
được cung cấp.
Mã sau đây minh hoạ cách tạo 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 và FocusMeteringAction
Để gọi startFocusAndMetering()
, các ứng dụng phải tạo một FocusMeteringAction
, bao gồm một hoặc nhiều MeteringPoints
có kết hợp chế độ đo sáng không bắt buộc từ FLAG_AF
, FLAG_AE
, FLAG_AWB
. Mã sau đây minh hoạ cách sử dụng này:
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)
Như đã trình bày trong mã trước, startFocusAndMetering()
sẽ lấy một FocusMeteringAction
bao gồm một MeteringPoint
cho vùng đo sáng AF/AE/AWB và một vùng khác MeteringPoint chỉ dành cho AF và AE.
Trong nội bộ, CameraX chuyển đổi mã thành Camera2 MeteringRectangles
và đặt các tham số CONTROL_AF_REGIONS
/ CONTROL_AE_REGIONS
/ CONTROL_AWB_REGIONS
tương ứng với yêu cầu chụp.
Vì không phải mọi thiết bị đều hỗ trợ AF/AE/AWB và nhiều vùng, nên CameraX cố gắng nhất có thể để thực thi FocusMeteringAction
. CameraX sử dụng số lượng MeteringPoint tối đa được hỗ trợ, theo thứ tự thêm điểm. Tất cả MeteringPoint được thêm sau khi bỏ qua số lượng tối đa. Ví dụ: Nếu FocusMeteringAction
được cung cấp cùng với 3 MeteringPoint trên nền tảng chỉ hỗ trợ 2, thì chỉ 2 MeteringPoint đầu tiên được sử dụng. MeteringPoint
cuối cùng bị CameraX bỏ qua.
Bù phơi sáng
Tính năng bù phơi sáng rất hữu ích khi các ứng dụng cần tinh chỉnh các giá trị phơi sáng (EV) ngoài kết quả đầu ra phơi sáng tự động (AE). Các giá trị bù phơi sáng được kết hợp theo cách sau để xác định mức phơi sáng cần thiết cho các điều kiện hình ảnh hiện tại:
Exposure = ExposureCompensationIndex * ExposureCompensationStep
CameraX cung cấp chức năng Camera.CameraControl.setExposureCompensationIndex()
để đặt giá trị bù phơi sáng dưới dạng trị số.
Trị số dương làm cho hình ảnh sáng hơn, trong khi trị số âm làm mờ hình ảnh. Các ứng dụng có thể truy vấn phạm vi được hỗ trợ bằng CameraInfo.ExposureState.exposureCompensationRange()
như được mô tả trong phần tiếp theo. Nếu giá trị được hỗ trợ, ListenableFuture
được trả về sẽ hoàn tất khi giá trị được bật thành công trong yêu cầu chụp; nếu trị số đã chỉ định nằm ngoài phạm vi được hỗ trợ, setExposureCompensationIndex()
sẽ khiến ListenableFuture
được trả về ngay lập tức hoàn tất với kết quả không thành công.
CameraX chỉ giữ lại yêu cầu setExposureCompensationIndex()
chưa xử lý mới nhất và gọi hàm nhiều lần trước khi yêu cầu trước đó được thực thi dẫn đến việc huỷ bỏ.
Đoạn mã sau đây sẽ thiết lập một trị số bù phơi sáng và đăng ký một lệnh gọi lại khi đã thực thi yêu cầu thay đổi độ phơi sáng:
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()
truy xuấtExposureState
hiện tại, bao gồm:- Khả năng hỗ trợ của tính năng kiểm soát bù phơi sáng.
- Trị số bù phơi sáng hiện tại.
- Phạm vi trị số bù phơi sáng.
- Bước bù phơi sáng được dùng trong phép tính giá trị bù phơi sáng.
Ví dụ: Mã sau đây khởi chạy chế độ cài đặt cho SeekBar
phơi sáng với các giá trị ExposureState
hiện tại:
Kotlin
val exposureState = camera.cameraInfo.exposureState binding.seekBar.apply { isEnabled = exposureState.isExposureCompensationSupported max = exposureState.exposureCompensationRange.upper min = exposureState.exposureCompensationRange.lower progress = exposureState.exposureCompensationIndex }
Tài nguyên khác
Để tìm hiểu thêm về CameraX, hãy tham khảo các tài liệu bổ sung sau đây.
Lớp học lập trình
Đoạn mã mẫu
Cộng đồng các nhà phát triển
Nhóm thảo luận của Android CameraX