Анализ изображений

Вариант использования анализа изображений предоставляет вашему приложению доступное для ЦП изображение, на котором вы можете выполнять обработку изображений, компьютерное зрение или выводы машинного обучения. Приложение реализует метод analyze() , который запускается для каждого кадра.

Чтобы узнать, как интегрировать Google ML Kit с вашим приложением CameraX, см. ML Kit Analyzer .

Режимы работы

Если конвейер анализа приложения не соответствует требованиям CameraX к частоте кадров, CameraX можно настроить на отбрасывание кадров одним из следующих способов:

  • неблокирующий (по умолчанию): в этом режиме исполнитель всегда кэширует последнее изображение в буфер изображения (аналогично очереди с глубиной, равной единице), пока приложение анализирует предыдущее изображение. Если 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 кадров в секунду), любой режим работы обеспечивает плавное общее восприятие. Режим блокировки по-прежнему может быть полезен в некоторых сценариях, например, при очень кратковременных дрожаниях системы.

При высокой задержке и высокой производительности анализатора для компенсации задержки необходим режим блокировки с более длинной очередью. Однако обратите внимание, что приложение по-прежнему может обрабатывать все кадры.

При высокой задержке и трудоемкости анализатора (анализатор не может обработать все кадры) неблокирующий режим может быть более подходящим выбором, поскольку для пути анализа кадры необходимо отбрасывать, но другие параллельные сценарии использования по-прежнему можно увидеть. все кадры.

Выполнение

Чтобы использовать анализ изображений в своем приложении, выполните следующие действия:

Сразу после привязки CameraX отправляет изображения на зарегистрированный анализатор. После завершения анализа вызовите ImageAnalysis.clearAnalyzer() или отмените привязку варианта использования ImageAnalysis , чтобы остановить анализ.

Создание варианта использования ImageAnaанализа

ImageAnalysis подключает ваш анализатор (потребитель изображений) к CameraX, который является производителем изображений. Приложения могут использовать ImageAnalysis.Builder для создания объекта ImageAnalysis . С помощью ImageAnalysis.Builder приложение может настроить следующее:

Приложения могут устанавливать либо разрешение, либо соотношение сторон, но не то и другое. Точное выходное разрешение зависит от запрошенного размера приложения (или соотношения сторон) и возможностей оборудования и может отличаться от запрошенного размера или соотношения сторон. Информацию об алгоритме сопоставления разрешения см. в документации для 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 .

См. вариант использования Build ImageAnaлиз для получения информации о конфигурациях цветового пространства и о том, где можно получить пиксельные байты.

Внутри анализатора приложение должно делать следующее:

  1. Анализируйте данный кадр как можно быстрее, желательно в пределах заданного временного ограничения частоты кадров (например, менее 32 мс для случая 30 кадров в секунду). Если приложение не может проанализировать кадр достаточно быстро, рассмотрите один из поддерживаемых механизмов отбрасывания кадров .
  2. Выпустите ImageProxy для CameraX, вызвав ImageProxy.close() . Обратите внимание, что вам не следует вызывать функцию закрытия обернутого Media.Image ( Media.Image.close() ).

Приложения могут напрямую использовать завернутый Media.Image внутри ImageProxy. Только не вызывайте Media.Image.close() для завернутого изображения, так как это нарушит механизм обмена изображениями внутри CameraX; вместо этого используйте ImageProxy.close() , чтобы передать базовый Media.Image в CameraX.

Настройте свой анализатор для ImageAnaанализа

После создания анализатора используйте ImageAnalysis.setAnalyzer() чтобы зарегистрировать его и начать анализ. Завершив анализ, используйте ImageAnalysis.clearAnalyzer() чтобы удалить зарегистрированный анализатор.

Для анализа изображений можно настроить только один активный анализатор. Вызов ImageAnalysis.setAnalyzer() заменяет зарегистрированный анализатор, если он уже существует. Приложения могут установить новый анализатор в любое время, до или после привязки варианта использования.

Привязка ImageAnaанализа к жизненному циклу

Настоятельно рекомендуется привязать ваш ImageAnalysis к существующему жизненному циклу AndroidX с помощью функции ProcessCameraProvider.bindToLifecycle() . Обратите внимание, что функция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)

Ява

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, см. следующие дополнительные ресурсы.

Кодлаб

  • Начало работы с CameraX
  • Пример кода

  • Примеры приложений CameraX