Вариант использования Анализ изображений предоставляет приложению доступное для ЦП изображение, которое можно использовать для обработки изображений, компьютерного зрения или инференса машинного обучения. В приложении реализован метод analyze(), который выполняется для каждого кадра.
Чтобы узнать, как интегрировать ML Kit от Google с приложением CameraX, ознакомьтесь со статьей ML Kit Analyzer.
Режимы работы
Если конвейер анализа приложения не справляется с требованиями CameraX к частоте кадров, CameraX можно настроить на пропуск кадров одним из следующих способов:
non-blocking (по умолчанию). В этом режиме исполнитель всегда кеширует последнее изображение в буфер изображений (похожий на очередь глубиной в один элемент), пока приложение анализирует предыдущее изображение. Если CameraX получает новое изображение до того, как приложение завершит обработку, новое изображение сохраняется в том же буфере, перезаписывая предыдущее изображение. Обратите внимание, что в этом случае параметр
ImageAnalysis.Builder.setImageQueueDepth()не действует и содержимое буфера всегда перезаписывается. Чтобы включить этот неблокирующий режим, вызовите методsetBackpressureStrategy()с параметромSTRATEGY_KEEP_ONLY_LATEST. Дополнительную информацию о последствиях использования исполнителя можно найти в справочной документации поSTRATEGY_KEEP_ONLY_LATEST.blocking – в этом режиме внутренний исполнитель может добавлять несколько изображений во внутреннюю очередь изображений и начинает пропускать кадры, только когда очередь заполнена. Блокировка происходит во всей области действия камеры: если у камеры есть несколько связанных вариантов использования, все они будут заблокированы, пока CameraX обрабатывает эти изображения. Например, если к камере привязаны и предварительный просмотр, и анализ изображений, то предварительный просмотр также будет заблокирован, пока CameraX обрабатывает изображения. Чтобы включить режим блокировки, передайте
STRATEGY_BLOCK_PRODUCERвsetBackpressureStrategy(). Вы также можете настроить глубину очереди изображений с помощью ImageAnalysis.Builder.setImageQueueDepth().
Если анализатор работает быстро и эффективно, а общее время анализа изображения меньше длительности кадра CameraX (например, 16 мс при 60 кадрах/с), то оба режима обеспечивают плавную работу. Режим блокировки может быть полезен в некоторых сценариях, например при кратковременных сбоях в системе.
Если анализатор работает с высокой задержкой и высокой производительностью, то для компенсации задержки необходим режим блокировки с более длинной очередью. Однако обратите внимание, что приложение по-прежнему может обрабатывать все кадры.
Если анализатор работает медленно и не успевает обрабатывать все кадры, лучше выбрать неблокирующий режим. В этом случае кадры будут пропускаться только для анализа, а в других параллельных процессах будут видны все кадры.
Реализация
Чтобы использовать анализ изображений в своем приложении, выполните следующие действия:
- Создайте вариант использования
ImageAnalysis. - Создайте
ImageAnalysis.Analyzer. - Установите анализатор в
ImageAnalysis. - Привяжите владельца жизненного цикла, селектор камеры и вариант использования
ImageAnalysisк жизненному циклу.
Immediately after binding, CameraX sends images to your registered analyzer.
После завершения анализа вызовите ImageAnalysis.clearAnalyzer() или отмените привязку варианта использования ImageAnalysis, чтобы остановить анализ.
Создание варианта использования ImageAnalysis
ImageAnalysis подключает анализатор (потребитель изображений) к CameraX (производитель изображений).
Приложения могут использовать ImageAnalysis.Builder для создания объекта ImageAnalysis. С помощью ImageAnalysis.Builder приложение может настроить следующее:
- Параметры выходного изображения:
- Формат. CameraX поддерживает
YUV_420_888иRGBA_8888черезsetOutputImageFormat(int). Формат по умолчанию –YUV_420_888. - Resolution и AspectRatio. Вы можете задать любой из этих параметров, но не оба одновременно.
- Ротация.
- Название цели. Используйте этот параметр для отладки.
- Формат. CameraX поддерживает
- Элементы управления показом изображений:
Приложения могут задавать либо разрешение, либо соотношение сторон, но не оба параметра. Точное разрешение на выходе зависит от размера (или соотношения сторон), запрошенного приложением, и возможностей оборудования и может отличаться от запрошенного размера или соотношения сторон. Информацию об алгоритме сопоставления разрешений можно найти в документации по setTargetResolution().
Приложение может настроить пиксели выходного изображения в цветовых пространствах YUV (по умолчанию) или RGBA. При выборе формата RGBA CameraX преобразует изображения из цветового пространства YUV в RGBA и упаковывает биты изображения в ByteBuffer первой плоскости ImageProxy (две другие плоскости не используются) в следующей последовательности:
ImageProxy.getPlanes()[0].buffer[0]: alpha
ImageProxy.getPlanes()[0].buffer[1]: red
ImageProxy.getPlanes()[0].buffer[2]: green
ImageProxy.getPlanes()[0].buffer[3]: blue
...
При выполнении сложного анализа изображений, когда устройство не может поддерживать частоту кадров, вы можете настроить CameraX на пропуск кадров, используя стратегии, описанные в разделе Режимы работы этой темы.
Создайте анализатор
Приложения могут создавать анализаторы, реализуя интерфейс ImageAnalysis.Analyzer и переопределяя analyze(ImageProxy image).
В каждом анализаторе приложения получают ImageProxy, который является оболочкой для Media.Image.
Графический формат можно запросить с помощью ImageProxy.getFormat().
Формат – это одно из следующих значений, которые приложение предоставляет с помощью ImageAnalysis.Builder:
ImageFormat.RGBA_8888, если приложение запрашиваетOUTPUT_IMAGE_FORMAT_RGBA_8888.ImageFormat.YUV_420_888, если приложение запрашиваетOUTPUT_IMAGE_FORMAT_YUV_420_888.
Информацию о конфигурациях цветового пространства и о том, где можно получить байты пикселей, вы найдете в разделе Создание варианта использования ImageAnalysis.
Внутри анализатора приложение должно выполнять следующие действия:
- Анализируйте данный кадр как можно быстрее, желательно в пределах времени, отведенного на частоту кадров (например, менее 32 мс при частоте 30 кадр/с). Если приложение не успевает анализировать кадры, используйте один из поддерживаемых механизмов пропуска кадров.
- Освободите
ImageProxyдля CameraX, вызвавImageProxy.close(). Обратите внимание, что не следует вызывать функцию close (Media.Image.close()) для упакованного объекта Media.Image.
Приложения могут использовать упакованный объект Media.Image непосредственно в ImageProxy.
Не вызывайте Media.Image.close() для упакованного изображения, так как это нарушит механизм обмена изображениями в CameraX. Вместо этого используйте ImageProxy.close(), чтобы передать базовый объект Media.Image в CameraX.
Настройте анализатор для ImageAnalysis
После создания анализатора используйте ImageAnalysis.setAnalyzer(), чтобы зарегистрировать его и начать анализ. Завершив анализ, используйте ImageAnalysis.clearAnalyzer(), чтобы удалить зарегистрированный анализатор.
Для анализа изображений можно настроить только один активный анализатор. Если анализатор уже зарегистрирован, вызов ImageAnalysis.setAnalyzer() заменит его. Приложения могут устанавливать новый анализатор в любое время, до или после привязки варианта использования.
Привяжите ImageAnalysis к Lifecycle
Настоятельно рекомендуем привязать ImageAnalysis к существующему жизненному циклу AndroidX с помощью функции ProcessCameraProvider.bindToLifecycle(). Обратите внимание, что функция bindToLifecycle() возвращает выбранное устройство Camera, которое можно использовать для точной настройки расширенных параметров, таких как экспозиция и другие. Подробнее об управлении выводом камеры…
В следующем примере показано, как связать варианты использования CameraX ImageAnalysis и Preview с владельцем lifeCycle:
Kotlin
val imageAnalysis = ImageAnalysis.Builder() // enable the following line if RGBA output is needed. // .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) .setTargetResolution(Size(1280, 720)) .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build() imageAnalysis.setAnalyzer(executor, ImageAnalysis.Analyzer { imageProxy -> val rotationDegrees = imageProxy.imageInfo.rotationDegrees // insert your code here. ... // after done, release the ImageProxy object imageProxy.close() }) cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, imageAnalysis, preview)
Java
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder() // enable the following line if RGBA output is needed. //.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) .setTargetResolution(new Size(1280, 720)) .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build(); imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() { @Override public void analyze(@NonNull ImageProxy imageProxy) { int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees(); // insert your code here. ... // after done, release the ImageProxy object imageProxy.close(); } }); cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, imageAnalysis, preview);
Дополнительные ресурсы
Чтобы узнать больше о CameraX, ознакомьтесь со следующими дополнительными ресурсами.
Практическая работа
Пример кода