Находим лица в картинке с веб-камеры
Сегодня сделаем модную штуку в Python — научимся находить лица в веб-камере. Потом научимся делать то же самое на картинах, а затем на основе этого сделаем много разного и интересного.
Вот что нужно для начала знать о распознавании лиц:
- Для распознавания лица компьютер должен получить изображение — через камеру или готовый файл.
- Компьютер использует особый алгоритм, который разбивает изображение на прямоугольники.
- С помощью этих прямоугольников алгоритм пытается найти на картинке знакомые ему переходы между светлыми и тёмными областями.
- Если в одном месте программа находит много таких совпадений, то, скорее всего, это лицо человека.
- Чтобы программистам каждый раз не писать свой код распознавания с нуля, сделали специальную библиотеку компьютерного зрения — cv2. Если в неё загрузить заранее подготовленные параметры лиц, она сможет распознавать их намного точнее.
- С помощью этой библиотеки можно находить на картинке не только лица, но и другие предметы — для этого нужно использовать дополнительные библиотеки либо обучать систему самому.
Сегодня мы научимся работать с этой библиотекой компьютерного зрения и определим лицо человека в кадре:
Логика проекта
- Установим и подключим библиотеку cv2.
- Получим изображение с камеры и выведем его в отдельном окне.
- Обучим библиотеку находить лица.
- Напишем функцию выделения лиц на изображении.
- Объединим всё вместе и получим выделение лица с камеры в режиме реального времени.
Для проекта нам понадобится Python — это идеальный язык для работы с нейросетями и компьютерным зрением.
Устанавливаем cv2
Для установки библиотеки запустим терминал или VS Code и выполним такую команду:
Теперь убедимся, что это сработало: создаём новый Python-файл и пишем в нём команду:
# подключаем библиотеку компьютерного зрения import cv2
Если после запуска скрипта ошибок нет — всё установилось правильно и можно двигаться дальше.
Получаем изображение с камеры
По умолчанию библиотека работает с веб-камерой, которая в системе установлена первой (и часто — единственной). Так как нумерация в программировании почти всегда начинается с нуля, нам нужно обратиться к нулевому устройству видеозахвата.
В современных операционных системах в целях безопасности доступ к камере отключён для внешних скриптов, поэтому при первом запуске у нас могут спросить: разрешить доступ к камере или нет? Выбираем вариант «Да, разрешить»:
После этого делаем так: пока не нажата любая клавиша — выводим окошко с изображением. Но может случиться так, что доступ к камере есть, а с самой камерой что-то не так — нет картинки, например. В этом случае нет смысла пытаться определить лица — лучше сразу прекратить работу. Для этого мы проверяем параметр hasFrame — он как раз отвечает за то, есть картинка или нет.
Добавляем этот код в файл, сохраняем и запускаем скрипт:
# получаем видео с камеры video=cv2.VideoCapture(0) # пока не нажата любая клавиша — выполняем цикл while cv2.waitKey(1)
Запускаем нейросеть для определения лиц
Чтобы библиотека компьютерного зрения могла уметь определять лица, её нужно этому научить. Для этого создадим внутреннюю нейросеть, которая уже натренирована на определение лиц, и используем её для наших задач.
Обученная нейросеть отличается тем, что в ней уже сформированы все слои виртуальных нейронов и правильно распределены веса каждого нейрона. Мы возьмём уже готовые веса и слои и положим их в ту же папку, что и скрипт. Эти файлы — результат работы программистов, которые уже обучили нейросеть на 25 тысячах фотографий.
Вот эти файлы нужно скачать и положить в ту же папку, что наш скрипт:
Теперь всё готово для создания нейросети по определению лица на изображении:
# загружаем веса для распознавания лиц faceProto="opencv_face_detector.pbtxt" # и конфигурацию самой нейросети — слои и связи нейронов faceModel="opencv_face_detector_uint8.pb" # запускаем нейросеть по распознаванию лиц faceNet=cv2.dnn.readNet(faceModel,faceProto)
Пишем функцию определения лиц
Компьютеру неважно, сколько лиц определять — одно или несколько, — поэтому мы сделаем универсальную функцию. Она возьмёт картинку, найдёт на ней все лица и обведёт их зелёной рамкой.
У функции на входе будет три параметра:
- модель определения лиц;
- кадр, в котором нужно найти все лица;
- порог срабатывания распознавания.
Кадр — это условный скриншот того, что видит камера. В секунду камера может обрабатывать от 15 до 60 кадров — это зависит от самой камеры и настроек операционной системы.
Порог определяет точность распознавания: если вероятность того, что перед нами лицо, больше порога, то это считается лицом. Поставим порог меньше — это поможет с картинкой плохого качества, но зато компьютер может начать видеть лица там, где их нет. Поставим порог повыше — мы будем уверены, что перед нами лицо, но стоит повернуть голову как-то не так или поменять свет, то алгоритм уже его не определит.
Модель определения — это алгоритм, по которому компьютер поймёт, что перед нами именно лицо. Его мы как раз сделали на предыдущем этапе
Выполним предварительную работу внутри функции:
- получим размеры кадра;
- превратим кадр в бинарный объект с помощью специального алгоритма;
- прогоним объект через модель распознавания;
- создадим массив для рамок — там будут храниться координаты рамок для всех найденных лиц.
# функция определения лиц def highlightFace(net, frame, conf_threshold=0.7): # делаем копию текущего кадра frameOpencvDnn=frame.copy() # высота и ширина кадра frameHeight=frameOpencvDnn.shape[0] frameWidth=frameOpencvDnn.shape[1] # преобразуем картинку в двоичный пиксельный объект blob=cv2.dnn.blobFromImage(frameOpencvDnn, 1.0, (300, 300), [104, 117, 123], True, False) # устанавливаем этот объект как входной параметр для нейросети net.setInput(blob) # выполняем прямой проход для распознавания лиц detections=net.forward() # переменная для рамок вокруг лица faceBoxes=[]
К этому моменту наша модель уже определила все лица в кадре, сохранила их у себя и готова работать дальше. Теперь мы можем проверить, насколько каждое определение превышает установленный порог — если значение выше порога, то это точно лицо.
Ещё мы сразу записываем координаты найденного блока с лицом в отдельный массив — он нам пригодится для отрисовки рамок вокруг лиц на картинке.
Результат работы функции — это сам кадр и массив с координатами рамок вокруг лиц.
# перебираем все блоки после распознавания for i in range(detections.shape[2]): # получаем результат вычислений для очередного элемента confidence=detections[0,0,i,2] # если результат превышает порог срабатывания — это лицо if confidence>conf_threshold: # формируем координаты рамки x1=int(detections[0,0,i,3]*frameWidth) y1=int(detections[0,0,i,4]*frameHeight) x2=int(detections[0,0,i,5]*frameWidth) y2=int(detections[0,0,i,6]*frameHeight) # добавляем их в общую переменную faceBoxes.append([x1,y1,x2,y2]) # рисуем рамку на кадре cv2.rectangle(frameOpencvDnn, (x1,y1), (x2,y2), (0,255,0), int(round(frameHeight/150)), 8) # возвращаем кадр с рамками return frameOpencvDnn,faceBoxes
Собираем всё вместе и запускаем скрипт
Единственное, что осталось сделать, — добавить в основной цикл вызов функции для определения лица и сделать проверку, когда определённых лиц нет:
# распознаём лица в кадре resultImg,faceBoxes=highlightFace(faceNet,frame) # если лиц нет if not faceBoxes: # выводим в консоли, что лицо не найдено print("Лица не распознаны")
Теперь скрипт можно запускать и проверять — на каком расстоянии перестанет работать компьютерное зрение и сколько человек одновременно система сможет распознать.
# подключаем библиотеку компьютерного зрения import cv2 # функция определения лиц def highlightFace(net, frame, conf_threshold=0.7): # делаем копию текущего кадра frameOpencvDnn=frame.copy() # высота и ширина кадра frameHeight=frameOpencvDnn.shape[0] frameWidth=frameOpencvDnn.shape[1] # преобразуем картинку в двоичный пиксельный объект blob=cv2.dnn.blobFromImage(frameOpencvDnn, 1.0, (300, 300), [104, 117, 123], True, False) # устанавливаем этот объект как входной параметр для нейросети net.setInput(blob) # выполняем прямой проход для распознавания лиц detections=net.forward() # переменная для рамок вокруг лица faceBoxes=[] # перебираем все блоки после распознавания for i in range(detections.shape[2]): # получаем результат вычислений для очередного элемента confidence=detections[0,0,i,2] # если результат превышает порог срабатывания — это лицо if confidence>conf_threshold: # формируем координаты рамки x1=int(detections[0,0,i,3]*frameWidth) y1=int(detections[0,0,i,4]*frameHeight) x2=int(detections[0,0,i,5]*frameWidth) y2=int(detections[0,0,i,6]*frameHeight) # добавляем их в общую переменную faceBoxes.append([x1,y1,x2,y2]) # рисуем рамку на кадре cv2.rectangle(frameOpencvDnn, (x1,y1), (x2,y2), (0,255,0), int(round(frameHeight/150)), 8) # возвращаем кадр с рамками return frameOpencvDnn,faceBoxes # загружаем веса для распознавания лиц faceProto="opencv_face_detector.pbtxt" # и конфигурацию самой нейросети — слои и связи нейронов faceModel="opencv_face_detector_uint8.pb" # запускаем нейросеть по распознаванию лиц faceNet=cv2.dnn.readNet(faceModel,faceProto) # получаем видео с камеры video=cv2.VideoCapture(0) # пока не нажата любая клавиша — выполняем цикл while cv2.waitKey(1)
Что дальше
В следующей части мы научим программу работать с файлами и познакомимся с параметрами запуска скрипта. Это нам пригодится и в других проектах.
Проходите подготовку на продвинутых курсах, чтобы не нейросети заменили вас, а вы создали нейросети. «Практикум» подобрал для вас фундаментальные и навыковые курсы, чтобы это сделать. Начните здесь, это бесплатно:
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.