предисловие
В прошлой статье мы решали как экологические, так и сетевые проблемы, а в этой, когда COVID-19 еще бушует по миру, мы пытаемся с помощью ИИ сделать интересное приложение для автоматического ношения масок. В основном используйте OpenCV + CNN для извлечения координат ключевых точек лица, а затем подгоните изображение маски в качестве маски. Не забудьте выйти на улицу во время Национального дня и Праздника середины осени и не забудьте надеть маску, чтобы защитить себя.
Весь процесс ношения маски делится на три этапа:
- найди лицо на картинке
- Обнаружение маркеров ключевых точек на лицах
- Закройте рот и нос изображением маски
Распознавание лиц
Во-первых, нам нужно определить положение лица на изображении, что легко может сделать модуль DNN в OpenCV. Модель обнаружения обучается во фреймворке Caffe, мы получаем файл определения сети face_detector.prototxt и файл веса face_detector.caffemodel.
# defining prototxt and caffemodel paths
# 人脸检测模型
detector_model = args.detector_model
detector_weights = args.detector_weights
# load model
detector = cv2.dnn.readNetFromCaffe(detector_model, detector_weights)
capture = cv2.VideoCapture(0)
while True:
# capture frame-by-frame
success, frame = capture.read()
# get frame's height and width
height, width = frame.shape[:2] # 640×480
# resize and subtract BGR mean values, since Caffe uses BGR images for input
blob = cv2.dnn.blobFromImage(
frame, scalefactor=1.0, size=(300, 300), mean=(104.0, 177.0, 123.0),
)
# passing blob through the network to detect a face
detector.setInput(blob)
# detector output format:
# [image_id, class, confidence, left, bottom, right, top]
face_detections = detector.forward()
После вывода мы можем получить серийный номер лица, тип (лицо), достоверность, значения левой, нижней, правой и верхней координат.
# loop over the detections
for i in range(0, face_detections.shape[2]):
# extract confidence
confidence = face_detections[0, 0, i, 2]
# filter detections by confidence greater than the minimum threshold
if confidence > 0.5:
# get coordinates of the bounding box
box = face_detections[0, 0, i, 3:7] * np.array(
[width, height, width, height],
)
Мы выбираем все обнаруженные лица, отфильтровываем цели с уровнем достоверности менее 50% и получаем координаты целевого кадра лица.
Tip:
Ввод модели обнаружения лиц: (300, 300).При конвертации изображений обратите внимание, что входной формат Caffe — BGR.
Получите ключевые точки лица
Мы получили целевой кадр всех лиц ранее, а затем в качестве входных данных модели обнаружения ключевых точек лица мы можем получить ключевые точки, такие как глаза, брови, нос, рот, подбородок и контуры лица.
1. Обзор модели
Выбранной здесь моделью является HRNet, которая имеет отличительную параллельную структуру и может поддерживать представления с высоким разрешением в любое время, а не только путем восстановления представлений с высоким разрешением из представлений с низким разрешением. Университет науки и технологий Китая и Microsoft Research Asia выпустили новую модель оценки позы человека, которая обновила три записи COCO в этом году и была выбрана для CVPR 2019.
Он начинается с подсети с высоким разрешением и медленно присоединяется к подсетям от более высокого к более низкому разрешению. Что особенного, так это то, что он не полагается на один шаг повышения частоты дискретизации от низкого к высокому, который грубо объединяет низкоуровневые и высокоуровневые представления вместе; представления в разных масштабах.
Команда использовала единицы обмена для перемещения между различными подсетями: каждая подсеть может получать информацию из представлений, созданных другими подсетями. Таким образом, можно получить богатое представление с высоким разрешением.
Для получения более подробной информации, пожалуйста, обратитесь к проекту с открытым исходным кодом
https://github.com/HRNet/HRNet-Facial-Landmark-Detection
2. Обрежьте изображение лица
Обратите внимание на то, как здесь настраивается размер лица, потому что выходной целевой кадр модели обнаружения лица может быть слишком близко к лицу, поэтому мы не можем напрямую использовать точные координаты кадра обнаружения для кадрирования изображения. Здесь лицо сначала увеличивается в 1,5 раза, а затем кадрируется картинка 256*256 относительно центрального положения.
(x1, y1, x2, y2) = box.astype("int")
# crop to detection and resize
resized = crop(
frame,
torch.Tensor([x1 + (x2 - x1) / 2, y1 + (y2 - y1) / 2]),
1.5,
tuple(input_size),
)
3. Предварительная обработка входных изображений HRNet
Преобразование формата изображения, нормализация предварительной обработки
# convert from BGR to RGB since HRNet expects RGB format
resized = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB)
img = resized.astype(np.float32) / 255.0
# normalize landmark net input
normalized_img = (img - mean) / std
Tip:
Обратите внимание, что входное изображение в HRNet находится в формате RGB.
4. Построение модели
# init landmark model
# 人脸关键点模型
model = models.get_face_alignment_net(config)
# get input size from the config
input_size = config.MODEL.IMAGE_SIZE
# load model
state_dict = torch.load(args.landmark_model, map_location=device)
# remove `module.` prefix from the pre-trained weights
new_state_dict = OrderedDict()
for key, value in state_dict.items():
name = key[7:]
new_state_dict[name] = value
# load weights without the prefix
model.load_state_dict(new_state_dict)
# run model on device
model = model.to(device)
5. Вывод модели
Введите предварительно обработанное изображение в сеть HRnet, чтобы получить данные о метках 68 лиц, а затем вызовите функцию decode_preds, чтобы восстановить предыдущую обрезку и масштабирование изображения и получить координаты ключевой точки на основе исходного изображения.
# predict face landmarks
model = model.eval()
with torch.no_grad():
input = torch.Tensor(normalized_img.transpose([2, 0, 1]))
input = input.to(device)
output = model(input.unsqueeze(0))
score_map = output.data.cpu()
preds = decode_preds(
score_map,
[torch.Tensor([x1 + (x2 - x1) / 2, y1 + (y2 - y1) / 2])],
[1.5],
score_map.shape[2:4],
)
Привязка изображения маски
Теперь мы получили информацию о ключевых точках лица.Поскольку маска обычно закрывает нижнюю часть носа и верхнюю часть подбородка, выбранные координатные числа от 2 до 16. Эти ключевые точки.
1. Назовите изображение маски
Чтобы лучше выровнять изображения, нам нужно аннотировать изображения маски. Здесь вы можете использовать makeense, онлайн-инструмент для аннотаций с открытым исходным кодом. Легко и просто использовать.
https://www.makesense.ai/
Наконец, сохраните аннотации в формате csv.
2. Чтение координат ключевой точки
Здесь выбраны ключевые точки 2-16, 30, а начальные координаты ключевых точек равны 0.
# get chosen landmarks 2-16, 30 as destination points
# note that landmarks numbering starts from 0
dst_pts = np.array(
[
landmarks[1],
landmarks[2],
landmarks[3],
landmarks[4],
landmarks[5],
landmarks[6],
landmarks[7],
landmarks[8],
landmarks[9],
landmarks[10],
landmarks[11],
landmarks[12],
landmarks[13],
landmarks[14],
landmarks[15],
landmarks[29],
],
dtype="float32",
)
# load mask annotations from csv file to source points
mask_annotation = os.path.splitext(os.path.basename(args.mask_image))[0]
mask_annotation = os.path.join(
os.path.dirname(args.mask_image), mask_annotation + ".csv",
)
with open(mask_annotation) as csv_file:
csv_reader = csv.reader(csv_file, delimiter=",")
src_pts = []
for i, row in enumerate(csv_reader):
# skip head or empty line if it's there
try:
src_pts.append(np.array([float(row[1]), float(row[2])]))
except ValueError:
continue
src_pts = np.array(src_pts, dtype="float32")
3. Привязать координаты ключевой точки
dst_pts — координаты обнаруженного лица, src_pts — координаты маркера изображения маски.
# overlay with a mask only if all landmarks have positive coordinates:
if (landmarks > 0).all():
# load mask image
mask_img = cv2.imread(args.mask_image, cv2.IMREAD_UNCHANGED)
mask_img = mask_img.astype(np.float32)
mask_img = mask_img / 255.0
# get the perspective transformation matrix
M, _ = cv2.findHomography(src_pts, dst_pts)
# transformed masked image
transformed_mask = cv2.warpPerspective(
mask_img,
M,
(result.shape[1], result.shape[0]),
None,
cv2.INTER_LINEAR,
cv2.BORDER_CONSTANT,
)
# mask overlay
alpha_mask = transformed_mask[:, :, 3]
alpha_image = 1.0 - alpha_mask
for c in range(0, 3):
result[:, :, c] = (
alpha_mask * transformed_mask[:, :, c]
+ alpha_image * result[:, :, c]
)
# display the resulting frame
cv2.imshow("image with mask overlay", result)
Здесь функция findHomography из библиотеки OpenCV используется для поиска преобразований между совпадающими ключевыми точками, а затем применяется найденная матрица преобразования с функцией warpPerspective для сопоставления этих точек.
Получите новое изображение transform_mask того же размера, что и исходный результат изображения, определите прозрачный канал alpha_mask в формате png и объедините два изображения вместе.
4. Установите зависимости
Сначала установите зависимость yacs, чтобы прочитать файл определения сетевой структуры.
pip install yacs
5. Запустите модель на Raspberry Pi.
python overlay_with_mask.py
--cfg experiments/300w/face_alignment_300w_hrnet_w18.yaml
--landmark_model HR18-300W.pth
--mask_image masks/anti_covid.png
--device cpu
Объясните параметры:
cfg: файл конфигурации сети для HRNet
ориентир: файл весов HRNet
mask_image: изображение маски
устройство: устройство вывода
Скорость относительно низкая, но он все еще может нормально рассуждать, что указывает на отсутствие проблем с нашей предыдущей средой pytorch. Raspberry Pi полностью загружен и вот-вот задымится. .
Tip:
Здесь есть ошибка в OpenVINO, в основном вызванная переносимостью 32-битной ОС. Замените i64 nGraph на i32 для size_t, измените исходный код nGraph, а затем перекомпилируйте его, чтобы решить проблему, или переключитесь на версию OpenCV 4.4, которую мы скомпилировали ранее.
https://github.com/openvinotoolkit/openvino/issues/1503
6. Запустите модель с графическим процессором
python overlay_with_mask.py
--cfg experiments/300w/face_alignment_300w_hrnet_w18.yaml
--landmark_model HR18-300W.pth
--mask_image masks/anti_covid.png
--device cuda
Скорость мышления немного выше, и видеокарта ноутбука GTX 1060 в принципе может играть. Тем не менее, отсечение модели, чтение масок изображений и операции ввода-вывода с метками файлов также являются избыточными. Две нейронные сети также могут быть распределены и работать на разных устройствах вывода и т. Д. Есть еще много возможностей для оптимизации. Если вам интересно , вы можете еще больше повысить скорость логического вывода.
Загрузка исходного кода
Для получения соответствующих документов и материалов в этом выпуске вы можете ответить на фоне официального аккаунта: «rpi12», чтобы получить ссылку для скачивания.
Следующее уведомление
Этот прикрыт маской, Следующий, Мы также будем использовать ИИ, Мозг наполняет твое благополучное лицо, Быть в курсе...