Вариант использования Анализ изображений предоставляет приложению доступное для ЦП изображение, на котором можно выполнять обработку изображений, компьютерное зрение или инференс машинного обучения. В приложении реализован метод 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.Блокировка. В этом режиме внутренний исполнитель может добавлять несколько изображений во внутреннюю очередь изображений и начинает отбрасывать кадры, только когда очередь заполнена. Блокировка происходит во всей области действия камеры: если у камеры есть несколько связанных вариантов использования, все они будут заблокированы, пока 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 к жизненному циклу
Настоятельно рекомендуем связать ImageAnalysis с существующим жизненным циклом AndroidX с помощью функции ProcessCameraProvider.bindToLifecycle(). Обратите внимание, что функция bindToLifecycle() возвращает выбранное устройство Camera, которое можно использовать для точной настройки расширенных параметров, таких как экспозиция и другие. Подробнее об управлении выводом камеры…
В следующем примере показано, как связать варианты использования CameraX ImageAnalysis и Preview с владельцем lifeCycle:
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)
Дополнительные ресурсы
Чтобы узнать больше о CameraX, ознакомьтесь со следующими дополнительными ресурсами.
Практическая работа
Пример кода