Вы настраиваете каждый вариант использования CameraX для управления различными аспектами операций варианта использования.
Например, в случае использования захвата изображения вы можете задать целевое соотношение сторон и режим вспышки. Следующий код показывает один пример:
Котлин
val imageCapture = ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build()
Ява
ImageCapture imageCapture = new ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build();
В дополнение к параметрам конфигурации, некоторые варианты использования предоставляют API для динамического изменения настроек после создания варианта использования. Для получения информации о конфигурации, которая является специфичной для отдельных вариантов использования, см. Реализация предварительного просмотра , Анализ изображений и Захват изображений .
CameraXConfig
Для простоты CameraX имеет конфигурации по умолчанию, такие как внутренние исполнители и обработчики, которые подходят для большинства сценариев использования. Однако, если ваше приложение имеет особые требования или предпочитает настраивать эти конфигурации, CameraXConfig
— это интерфейс для этой цели.
С помощью CameraXConfig
приложение может выполнять следующие действия:
- Оптимизируйте задержку запуска с помощью
setAvailableCameraLimiter()
. - Предоставьте исполнителю приложения CameraX функцию
setCameraExecutor()
. - Замените обработчик планировщика по умолчанию на
setSchedulerHandler()
. - Измените уровень ведения журнала с помощью
setMinimumLoggingLevel()
.
Модель использования
Следующая процедура описывает, как использовать CameraXConfig
:
- Создайте объект
CameraXConfig
с вашими индивидуальными конфигурациями. - Реализуйте интерфейс
CameraXConfig.Provider
в своемApplication
и верните объектCameraXConfig
вgetCameraXConfig()
. - Добавьте класс
Application
в файлAndroidManifest.xml
, как описано здесь .
Например, следующий пример кода ограничивает регистрацию CameraX только сообщениями об ошибках:
Котлин
class CameraApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setMinimumLoggingLevel(Log.ERROR).build() } }
Сохраните локальную копию объекта CameraXConfig
, если вашему приложению необходимо знать конфигурацию CameraX после ее настройки.
Ограничитель камеры
Во время первого вызова ProcessCameraProvider.getInstance()
CameraX перечисляет и запрашивает характеристики камер, доступных на устройстве. Поскольку CameraX необходимо взаимодействовать с аппаратными компонентами, этот процесс может занять нетривиальное количество времени для каждой камеры, особенно на бюджетных устройствах. Если ваше приложение использует только определенные камеры на устройстве, например фронтальную камеру по умолчанию, вы можете настроить CameraX на игнорирование других камер, что может сократить задержку запуска для камер, используемых вашим приложением.
Если CameraSelector
, переданный в CameraXConfig.Builder.setAvailableCamerasLimiter()
отфильтровывает камеру, CameraX ведет себя так, как будто эта камера не существует. Например, следующий код ограничивает приложение, чтобы использовать только заднюю камеру устройства по умолчанию:
Котлин
class MainApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setAvailableCamerasLimiter(CameraSelector.DEFAULT_BACK_CAMERA) .build() } }
Темы
Многие API платформы, на которых построен CameraX, требуют блокировки межпроцессного взаимодействия (IPC) с оборудованием, на ответ которого иногда могут уходить сотни миллисекунд. По этой причине CameraX вызывает эти API только из фоновых потоков, чтобы основной поток не блокировался, а пользовательский интерфейс оставался текучим. CameraX внутренне управляет этими фоновыми потоками, так что это поведение кажется прозрачным. Однако некоторые приложения требуют строгого контроля потоков. CameraXConfig
позволяет приложению устанавливать фоновые потоки, которые используются через CameraXConfig.Builder.setCameraExecutor()
и CameraXConfig.Builder.setSchedulerHandler()
.
Исполнитель камеры
Исполнитель камеры используется для всех внутренних вызовов API платформы Camera, а также для обратных вызовов из этих API. CameraX выделяет и управляет внутренним Executor
для выполнения этих задач. Однако, если ваше приложение требует более строгого контроля потоков, используйте CameraXConfig.Builder.setCameraExecutor()
.
Планировщик-обработчик
Обработчик планировщика используется для планирования внутренних задач с фиксированными интервалами, например, повторной попытки открытия камеры, когда она недоступна. Этот обработчик не выполняет задания, а только отправляет их исполнителю камеры. Он также иногда используется на устаревших платформах API, которым требуется Handler
для обратных вызовов. В этих случаях обратные вызовы по-прежнему отправляются только напрямую исполнителю камеры. CameraX выделяет и управляет внутренним HandlerThread
для выполнения этих задач, но вы можете переопределить его с помощью CameraXConfig.Builder.setSchedulerHandler()
.
Ведение журнала
Ведение журнала CameraX позволяет приложениям фильтровать сообщения logcat, поскольку это может быть хорошей практикой — избегать подробных сообщений в вашем производственном коде. CameraX поддерживает четыре уровня ведения журнала, от самого подробного до самого строгого:
-
Log.DEBUG
(по умолчанию) -
Log.INFO
-
Log.WARN
-
Log.ERROR
Подробные описания этих уровней журналирования см. в документации Android Log . Используйте CameraXConfig.Builder.setMinimumLoggingLevel(int)
чтобы задать соответствующий уровень журналирования для вашего приложения.
Автоматический выбор
CameraX автоматически предоставляет функциональность, специфичную для устройства, на котором работает ваше приложение. Например, CameraX автоматически определяет наилучшее разрешение для использования, если вы не указали разрешение или если указанное вами разрешение не поддерживается. Все это обрабатывается библиотекой, что устраняет необходимость писать код, специфичный для устройства.
Цель CameraX — успешно инициализировать сеанс камеры. Это означает, что CameraX идет на компромисс по разрешению и соотношению сторон в зависимости от возможностей устройства. Компромисс может произойти по следующим причинам:
- Устройство не поддерживает запрошенное разрешение.
- У устройства есть проблемы с совместимостью, например, устаревшие устройства, для корректной работы которых требуются определенные разрешения.
- На некоторых устройствах определенные форматы доступны только при определенных соотношениях сторон.
- Устройство имеет предпочтение "ближайшего mod16" для кодирования JPEG или видео. Для получения дополнительной информации см.
SCALER_STREAM_CONFIGURATION_MAP
.
Хотя CameraX создает и управляет сеансом, всегда проверяйте возвращаемые размеры изображений в выходных данных варианта использования в вашем коде и вносите соответствующие изменения.
Вращение
По умолчанию поворот камеры устанавливается в соответствии с поворотом дисплея по умолчанию во время создания варианта использования. В этом варианте использования по умолчанию CameraX создает выходные данные, чтобы приложение соответствовало тому, что вы ожидаете увидеть в предварительном просмотре. Вы можете изменить поворот на пользовательское значение для поддержки устройств с несколькими дисплеями, передав текущую ориентацию дисплея при настройке объектов варианта использования или динамически после их создания.
Ваше приложение может задать целевой поворот с помощью параметров конфигурации. Затем оно может обновить параметры поворота с помощью методов из API вариантов использования (таких как ImageAnalysis.setTargetRotation()
), даже когда жизненный цикл находится в состоянии выполнения. Вы можете использовать это, когда приложение заблокировано в портретном режиме, и поэтому при повороте не происходит перенастройки, но вариант использования фотографии или анализа должен знать о текущем повороте устройства. Например, может потребоваться распознавание поворота, чтобы лица были правильно ориентированы для обнаружения лиц или чтобы фотографии были установлены в альбомную или портретную ориентацию.
Данные для захваченных изображений могут храниться без информации о повороте. Данные Exif содержат информацию о повороте, чтобы приложения галереи могли отображать изображение в правильной ориентации после сохранения.
Чтобы отобразить данные предварительного просмотра с правильной ориентацией, можно использовать вывод метаданных из Preview.PreviewOutput()
для создания преобразований.
В следующем примере кода показано, как задать поворот при событии ориентации:
Котлин
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() }
Ява
@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(); }
На основе заданного поворота каждый вариант использования либо поворачивает данные изображения напрямую, либо предоставляет метаданные поворота потребителям неповернутых данных изображения.
- Предварительный просмотр : Предоставляется вывод метаданных, чтобы можно было узнать поворот целевого разрешения с помощью
Preview.getTargetRotation()
. - ImageAnalysis : вывод метаданных обеспечивается таким образом, чтобы координаты буфера изображения были известны относительно координат дисплея.
- ImageCapture : метаданные Exif изображения, буфер или и буфер, и метаданные изменяются для учета настройки поворота. Измененное значение зависит от реализации HAL.
Обрезка прямоугольника
По умолчанию прямоугольник обрезки — это полный буферный прямоугольник. Вы можете настроить его с помощью ViewPort
и UseCaseGroup
. Группируя варианты использования и устанавливая область просмотра, CameraX гарантирует, что прямоугольники обрезки всех вариантов использования в группе указывают на одну и ту же область в датчике камеры.
Следующий фрагмент кода показывает, как использовать эти два класса:
Котлин
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)
Ява
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
определяет буферный прямоугольник, видимый конечным пользователям. Затем CameraX вычисляет максимально возможный прямоугольник обрезки на основе свойств области просмотра и прикрепленных вариантов использования. Обычно для достижения эффекта WYSIWYG можно настроить область просмотра на основе варианта использования предварительного просмотра. Простой способ получить область просмотра — использовать PreviewView
.
В следующих фрагментах кода показано, как получить объект ViewPort
:
Котлин
val viewport = findViewById<PreviewView>(R.id.preview_view).viewPort
Ява
ViewPort viewPort = ((PreviewView)findViewById(R.id.preview_view)).getViewPort();
В предыдущем примере то, что приложение получает от ImageAnalysis
и ImageCapture
соответствует тому, что конечный пользователь видит в PreviewView
, предполагая, что тип масштабирования PreviewView
установлен по умолчанию, FILL_CENTER
. После применения прямоугольника обрезки и поворота к выходному буферу изображение из всех вариантов использования будет одинаковым, хотя, возможно, с разным разрешением. Для получения дополнительной информации о том, как применять информацию о преобразовании, см. transform output .
Выбор камеры
CameraX автоматически выбирает лучшее устройство камеры для требований и вариантов использования вашего приложения. Если вы хотите использовать другое устройство, а не то, которое вы выбрали, есть несколько вариантов:
- Запросите фронтальную камеру по умолчанию с помощью
CameraSelector.DEFAULT_FRONT_CAMERA
. - Запросите заднюю камеру по умолчанию с помощью
CameraSelector.DEFAULT_BACK_CAMERA
. - Отфильтруйте список доступных устройств по их
CameraCharacteristics
с помощьюCameraSelector.Builder.addCameraFilter()
.
Следующий пример кода иллюстрирует, как создать CameraSelector
для влияния на выбор устройства:
Котлин
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)
Выберите несколько камер одновременно
Начиная с CameraX 1.3, вы также можете выбрать несколько камер одновременно. Например, вы можете привязаться к передней и задней камере, чтобы делать фотографии или записывать видео с обеих точек одновременно.
При использовании функции Concurrent Camera устройство может одновременно управлять двумя камерами с разными объективами или одновременно управлять двумя задними камерами. Следующий блок кода показывает, как задать две камеры при вызове bindToLifecycle
и как получить оба объекта Camera из возвращаемого объекта ConcurrentCamera
.
Котлин
// 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]
Ява
// 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);
Разрешение камеры
Вы можете разрешить CameraX устанавливать разрешение изображения на основе комбинации возможностей устройства, поддерживаемого уровня оборудования устройства, варианта использования и предоставленного соотношения сторон. В качестве альтернативы вы можете задать определенное целевое разрешение или определенное соотношение сторон в вариантах использования, которые поддерживают эту конфигурацию.
Автоматическое разрешение
CameraX может автоматически определять наилучшие настройки разрешения на основе вариантов использования, указанных в cameraProcessProvider.bindToLifecycle()
. По возможности указывайте все варианты использования, необходимые для одновременного запуска в одном сеансе, в одном вызове bindToLifecycle()
. CameraX определяет разрешения на основе набора вариантов использования, связанных с учетом поддерживаемого уровня оборудования устройства и с учетом вариации, специфичной для устройства (когда устройство превышает или не соответствует доступным конфигурациям потока ). Цель состоит в том, чтобы позволить приложению работать на самых разных устройствах, минимизируя пути кода, специфичные для устройства.
Соотношение сторон по умолчанию для захвата и анализа изображений составляет 4:3.
Варианты использования имеют настраиваемое соотношение сторон, позволяющее приложению указывать желаемое соотношение сторон на основе дизайна пользовательского интерфейса. Вывод CameraX создается для соответствия запрошенным соотношениям сторон настолько точно, насколько это поддерживает устройство. Если не поддерживается точное соответствие разрешению, выбирается то, которое удовлетворяет большинству условий. Таким образом, приложение определяет, как камера будет выглядеть в приложении, а CameraX определяет наилучшие настройки разрешения камеры, чтобы удовлетворить это на разных устройствах.
Например, приложение может выполнять любые из следующих действий:
- Укажите целевое разрешение 4:3 или 16:9 для варианта использования.
- Укажите пользовательское разрешение, которому CameraX попытается найти наиболее близкое соответствие
- Укажите соотношение сторон кадрирования для
ImageCapture
CameraX автоматически выбирает внутренние разрешения поверхности Camera2. В следующей таблице показаны разрешения:
Вариант использования | Разрешение внутренней поверхности | Разрешение выходных данных |
---|---|---|
Предварительный просмотр | Соотношение сторон: разрешение, которое наилучшим образом соответствует заданным параметрам. | Разрешение внутренней поверхности. Метаданные предоставляются для того, чтобы View мог обрезать, масштабировать и вращать для целевого соотношения сторон. |
Разрешение по умолчанию: самое высокое разрешение предварительного просмотра или самое высокое разрешение, предпочитаемое устройством, которое соответствует соотношению сторон предварительного просмотра. | ||
Максимальное разрешение: размер предварительного просмотра, который соответствует максимальному соответствию разрешению экрана устройства или 1080p (1920x1080), в зависимости от того, какое значение меньше. | ||
Анализ изображения | Соотношение сторон: разрешение, которое наилучшим образом соответствует заданным параметрам. | Разрешение внутренней поверхности. |
Разрешение по умолчанию: Целевое разрешение по умолчанию — 640x480. Настройка целевого разрешения и соответствующего соотношения сторон приводит к наилучшему поддерживаемому разрешению. | ||
Максимальное разрешение: максимальное выходное разрешение устройства камеры в формате YUV_420_888, которое извлекается из StreamConfigurationMap.getOutputSizes() . Целевое разрешение по умолчанию установлено как 640x480, поэтому, если вам нужно разрешение больше 640x480, вы должны использовать setTargetResolution() и setTargetAspectRatio() чтобы получить ближайшее из поддерживаемых разрешений. | ||
Захват изображения | Соотношение сторон: Соотношение сторон, которое лучше всего подходит для данной обстановки. | Разрешение внутренней поверхности. |
Разрешение по умолчанию: максимально возможное разрешение или максимальное разрешение, предпочитаемое устройством, которое соответствует соотношению сторон ImageCapture. | ||
Максимальное разрешение: Максимальное выходное разрешение устройства камеры в формате JPEG. Используйте StreamConfigurationMap.getOutputSizes() для получения этого. |
Укажите разрешение
Вы можете задать определенные разрешения при создании вариантов использования с помощью метода setTargetResolution(Size resolution)
, как показано в следующем примере кода:
Котлин
val imageAnalysis = ImageAnalysis.Builder() .setTargetResolution(Size(1280, 720)) .build()
Ява
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder() .setTargetResolution(new Size(1280, 720)) .build();
Вы не можете задать и целевое соотношение сторон, и целевое разрешение в одном и том же варианте использования. Это приведет к исключению IllegalArgumentException
при построении объекта конфигурации.
Выразите разрешение Size
в системе координат после поворота поддерживаемых размеров на целевой поворот. Например, устройство с портретной естественной ориентацией в естественном целевом повороте, запрашивающее портретное изображение, может указать 480x640, а то же устройство, повернутое на 90 градусов и нацеленное на альбомную ориентацию, может указать 640x480.
Целевое разрешение пытается установить минимальную границу для разрешения изображения. Фактическое разрешение изображения — это ближайшее доступное разрешение по размеру, которое не меньше целевого разрешения, как определено реализацией камеры.
Однако, если не существует разрешения, равного или большего целевого разрешения, выбирается ближайшее доступное разрешение, меньшее целевого разрешения. Разрешения с одинаковым соотношением сторон указанного Size
имеют более высокий приоритет, чем разрешения с другими соотношениями сторон.
CameraX применяет наиболее подходящее разрешение на основе запросов. Если основной потребностью является удовлетворение соотношения сторон, укажите только setTargetAspectRatio
, и CameraX определит конкретное подходящее разрешение на основе устройства. Если основной потребностью приложения является указание разрешения для повышения эффективности обработки изображений (например, изображение небольшого или среднего размера на основе возможностей обработки устройства), используйте setTargetResolution(Size resolution)
.
Если вашему приложению требуется точное разрешение, см. таблицу в createCaptureSession()
чтобы определить, какие максимальные разрешения поддерживаются каждым аппаратным уровнем. Чтобы проверить конкретные разрешения, поддерживаемые текущим устройством, см. StreamConfigurationMap.getOutputSizes(int)
.
Если ваше приложение работает на Android 10 или выше, вы можете использовать isSessionConfigurationSupported()
для проверки определенного SessionConfiguration
.
Управление выходом камеры
Помимо возможности настраивать вывод камеры по мере необходимости для каждого отдельного варианта использования, CameraX также реализует следующие интерфейсы для поддержки операций камеры, общих для всех связанных вариантов использования:
-
CameraControl
позволяет настраивать общие функции камеры. -
CameraInfo
позволяет вам запрашивать состояния этих распространенных функций камеры.
Ниже перечислены поддерживаемые функции камеры с CameraControl:
- Увеличить
- Факел
- Фокусировка и замер (фокусировка одним касанием)
- Компенсация экспозиции
Получить экземпляры CameraControl и CameraInfo
Извлеките экземпляры CameraControl
и CameraInfo
, используя объект Camera
, возвращаемый ProcessCameraProvider.bindToLifecycle()
. Следующий код показывает пример:
Котлин
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
Ява
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()
Например, вы можете отправить зум и другие операции CameraControl
после вызова bindToLifecycle()
. После остановки или уничтожения активности, используемой для привязки экземпляра камеры, CameraControl
больше не может выполнять операции и возвращает неудавшийся ListenableFuture
.
Увеличить
CameraControl предлагает два способа изменения уровня масштабирования:
setZoomRatio()
устанавливает масштаб по коэффициенту масштабирования.Соотношение должно быть в диапазоне
CameraInfo.getZoomState().getValue().getMinZoomRatio()
иCameraInfo.getZoomState().getValue().getMaxZoomRatio()
. В противном случае функция возвращает неудавшийсяListenableFuture
.setLinearZoom()
устанавливает текущий масштаб с линейным значением масштабирования в диапазоне от 0 до 1,0.Преимущество линейного зума в том, что он масштабирует поле зрения (FOV) при изменении зума. Это делает его идеальным для использования с видом
Slider
.
CameraInfo.getZoomState()
возвращает LiveData текущего состояния масштабирования. Значение изменяется при инициализации камеры или если уровень масштабирования установлен с помощью setZoomRatio()
или setLinearZoom()
. Вызов любого из методов устанавливает значения, поддерживающие ZoomState.getZoomRatio()
и ZoomState.getLinearZoom()
. Это полезно, если вы хотите отобразить текст коэффициента масштабирования рядом со ползунком. Просто наблюдайте за ZoomState
LiveData
, чтобы обновить оба без необходимости выполнять преобразование.
ListenableFuture
, возвращаемый обоими API, предоставляет возможность приложениям получать уведомления о завершении повторяющегося запроса с указанным значением масштабирования. Кроме того, если вы устанавливаете новое значение масштабирования, пока предыдущая операция все еще выполняется, ListenableFuture
предыдущей операции масштабирования немедленно завершается ошибкой.
Факел
CameraControl.enableTorch(boolean)
включает или выключает фонарик (также известный как фонарик).
CameraInfo.getTorchState()
можно использовать для запроса текущего состояния факела. Вы можете проверить значение, возвращаемое CameraInfo.hasFlashUnit()
чтобы определить, доступен ли факел. Если нет, вызов CameraControl.enableTorch(boolean)
приводит к немедленному завершению возвращаемого ListenableFuture
с неудачным результатом и устанавливает состояние факела в TorchState.OFF
.
Когда фонарик включен, он остается включенным во время фото- и видеосъемки независимо от настройки flashMode. flashMode
в ImageCapture
работает только при отключенном фонарике.
Фокусировка и замер
CameraControl.startFocusAndMetering()
запускает автофокусировку и замер экспозиции, устанавливая области замера AF/AE/AWB на основе заданного FocusMeteringAction. Это часто используется для реализации функции «нажатие для фокусировки» во многих приложениях для камер.
MeteringPoint
Для начала создайте MeteringPoint
с помощью MeteringPointFactory.createPoint(float x, float y, float size)
. MeteringPoint
представляет собой одну точку на Surface
камеры. Она хранится в нормализованной форме, чтобы ее можно было легко преобразовать в координаты датчика для указания областей AF/AE/AWB.
Размер MeteringPoint
варьируется от 0 до 1, с размером по умолчанию 0,15f. При вызове MeteringPointFactory.createPoint(float x, float y, float size)
CameraX создает прямоугольную область с центром в точке (x, y)
для указанного size
.
Следующий код демонстрирует, как создать MeteringPoint
:
Котлин
// 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 и FocusMeteringAction
Для вызова startFocusAndMetering()
приложения должны создать FocusMeteringAction
, который состоит из одного или нескольких MeteringPoints
с дополнительными комбинациями режимов измерения из FLAG_AF
, FLAG_AE
, FLAG_AWB
. Следующий код демонстрирует это использование:
Котлин
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)
Как показано в предыдущем коде, startFocusAndMetering()
принимает FocusMeteringAction
, состоящий из одной MeteringPoint
для областей замера AF/AE/AWB и другой MeteringPoint только для AF и AE.
Внутренне CameraX преобразует его в Camera2 MeteringRectangles
и устанавливает соответствующие параметры CONTROL_AF_REGIONS
/ CONTROL_AE_REGIONS
/ CONTROL_AWB_REGIONS
для запроса на захват.
Поскольку не все устройства поддерживают AF/AE/AWB и несколько областей, CameraX выполняет FocusMeteringAction
с максимальной эффективностью. CameraX использует максимальное количество поддерживаемых точек замера в том порядке, в котором они были добавлены. Все точки замера, добавленные после максимального количества, игнорируются. Например, если FocusMeteringAction
поставляется с 3 точками замера на платформе, поддерживающей только 2, используются только первые 2 точки замера. Последняя MeteringPoint
игнорируется CameraX.
Компенсация экспозиции
Компенсация экспозиции полезна, когда приложениям необходимо точно настроить значения экспозиции (EV) за пределами выходного результата автоматической экспозиции (AE). Значения компенсации экспозиции комбинируются следующим образом для определения необходимой экспозиции для текущих условий изображения:
Exposure = ExposureCompensationIndex * ExposureCompensationStep
CameraX предоставляет функцию Camera.CameraControl.setExposureCompensationIndex()
для установки компенсации экспозиции в качестве значения индекса.
Положительные значения индекса делают изображение ярче, а отрицательные — затемняют. Приложения могут запрашивать поддерживаемый диапазон с помощью CameraInfo.ExposureState.exposureCompensationRange()
описанного в следующем разделе. Если значение поддерживается, возвращаемый ListenableFuture
завершается, когда значение успешно включено в запросе захвата; если указанный индекс выходит за пределы поддерживаемого диапазона, setExposureCompensationIndex()
заставляет возвращаемый ListenableFuture
немедленно завершиться с неудачным результатом.
CameraX сохраняет только последний невыполненный запрос setExposureCompensationIndex()
, а многократный вызов функции до выполнения предыдущего запроса приводит к его отмене.
Следующий фрагмент устанавливает индекс компенсации экспозиции и регистрирует обратный вызов при выполнении запроса на изменение экспозиции:
Котлин
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()
извлекает текущееExposureState
включая:- Возможность поддержки управления компенсацией экспозиции.
- Текущий индекс компенсации экспозиции.
- Диапазон индекса компенсации экспозиции.
- Шаг компенсации экспозиции, используемый при расчете значения компенсации экспозиции.
Например, следующий код инициализирует настройки для SeekBar
экспозиции с текущими значениями ExposureState
:
Котлин
val exposureState = camera.cameraInfo.exposureState binding.seekBar.apply { isEnabled = exposureState.isExposureCompensationSupported max = exposureState.exposureCompensationRange.upper min = exposureState.exposureCompensationRange.lower progress = exposureState.exposureCompensationIndex }
Дополнительные ресурсы
Чтобы узнать больше о CameraX, ознакомьтесь со следующими дополнительными ресурсами.
Кодовая лаборатория
Пример кода
Сообщество разработчиков
Группа обсуждения Android CameraX