Создание приложений глубокого обучения с помощью масок Raspberry Pi 4b (12)

малиновый пирог
Создание приложений глубокого обучения с помощью масок Raspberry Pi 4b (12)

предисловие

В прошлой статье мы решали как экологические, так и сетевые проблемы, а в этой, когда 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», чтобы получить ссылку для скачивания.


Следующее уведомление

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