Pull to refresh

Создание Android приложения для обнаружения лиц в режиме реального времени с использованием Firebase ML Kit

Reading time4 min
Views7.8K
Original author: Husayn Hakeem

Создание Android приложения для обнаружения лиц в режиме реального времени с использованием ML Kit


В начале этого года Google представил новый продукт: Firebase Machine Learning Kit. ML Kit позволяет эффективно использовать возможности машинного обучения в Android и iOS приложениях. В этом посте я буду рассказывать о том, как с его помощью создать Android приложение для обнаружения лиц в реальном времени.


Обнаружение лиц — это только одна из возможностей компьютерного зрения, которую предлагает Firebase ML Kit (или, вернее, облегчает её использование). Это функция, которая может быть полезна во многих приложениях: подписывание людей на фотографиях, работа с селфи, добавление эмоджи и других эффектов во время съёмки, фотографирование только тогда, когда все улыбаются с открытыми глазами, и т.д. Возможности безграничны.


Мы уже публиковали статьи о других функциях Firebase ML Kit:



Однако, реализовать детектор лиц в собственном приложении по-прежнему нелегко. Нужно понять, как работает API, какую информацию он предоставляет, как её обрабатывать и использовать, учитывая ориентацию устройства, источник камеры и выбранную камеру (переднюю или заднюю).


В идеале мы должны получить код вроде этого:


camera.addFrameProcessor { frame -> 
    faceDetector.detectFaces(frame) 
}

Основные компоненты здесь — это camera, frame, faceDetector. Прежде чем разобраться с каждым из них, предположим, что наш layout содержит сам компонент камеры и некий оверлей, на котором мы будем рисовать квадратики вокруг обнаруженных лиц.


<FrameLayout
    ...>

    // Any other views

    <CameraView
        ... />

    <husaynhakeem.io.facedetector.FaceBoundsOverlay
        ... />

    // Any other views

</FrameLayout>

Камера (Camera)


Независимо от того, какой API-интерфейс камеры мы используем, самое главное, чтобы он предоставлял способ обработки отдельных кадров. Таким образом, мы сможем обрабатывать каждый входящий кадр, идентифицировать лица в нём и отображать это пользователю.


Кадр (Frame)


Кадр представляет собой информацию, предоставленную камерой, для обнаружения лиц. Он должен содержать всё, что требуется детектору лиц для их обнаружения. Эта необходимая информация определяется ниже:


data class Frame(
    val data: ByteArray?,
    val rotation: Int,
    val size: Size,
    val format: Int,
    val isCameraFacingBack: Boolean)

data class Size(val width: Int, val height: Int)

  • data — массив байтов, содержащий информацию о том, что камера отображает;
  • rotation — ориентация устройства;
  • size — ширина и высота предпросмотра камеры;
  • format — формат кодирования кадров;
  • isCameraFacingBack — указывает, используется ли передняя камера или задняя.

Детектор лиц (Face Detector)


Детектор лиц является самым важным компонентом — он берёт кадр, обрабатывает его и затем выводит результаты пользователю. Таким образом, детектор лиц использует экземпляр FirebaseVisionFaceDetector для обработки входящих кадров с камеры. Он также должен знать ориентацию камеры и её направление (передняя или задняя). Наконец, он должен знать на каком оверлее будут отображаться результаты. Скелет класса FaceDetector выглядит так:


class FaceDetector(private val faceBoundsOverlay: FaceBoundsOverlay) {

    private val faceBoundsOverlayHandler = FaceBoundsOverlayHandler()
    private val firebaseFaceDetectorWrapper = FirebaseFaceDetectorWrapper()

    fun process(frame: Frame) {
        updateOverlayAttributes(frame)
        detectFacesIn(frame)
    }

    private fun updateOverlayAttributes(frame: Frame) {
        faceBoundsOverlayHandler.updateOverlayAttributes(...)
    }

    private fun detectFacesIn(frame: Frame) {
        firebaseFaceDetectorWrapper.process(
                image = convertFrameToImage(frame),
                onSuccess = {
                    faceBoundsOverlay.updateFaces( /* Faces */)
                },
                onError = { /* Display error message */ })
    }
}

Оверлей (Overlay)


Оверлей — это View-компонент, который находится поверх камеры. Он отображает рамки (или границы) вокруг обнаруженных лиц. Он должен знать ориентацию устройства, направление камеры (передняя или задняя) и размеры камеры (ширина и высота). Эта информация помогает определить, как рисовать границы вокруг обнаруженного лица, как масштабировать границы и следует ли их отражать.


class FaceBoundsOverlay @JvmOverloads constructor(
        ctx: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0) : View(ctx, attrs, defStyleAttr) {

    private val facesBounds: MutableList<FaceBounds> = mutableListOf()

    fun updateFaces(bounds: List<FaceBounds>) {
        facesBounds.clear()
        facesBounds.addAll(bounds)
        invalidate()
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        facesBounds.forEach {
            val centerX = /* Compute the center's x coordinate */
            val centerY = /* Compute the center's ycoordinate */
            drawBounds(it.box, canvas, centerX, centerY)
        }
    }

    private fun drawBounds(box: Rect, canvas: Canvas, centerX: Float, centerY: Float) {
        /* Compute the positions left, right, top and bottom */
        canvas.drawRect(
                left,
                top,
                right,
                bottom,
                boundsPaint)
    }
}

На приведённой ниже диаграмме показаны компоненты, описанные выше, и способы взаимодействия их друг с другом с момента, когда камера подаёт на вход кадр, до момента, когда результаты отображаются пользователю.


Взаимодействие компонентов детектора лиц


Создание приложения для обнаружения лиц в реальном времени за 3 шага


Используя библиотеку для обнаружения лиц (которая содержит код, описанный выше), создание приложения становится довольно простым.


В этом примере я выбрал следующую библиотеку камеры.


Шаг 1. Добавьте FaceBoundsOverlay поверх камеры.


<FrameLayout
    ...>

    // Any other views

    <CameraView
        ... />

    <husaynhakeem.io.facedetector.FaceBoundsOverlay
        ... />

    // Any other views

</FrameLayout>

Шаг 2. Определите экземпляр FaceDetection и подключите его к камере.


private val faceDetector: FaceDetector by lazy {
    FaceDetector(facesBoundsOverlay)
}
cameraView.addFrameProcessor {
    faceDetector.process(Frame(
            data = it.data,
            rotation = it.rotation,
            size = Size(it.size.width, it.size.height),
            format = it.format))
}

Шаг 3. Настройте Firebase в проекте.


Заключение


Обнаружение лиц — это мощный функционал, а ML Kit делает его доступным и позволяет разработчикам выполнять с его помощью более сложные функции, такие как распознавание лиц, что выходит за рамки простого обнаружения: важно не только обнаружить лицо, но и определить, чьё оно.


Скоро в Ml Kit планируют добавить новую функцию — распознавание контура лица. С её помощью можно будет обнаруживать более 100 точек вокруг лица и быстро обрабатывать их. Это потенциально может быть полезно в приложениях с использованием объектов дополненной реальности или виртуальных стикеров (таких как Snapchat). Вместе функционалом обнаружения лиц можно будет создать много интересных приложений.

Tags:
Hubs:
+11
Comments0

Articles