face-api.js: JS-интерфейс для распознавания лиц в браузере

GitHub JavaScript браузер API

Выбрано из IT Next, автор: Винсент Мюлер, составлено Heart of Machines, участие: Geek AI, Zhang Qian.

В этой статье будет представлен javascript API, построенный на ядре «tensorflow.js» — «face-api.js», который реализует три архитектуры сверточной нейронной сети для обнаружения лиц, распознавания и характерных точек. Для задач обнаружения распознавание лиц может выполняться в браузер.

Дополнительный! Дополнительный! Теперь люди наконец-то могут распознавать лица в браузере! В этой статье будет представлен «face-api.js», модуль javascript, построенный на ядре «tensorflow.js», который реализует три архитектуры сверточной нейронной сети (CNN) для задач обнаружения лиц, распознавания и обнаружения характерных точек.

Как обычно, мы рассмотрим простой пример кода, который позволит вам сразу же приступить к работе с API всего за несколько строк кода. Давайте начнем!

У нас уже есть «face-recognition.js», теперь есть еще один такой же пакет?

Если вы читали другую статью автора «Node.js + face-recognition.js: Простое и надежное распознавание лиц с использованием глубокого обучения» (Node.js + распознавание лиц с использованием глубокого обучения) о распознавании лиц в «node.js» environmentcognition.js: простое и надежное распознавание лиц с помощью глубокого обучения)(medium.com/@hengoosehailar.V/…), вы знаете, что он собирал аналогичный пакет раньше, например, «face-recgnition.js», который вводил функциональность распознавания лиц в «node.js».

Поначалу автор не предвидел столь высокого уровня востребованности пакетов, связанных с распознаванием лиц, в сообществе JavaScript. Многим «face-recognition.js» кажется хорошей бесплатной альтернативой с открытым исходным кодом платным службам распознавания лиц, предлагаемым такими компаниями, как Microsoft или Amazon. Но автора несколько раз спрашивали: можно ли запустить полный рабочий процесс распознавания лиц в браузере?

Благодаря «tensorflow.js» это видение наконец стало реальностью! Автору удалось реализовать некоторые подобные инструменты с использованием ядра "tf.js", и они дают почти те же результаты, что и "face-recognition.js", но автор проделал эту работу в браузере! И самое главное, этот инструмент не требует никаких внешних зависимостей, что делает его очень удобным в использовании. И этот набор инструментов также можно ускорить с помощью графического процессора, а соответствующие операции можно выполнять с помощью WebGL.

Этого достаточно, чтобы убедить меня в том, что сообществу JavaScript нужен такой пакет, написанный для среды браузера! Представьте, какие приложения вы можете создавать с его помощью.


Как использовать глубокое обучение для решения проблем с распознаванием лиц

Если вы хотите как можно скорее приступить к практической части, вы можете пропустить эту главу и сразу перейти к части анализа кода. Но чтобы лучше понять методы, используемые в face-api.js для реализации распознавания лиц, я настоятельно рекомендую вам дочитать эту главу, потому что мне часто задают этот вопрос.

Для простоты, чего мы на самом деле хотим добиться, так это, учитывая изображение лица, идентифицировать человека на изображении. Для достижения этой цели нам нужно предоставить каждому человеку, которого мы хотим идентифицировать, одно (или несколько) изображений их лиц и пометить эти изображения именем владельца лица в качестве справочных данных. Теперь мы сравниваем входное изображение с эталонными данными, чтобы найти эталонное изображение, наиболее похожее на входное изображение. Если есть два изображения, достаточно похожие на вход, то выводим имя человека, иначе выводим «неизвестно».

Звучит как действительно хорошая идея! Однако в этой схеме есть еще две проблемы. Во-первых, что, если бы у нас было изображение, показывающее нескольких людей, и нам нужно было бы идентифицировать их всех? Во-вторых, нам нужно установить меру подобия для сравнения двух изображений лиц.


Распознавание лиц

Ответ на первый вопрос мы можем найти в технологии распознавания лиц. Вкратце, мы сначала найдем все лица на входном изображении. «face-api.js» реализует алгоритм SSD (Single Shot Multibox Detector) для работы по обнаружению лиц, который по сути является сверточной нейронной сетью (CNN) на основе MobileNetV1, добавляя некоторые границы лица к верхнему слою сетевого прогнозирования.

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


Обнаружение характерных точек лица и выравнивание лица

Выше мы решили первую проблему! Тем не менее, я хотел бы отметить, что нам нужно выровнять ограничивающие рамки, чтобы мы извлекали изображение с лицами, центрированными в каждой ограничивающей рамке, и передавали его в качестве входных данных в сеть распознавания лиц, так как это делает распознавание лиц более точным!

Для достижения этой цели «face-api.js» реализует простую сверточную нейронную сеть (CNN), которая возвращает 68 ориентиров лица для данного изображения:

Исходя из положения характерных точек, ограничительная рамка может центрировать грань. Вы можете увидеть результат обнаружения лица (левое изображение) по сравнению с выровненным изображением лица (правое изображение) на изображении ниже:


распознавание лица

Теперь мы можем передать извлеченные выровненные изображения лиц в сеть распознавания лиц, которая основана на архитектуре, подобной ResNet-34, в основном такой же, как dlib (GitHub.com/Дэвис Кинг/…) соответствует архитектуре, реализованной в . Сеть была обучена обучению сопоставлению черт лица с дескрипторами лица (вектор признаков из 128 значений) — процессу, широко известному как встраивание лиц.

Теперь вернемся к исходной задаче сравнения двух изображений лица: мы будем использовать дескрипторы лица каждого извлеченного изображения лица и сравнивать их с дескрипторами лица эталонных данных. Точнее, мы можем вычислить евклидово расстояние между двумя дескрипторами лиц и судить о сходстве двух изображений лиц на основе порога (0,6 — хороший порог для 150*150 изображений). Использование евклидова расстояния работает на удивление хорошо, но, конечно, вы можете использовать любой классификатор. На гифке ниже визуализируется процесс сравнения двух изображений лиц по евклидову расстоянию:

Пока что у нас есть понимание теории распознавания лиц. Далее приступим к написанию примера кода.


Пора начинать программировать!

В этом коротком примере мы увидим, как шаг за шагом запустить программу распознавания лиц, чтобы распознать несколько людей на входном изображении, например:


скрипт импорта

Во-первых, получите последнюю версию из dist/face-api.js (GitHub.com/ Культура, которую он, как говорят, читает…), или получите уменьшенную версию из dist/face-api.min.js и импортируйте скрипт:

<script src="face-api.js"></script>

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

npm i face-api.js


Загрузить данные модели

Вы можете загрузить определенные модели, которые вам нужны, исходя из требований вашего приложения. Но для запуска полного сквозного примера нам также необходимо загрузить модели обнаружения лиц, обнаружения ориентиров лица и распознавания лиц. Соответствующие файлы моделей можно найти в репозитории кода по следующим ссылкам:GitHub.com/ Культура, которую он, как говорят, читает….

Среди них веса модели были квантованы, а размер файла был уменьшен на 75% по сравнению с исходной моделью, так что вашему клиенту нужно загрузить только минимально необходимые данные. Кроме того, веса модели разбиваются на фрагменты размером до 4 МБ, что позволяет браузерам кэшировать эти файлы, поэтому их нужно загрузить только один раз.

Файлы модели можно использовать непосредственно как статические ресурсы в вашем веб-приложении, или вы можете хранить их на другом хосте и загружать, указав путь или URL-ссылку на файл. Предположим, вы храните их в каталоге моделей, а ваши активы — в папке public/models:

const MODEL_URL = '/models'
await faceapi.loadModels(MODEL_URL)

Или, если вы просто хотите загрузить определенные модели:

const MODEL_URL = '/models'
await faceapi.loadFaceDetectionModel(MODEL_URL)
await faceapi.loadFaceLandmarkModel(MODEL_URL)
await faceapi.loadFaceRecognitionModel(MODEL_URL)


Получить полное описание всех лиц из входного изображения

В качестве входных данных нейронная сеть может получать HTML-изображения, холст, видеоэлементы или тензоры. Чтобы обнаружить ограничивающие прямоугольники лица на входном изображении с оценкой (score), превышающей минимальный порог (minScore), мы можем использовать следующую простую операцию:

const minConfidence = 0.8
const fullFaceDescriptions = await faceapi.allFaces(input, minConfidence)

Полный дескриптор лица содержит результаты обнаружения (ограничивающий прямоугольник + оценка), характерные точки лица и вычисленные дескрипторы. Как видите, «faceapi.allFaces» выполняет всю работу, описанную в предыдущих главах этой статьи, «под капотом». Однако вы также можете получить локализацию лица и характерные точки вручную. Если это ваша цель, вы можете обратиться к нескольким примерам в репозитории github.

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

const resized = fullFaceDescriptions.map(fd => fd.forSize(width, height))

Мы можем визуализировать результаты обнаружения, нарисовав ограничивающую рамку на холсте:

fullFaceDescription.forEach((fd, i) => {
  faceapi.drawDetection(canvas, fd.detection, { withScore: true })
})


Характерные точки лица можно отобразить следующими способами:

fullFaceDescription.forEach((fd, i) => {
  faceapi.drawLandmarks(canvas, fd.landmarks, { drawLines: true })
})

Обычно я накладываю абсолютно позиционированный холст с одинаковой шириной и высотой поверх элемента img (см. пример на github для получения дополнительной информации).


распознавание лица

Как только мы узнаем, как получить позиции и дескрипторы всех лиц на заданном изображении, мы получим несколько изображений, показывающих одного человека на изображении, и вычислим их дескрипторы лица. Эти дескрипторы будут служить нам в качестве справочных данных.

Предполагая, что у нас есть несколько образцов изображений для работы, мы сначала получаем изображения по URL-ссылке, а затем используем «faceapi.bufferToImage» для создания элементов изображения HTML из их буфера данных:

// fetch images from url as blobs
const blobs = await Promise.all(
  ['sheldon.png' 'raj.png', 'leonard.png', 'howard.png'].map(
    uri => (await fetch(uri)).blob()
  )
)

// convert blobs (buffers) to HTMLImage elements
const images = await Promise.all(blobs.map(
  blob => await faceapi.bufferToImage(blob)
))

Затем в каждом изображении, как мы делали с входным изображением ранее, мы локализуем лицо и вычисляем дескриптор лица:

const refDescriptions = await Promsie.all(images.map(
  img => (await faceapi.allFaces(img))[0]
))

const refDescriptors = refDescriptions.map(fd => fd.descriptor)

Теперь все, что нам нужно сделать, это перебрать дескрипторы лица нашего входного изображения и найти дескриптор в эталонных данных, который имеет наименьшее расстояние от входного изображения:

const sortAsc = (a, b) => a - b
const labels = ['sheldon', 'raj', 'leonard', 'howard']

const results = fullFaceDescription.map((fd, i) => {
  const bestMatch = refDescriptors.map(
    refDesc => ({
      label: labels[i],
      distance: faceapi.euclideanDistance(fd.descriptor, refDesc)
    })
  ).sort(sortAsc)[0]

  return {
    detection: fd.detection,
    label: bestMatch.label,
    distance: bestMatch.distance
  }
})

Как упоминалось ранее, мы используем здесь евклидово расстояние в качестве меры подобия, и это работает очень хорошо. Каждое лицо, которое мы обнаружили на входном изображении, было наилучшим совпадением.

Наконец, мы можем нарисовать ограничивающие рамки вместе с их метками на холсте, показывая результаты обнаружения:

// 0.6 is a good distance threshold value to judge
// whether the descriptors match or not
const maxDistance = 0.6

results.forEach(result => {
  faceapi.drawDetection(canvas, result.detection, { withScore: false })

  const text = `${result.distance < maxDistance ? result.className : 'unkown'} (${result.distance})`
  const { x, y, height: boxHeight } = detection.getBox()
  faceapi.drawText(
    canvas.getContext('2d'),
    x,
    y + boxHeight,
    text
  )
})

К этому моменту я надеюсь, что у вас есть начальное понимание того, как использовать этот API. В то же время я также рекомендую вам взглянуть на другие примеры в репозитории кода, приведенном в статье. Желаем приятно провести время с этим пакетом!

Оригинальная ссылка:IT next.IO/face-API - просто...