Вы можете использовать изображение с камеры, которое ARCore захватывает в конвейере машинного обучения, для создания интеллектуального опыта дополненной реальности. Образец ARCore ML Kit демонстрирует, как использовать ML Kit и API Google Cloud Vision для идентификации реальных объектов. В образце используется модель машинного обучения для классификации объектов в поле зрения камеры и прикрепления метки к объекту в виртуальной сцене.
Образец набора ARCore ML написан на Kotlin. Он также доступен в виде примера приложения ml_kotlin в репозитории ARCore SDK GitHub.
Используйте образ процессора ARCore
По умолчанию ARCore захватывает как минимум два набора потоков изображений:
- Поток изображений ЦП, используемый для распознавания функций и обработки изображений. По умолчанию изображение ЦП имеет разрешение VGA (640x480). При необходимости ARCore можно настроить на использование дополнительного потока изображений с более высоким разрешением.
- Поток текстур графического процессора , который содержит текстуру высокого разрешения, обычно 1080p. Обычно это используется в качестве предварительного просмотра камеры, обращенной к пользователю. Это хранится в текстуре OpenGL, указанной
Session.setCameraTextureName()
. - Любые дополнительные потоки, указанные
SharedCamera.setAppSurfaces()
.
Рекомендации по размеру образа ЦП
Никаких дополнительных затрат не возникает, если используется поток ЦП по умолчанию размером VGA, поскольку ARCore использует этот поток для понимания мира. Запрос потока с другим разрешением может оказаться дорогостоящим, поскольку потребуется захватить дополнительный поток. Имейте в виду, что более высокое разрешение может быстро стать дорогостоящим для вашей модели: удвоение ширины и высоты изображения увеличивает количество пикселей в изображении в четыре раза.
Возможно, будет полезно уменьшить масштаб изображения, если ваша модель по-прежнему может хорошо работать с изображением с более низким разрешением.
Настройте дополнительный поток изображений ЦП высокого разрешения.
Производительность вашей модели машинного обучения может зависеть от разрешения изображения, используемого в качестве входных данных. Разрешение этих потоков можно настроить, изменив текущую CameraConfig
с помощью Session.setCameraConfig()
и выбрав допустимую конфигурацию из Session.getSupportedCameraConfigs()
.
CameraConfigFilter cameraConfigFilter =
new CameraConfigFilter(session)
// World-facing cameras only.
.setFacingDirection(CameraConfig.FacingDirection.BACK);
List<CameraConfig> supportedCameraConfigs =
session.getSupportedCameraConfigs(cameraConfigFilter);
// Select an acceptable configuration from supportedCameraConfigs.
CameraConfig cameraConfig = selectCameraConfig(supportedCameraConfigs);
session.setCameraConfig(cameraConfig);
val cameraConfigFilter =
CameraConfigFilter(session)
// World-facing cameras only.
.setFacingDirection(CameraConfig.FacingDirection.BACK)
val supportedCameraConfigs = session.getSupportedCameraConfigs(cameraConfigFilter)
// Select an acceptable configuration from supportedCameraConfigs.
val cameraConfig = selectCameraConfig(supportedCameraConfigs)
session.setCameraConfig(cameraConfig)
Получить образ процессора
Получите изображение процессора с помощью Frame.acquireCameraImage()
. От этих изображений следует избавиться, как только они больше не нужны.
Image cameraImage = null;
try {
cameraImage = frame.acquireCameraImage();
// Process `cameraImage` using your ML inference model.
} catch (NotYetAvailableException e) {
// NotYetAvailableException is an exception that can be expected when the camera is not ready
// yet. The image may become available on a next frame.
} catch (RuntimeException e) {
// A different exception occurred, e.g. DeadlineExceededException, ResourceExhaustedException.
// Handle this error appropriately.
handleAcquireCameraImageFailure(e);
} finally {
if (cameraImage != null) {
cameraImage.close();
}
}
// NotYetAvailableException is an exception that can be expected when the camera is not ready yet.
// Map it to `null` instead, but continue to propagate other errors.
fun Frame.tryAcquireCameraImage() =
try {
acquireCameraImage()
} catch (e: NotYetAvailableException) {
null
} catch (e: RuntimeException) {
// A different exception occurred, e.g. DeadlineExceededException, ResourceExhaustedException.
// Handle this error appropriately.
handleAcquireCameraImageFailure(e)
}
// The `use` block ensures the camera image is disposed of after use.
frame.tryAcquireCameraImage()?.use { image ->
// Process `image` using your ML inference model.
}
Обработка образа процессора
Для обработки образа ЦП можно использовать различные библиотеки машинного обучения.
- ML Kit : ML Kit предоставляет API обнаружения и отслеживания объектов на устройстве. Он поставляется со встроенным в API грубым классификатором, а также может использовать пользовательские модели классификации для охвата более узкой области объектов. Используйте
InputImage.fromMediaImage
, чтобы преобразовать образ вашего процессора вInputImage
. - Машинное обучение Firebase : Firebase предоставляет API-интерфейсы машинного обучения , которые работают либо в облаке, либо на устройстве. См. документацию Firebase по безопасной маркировке изображений с помощью Cloud Vision с использованием Firebase Auth и функций на Android .
Отображение результатов в вашей AR-сцене
Модели распознавания изображений часто выводят обнаруженные объекты, указывая центральную точку или ограничивающий многоугольник, представляющий обнаруженный объект.
Используя центральную точку или центр ограничивающей рамки, полученной из модели, можно прикрепить привязку к обнаруженному объекту. Используйте Frame.hitTest()
, чтобы оценить положение объекта в виртуальной сцене.
Преобразуйте координаты IMAGE_PIXELS
в координаты VIEW
:
// Suppose `mlResult` contains an (x, y) of a given point on the CPU image.
float[] cpuCoordinates = new float[] {mlResult.getX(), mlResult.getY()};
float[] viewCoordinates = new float[2];
frame.transformCoordinates2d(
Coordinates2d.IMAGE_PIXELS, cpuCoordinates, Coordinates2d.VIEW, viewCoordinates);
// `viewCoordinates` now contains coordinates suitable for hit testing.
// Suppose `mlResult` contains an (x, y) of a given point on the CPU image.
val cpuCoordinates = floatArrayOf(mlResult.x, mlResult.y)
val viewCoordinates = FloatArray(2)
frame.transformCoordinates2d(
Coordinates2d.IMAGE_PIXELS,
cpuCoordinates,
Coordinates2d.VIEW,
viewCoordinates
)
// `viewCoordinates` now contains coordinates suitable for hit testing.
Используйте эти координаты VIEW
для проведения проверки попадания и создания привязки на основе результата:
List<HitResult> hits = frame.hitTest(viewCoordinates[0], viewCoordinates[1]);
HitResult depthPointResult = null;
for (HitResult hit : hits) {
if (hit.getTrackable() instanceof DepthPoint) {
depthPointResult = hit;
break;
}
}
if (depthPointResult != null) {
Anchor anchor = depthPointResult.getTrackable().createAnchor(depthPointResult.getHitPose());
// This anchor will be attached to the scene with stable tracking.
// It can be used as a position for a virtual object, with a rotation prependicular to the
// estimated surface normal.
}
val hits = frame.hitTest(viewCoordinates[0], viewCoordinates[1])
val depthPointResult = hits.filter { it.trackable is DepthPoint }.firstOrNull()
if (depthPointResult != null) {
val anchor = depthPointResult.trackable.createAnchor(depthPointResult.hitPose)
// This anchor will be attached to the scene with stable tracking.
// It can be used as a position for a virtual object, with a rotation prependicular to the
// estimated surface normal.
}
Вопросы производительности
Следуйте следующим рекомендациям, чтобы сэкономить вычислительную мощность и потреблять меньше энергии:
- Не запускайте модель машинного обучения в каждом входящем кадре. Вместо этого рассмотрите возможность запуска обнаружения объектов с низкой частотой кадров.
- Рассмотрите онлайн-модель вывода ML, чтобы уменьшить сложность вычислений.
Следующие шаги
- Узнайте о лучших практиках разработки машинного обучения .
- Узнайте о практиках ответственного ИИ .
- Изучите основы машинного обучения с курсом TensorFlow .