summaryrefslogtreecommitdiff
path: root/megapixels/app/processors/face_landmarks_3d.py
blob: 3663364c7d4993fff4c20a24a8f77c9e9d990ea2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import os
from os.path import join
from pathlib import Path
import math

import cv2 as cv
import numpy as np
import imutils

from app.utils import im_utils, logger_utils
from app.models.bbox import BBox
from app.settings import app_cfg as cfg
from app.settings import types


class FaceLandmarks2D:

  # Estimates 2D facial landmarks
  import face_alignment

  def __init__(self, gpu=0):
    self.log = logger_utils.Logger.getLogger()
    device = f'cuda:{gpu}' if gpu > -1 else 'cpu'
    self.fa = face_alignment.FaceAlignment(face_alignment.LandmarksType._2D, device=device, flip_input=True)

  def landmarks(self, im, as_type=str):
    '''Calculates the 3D facial landmarks
    :param im: (numpy.ndarray) image
    :param as_type: (str) or (list) type to return data
    '''
    preds = self.fa.get_landmarks(im)
    # convert to comma separated ints
    # storing data as "[1,2], [3,4]" is larger file size than storing as "1,2,3,4"
    # storing a list object in Pandas seems to result in 30% larger CSV files
    # TODO optimize this
    preds_int = [list(map(int, x)) for x in preds[0]]  # list of ints
    if as_type is str:
      return ','.join([','.join(list(map(str,[x,y]))) for x,y in preds_int])
    else
      return preds_int


class FaceLandmarks3D:

  # Estimates 3D facial landmarks
  import face_alignment

  def __init__(self, gpu=0):
    self.log = logger_utils.Logger.getLogger()
    device = f'cuda:{gpu}' if gpu > -1 else 'cpu'
    self.fa = face_alignment.FaceAlignment(face_alignment.LandmarksType._3D, device=device, flip_input=False)

  def landmarks(self, im, as_type=str):
    '''Calculates the 3D facial landmarks
    :param im: (numpy.ndarray) image
    :param as_type: (str) or (list) type to return data
    '''
    preds = self.fa.get_landmarks(im)
    # convert to comma separated ints
    # storing data as "[1,2], [3,4]" is larger file size than storing as "1,2,3,4"
    # storing a list object in Pandas seems to result in 30% larger CSV files
    # TODO optimize this
    preds_int = [list(map(int, x)) for x in preds[0]]  # list of ints
    if as_type is str:
      return ','.join([','.join(list(map(str,[x,y]))) for x,y in preds_int])
    else
      return preds_int

  def draw(self, im):
    '''draws landmarks in 3d scene'''

    # TODO
    '''
    import face_alignment
    import numpy as np
    from mpl_toolkits.mplot3d import Axes3D
    import matplotlib.pyplot as plt
    from skimage import io

    # Run the 3D face alignment on a test image, without CUDA.
    fa = face_alignment.FaceAlignment(face_alignment.LandmarksType._3D, device='cuda:0', flip_input=True)

    input = io.imread('../test/assets/aflw-test.jpg')
    preds = fa.get_landmarks(input)[-1]

    #TODO: Make this nice
    fig = plt.figure(figsize=plt.figaspect(.5))
    ax = fig.add_subplot(1, 2, 1)
    ax.imshow(input)
    ax.plot(preds[0:17,0],preds[0:17,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)
    ax.plot(preds[17:22,0],preds[17:22,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)
    ax.plot(preds[22:27,0],preds[22:27,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)
    ax.plot(preds[27:31,0],preds[27:31,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)
    ax.plot(preds[31:36,0],preds[31:36,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)
    ax.plot(preds[36:42,0],preds[36:42,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)
    ax.plot(preds[42:48,0],preds[42:48,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)
    ax.plot(preds[48:60,0],preds[48:60,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)
    ax.plot(preds[60:68,0],preds[60:68,1],marker='o',markersize=6,linestyle='-',color='w',lw=2) 
    ax.axis('off')

    ax = fig.add_subplot(1, 2, 2, projection='3d')
    surf = ax.scatter(preds[:,0]*1.2,preds[:,1],preds[:,2],c="cyan", alpha=1.0, edgecolor='b')
    ax.plot3D(preds[:17,0]*1.2,preds[:17,1], preds[:17,2], color='blue' )
    ax.plot3D(preds[17:22,0]*1.2,preds[17:22,1],preds[17:22,2], color='blue')
    ax.plot3D(preds[22:27,0]*1.2,preds[22:27,1],preds[22:27,2], color='blue')
    ax.plot3D(preds[27:31,0]*1.2,preds[27:31,1],preds[27:31,2], color='blue')
    ax.plot3D(preds[31:36,0]*1.2,preds[31:36,1],preds[31:36,2], color='blue')
    ax.plot3D(preds[36:42,0]*1.2,preds[36:42,1],preds[36:42,2], color='blue')
    ax.plot3D(preds[42:48,0]*1.2,preds[42:48,1],preds[42:48,2], color='blue')
    ax.plot3D(preds[48:,0]*1.2,preds[48:,1],preds[48:,2], color='blue' )

    ax.view_init(elev=90., azim=90.)
    ax.set_xlim(ax.get_xlim()[::-1])
    plt.show()
    '''
    return im