Рубрики
Без рубрики

Иметь дело с ним в Python с выявлением лица

Автоматическое создание мема с использованием функций лица. Помечено Python, Opencv, Computerivery, Учебник.

Иметь дело с этим это мем, где стекла летают с экрана, а на лицо пользователя. Лучшие экземпляры этого мема делают это уникально.

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

Я получил идею для этого поста от Эрик Тари и его в браузере JavaScript версия из этого эффекта.

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

Инструменты обнаружения лица и создания GIF

Мы будем использовать DLIB get_frontal_face_detector вместе с Модель прогнозирования формы 68 точек Мы использовали в Линз Snapchat статья.

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

Нам нужно будет затем масштабировать и повернуть наши очки, чтобы соответствовать лицу каждого человека. Мы будем использовать набор очков, возвращаемых из модели 68 точек DLIB, чтобы найти центр массы для глаз, и вращение для пространства между ними.

После того, как мы нашли конечную позицию и вращение для очков, мы можем затем оживить GIF, со стеклами, идущими от верхней части экрана. Мы нарисуем это с помощью Movelpy и A make_frame функция.

Архитектура автоматических GIFS

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

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

Мы можем накапливать набор граней и их окончательные позиции, добавляя их в список.

Наконец, с этим списком мы можем затем создать рутину рисования, используя MoviePy, который затем генерирует наш анимированный GIF.

Написание кода

С нашей архитектурой кода запланировано, следующее, что нам нужно сделать, это построить наш код шаг за шагом.

Сначала мы импортируем все наши инструменты и принимаем изображение из командной строки:

import dlib
from PIL import Image
import argparse

from imutils import face_utils
import numpy as np

import moviepy.editor as mpy

parser = argparse.ArgumentParser()
parser.add_argument("-image", required=True, help="path to input image")
args = parser.parse_args()

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

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

На данный момент мы также должны обнаруживать, обнаружены ли даже какие-либо лица, обнаруженные на изображении. Если нет, мы должны немедленно выйти.

detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68.dat')

# resize to a max_width to keep gif size small
max_width = 500

# open our image, convert to rgba
img = Image.open(args.image).convert('RGBA')

# two images we'll need, glasses and deal with it text
deal = Image.open("deals.png")
text = Image.open('text.png')

if img.size[0] > max_width:
    scaled_height = int(max_width * img.size[1] / img.size[0])
    img.thumbnail((max_width, scaled_height))

img_gray = np.array(img.convert('L')) # need grayscale for dlib face detection

rects = detector(img_gray, 0)

if len(rects) == 0:
    print("No faces found, exiting.")
    exit()

print("%i faces found in source image. processing into gif now." % len(rects))

Здорово! Теперь мы можем закрутить каждый из обнаруженных граней и создать список масштабированных и повернутых очков вместе с их конечными позициями.

faces = []

for rect in rects:
    face = {}
    print(rect.top(), rect.right(), rect.bottom(), rect.left())
    shades_width = rect.right() - rect.left()

    # predictor used to detect orientation in place where current face is
    shape = predictor(img_gray, rect)
    shape = face_utils.shape_to_np(shape)

    # grab the outlines of each eye from the input image
    leftEye = shape[36:42]
    rightEye = shape[42:48]

    # compute the center of mass for each eye
    leftEyeCenter = leftEye.mean(axis=0).astype("int")
    rightEyeCenter = rightEye.mean(axis=0).astype("int")

    # compute the angle between the eye centroids
    dY = leftEyeCenter[1] - rightEyeCenter[1] 
    dX = leftEyeCenter[0] - rightEyeCenter[0]
    angle = np.rad2deg(np.arctan2(dY, dX)) 

    # resize glasses to fit face width
    current_deal = deal.resize((shades_width, int(shades_width * deal.size[1] / deal.size[0])),
                               resample=Image.LANCZOS)
    # rotate and flip to fit eye centers
    current_deal = current_deal.rotate(angle, expand=True)
    current_deal = current_deal.transpose(Image.FLIP_TOP_BOTTOM)

    # add the scaled image to a list, shift the final position to the
    # left of the leftmost eye
    face['glasses_image'] = current_deal
    left_eye_x = leftEye[0,0] - shades_width // 4
    left_eye_y = leftEye[0,1] - shades_width // 6
    face['final_pos'] = (left_eye_x, left_eye_y)
    faces.append(face)

С нашими заключительными позициями на месте вместе с нашими масштабированными и повернутыми стеклами мы можем затем собрать наш фильм. Мы установим продолжительность всего GIF, а также время остановки очков, поэтому мы можем поставить сделку с ним текст на экране.

# how long our gif should be
duration = 4

def make_frame(t):
    draw_img = img.convert('RGBA') # returns copy of original image

    if t == 0: # no glasses first image
        return np.asarray(draw_img)

    for face in faces: 
        if t <= duration - 2: # leave 2 seconds for text
            current_x = int(face['final_pos'][0]) # start from proper x
            current_y = int(face['final_pos'][1] * t / (duration - 2)) # move to position w/ 2 secs to spare
            draw_img.paste(face['glasses_image'], (current_x, current_y) , face['glasses_image'])
        else: # draw the text for last 2 seconds
            draw_img.paste(face['glasses_image'], face['final_pos'], face['glasses_image'])
            draw_img.paste(text, (75, draw_img.height // 2 - 32), text)

    return np.asarray(draw_img)

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

Наконец, нам нужно создать Видеоклип Объект в Movelpy и пропустите в нашей анимационной раме вместе с FPS.

animation = mpy.VideoClip(make_frame, duration=duration)
animation.write_gif("deal.gif", fps=4)

С этим мы закончили!

Анимация мем в реальном времени

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

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

        # I got lazy, didn't want to bother with transparent pngs in opencv
        # this is probably slower than it should be
        if dealing:
            if current_animation < glasses_on:
                current_y = int(current_animation / glasses_on * left_eye_y)
                img.paste(current_deal, (left_eye_x, current_y), current_deal)
            else:
                img.paste(current_deal, (left_eye_x, left_eye_y), current_deal)
                img.paste(text, (75, img.height // 2 - 32), text)

    if dealing:
        current_animation += 1
        if current_animation > animation_length:
            dealing = False
            current_animation = 0
        else:
            frame = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
   cv2.imshow("deal generator", frame)
   key = cv2.waitKey(1) & 0xFF
    if key == ord("q"):
        break

    if key == ord("d"):
        dealing = not dealing

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

Вы можете прочитать остаток кода для этого на Github Отказ

Куда пойти отсюда

Мы успешно построили самую первую часть в программе, которая может быть использована в качестве API для автоматического генерации MEMES.

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

Что касается чего-то вроде YouTube-DL, у нас могут быть вставки пользователей в видео URL YouTube, чтобы автоматически генерировать MEMES.

Если вы пропустили его, код доступен в Github Отказ

Если вы заинтересованы в таких как эти проекты, пожалуйста, зарегистрируйтесь учетной записи на Сделать искусство с Python Отказ Вы получите первые три главы моей новой книги, когда вы делаете, и вы поможете мне продолжать делать такие проекты.

Оригинал: “https://dev.to/burningion/deal-with-it-in-python-with-face-detection-chi”