Подтвердить что ты не робот

Как я могу достичь этого в opencv с аффинным преобразованием?

Мне было интересно, как бы я воспроизвел то, что делается на этом изображении: введите описание изображения здесь

Чтобы разбить его:

  • Получить ориентиры лица с помощью dlib (зеленые точки)
  • Поверните изображение так, чтобы глаза были горизонтальными.
  • Найдите среднюю точку лица, усредняя левый самый и самый правый ориентир (синяя точка) и центрируйте изображение по оси x
  • Закрепите положение вдоль оси y, разместив центр глаз на 45% от верхней части изображения, а центр рта 25% от изображения

Сейчас это то, что у меня есть: введите описание изображения здесь

Я как бы застрял на шаге 3, который, я думаю, может быть сделан аффинным преобразованием? Но я полностью ошеломлен на шаге 4, я понятия не имею, как бы я этого добился.

Скажите, пожалуйста, если вам нужно, чтобы я предоставил код!

РЕДАКТОР: Итак, посмотрев на ответ @Gal Dreiman, я смог полностью сосредоточить лицо так, чтобы синяя точка была в центре моего изображения.

введите описание изображения здесь

Хотя, когда я выполнил вторую часть своего ответа, я получаю что-то вроде этого:

введите описание изображения здесь

Я вижу, что точки были преобразованы в правильные места, но это не тот результат, который я желал, поскольку он выглядит довольно резко. Любые идеи?

ИЗМЕНИТЬ 2:

После переключения координат x, y для центральных точек, это то, что я получил:

введите описание изображения здесь

4b9b3361

Ответ 1

Как я вижу вас в разделе 3, самый простой способ сделать это:

  • Найдите грани на изображении:

    faces = faceCascade.detectMultiScale(
        gray,
        scaleFactor=1.1,
        minNeighbors=5,
        minSize=(30, 30),
        flags = cv2.cv.CV_HAAR_SCALE_IMAGE
    )
    
  • Для каждого лица вычисляют середину:

    for (x, y, w, h) in faces:
        mid_x = x + int(w/2)
        mid_y = y + int(h/2)
    
  • Аффинное преобразование изображения в центр синей точки, которую вы уже рассчитали:

    height, width = img.shape
    x_dot = ...
    y_dot = ...
    
    dx_dot = int(width/2) - x_dot
    dy_dot = int(height/2) - y_dot
    
    M = np.float32([[1,0,dx_dot],[0,1,dy_dot]])
    dst = cv2.warpAffine(img,M,(cols,rows))
    

Надеюсь, что это было полезно.

Изменить:

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

    p_1 = [eyes_x, eye_y]
    p_2 = [int(width/2),int(height/2)] # default: center of the image
    p_3 = [mouth_x, mouth_y]

    target_p_1 = [eyes_x, int(eye_y * 0.45)]
    target_p_2 = [int(width/2),int(height/2)] # don't want to change
    target_p_3 = [mouth_x, int(mouth_y * 0.75)]

    pts1 = np.float32([p_1,p_2,p_3])
    pts2 = np.float32([target_p_1,target_p_2,target_p_3])

    M = cv2.getAffineTransform(pts1,pts2)

    output = cv2.warpAffine(image,M,(height,width))

Чтобы прояснить ситуацию:

  • eye_x/eye_y - расположение центра глаз.
  • То же самое относится к mouth_x/mouth_y для центра рта.
  • target_p_1/2/3 являются целевыми точками.

Изменить 2: Я вижу, что у вас проблемы, надеюсь, на этот раз мое предложение будет работать для вас:

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

up_left = [x,y]
up_right = [...]
down_left = [...]
down_right = [...]

pts1 = np.float32([up_left,up_right,down_left,down_right])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])

M = cv2.getPerspectiveTransform(pts1,pts2)

dst = cv2.warpPerspective(img,M,(300,300))

Итак, все, что вам нужно сделать, это определить эти 4 балла. Мое предложение, вычислить контур вокруг лица (который вы уже сделали), а затем добавить delta_x и delta_y (или вычесть) в координаты.