refactor: changing projection
This commit is contained in:
parent
fdfed4c1ff
commit
97fbc9bdb3
|
@ -18,3 +18,6 @@ TODO: https://github.com/Rassibassi/mediapipeFacegeometryPython/blob/main/head_p
|
||||||
-> pnp -> pose estimation -> paramètres extrinsèques
|
-> pnp -> pose estimation -> paramètres extrinsèques
|
||||||
-> + param intrasèque (supposé connu, check site mediapipe)
|
-> + param intrasèque (supposé connu, check site mediapipe)
|
||||||
-> placer dans l'espace les textures -> et projeter dans le plan image
|
-> placer dans l'espace les textures -> et projeter dans le plan image
|
||||||
|
|
||||||
|
|
||||||
|
https://github.com/Rassibassi/mediapipeDemos
|
||||||
|
|
|
@ -15,6 +15,7 @@ from bodyparts import (
|
||||||
RightEye,
|
RightEye,
|
||||||
RightMoustache,
|
RightMoustache,
|
||||||
)
|
)
|
||||||
|
from face_geometry import PCF, get_metric_landmarks, procrustes_landmark_basis
|
||||||
from utils import (
|
from utils import (
|
||||||
LANDMARKS_BOTTOM_SIDE,
|
LANDMARKS_BOTTOM_SIDE,
|
||||||
LANDMARKS_LEFT_SIDE,
|
LANDMARKS_LEFT_SIDE,
|
||||||
|
@ -23,6 +24,13 @@ from utils import (
|
||||||
landmark2vec,
|
landmark2vec,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
points_idx = [33, 263, 61, 291, 199]
|
||||||
|
points_idx = points_idx + [key for (key, val) in procrustes_landmark_basis]
|
||||||
|
points_idx = list(set(points_idx))
|
||||||
|
points_idx.sort()
|
||||||
|
|
||||||
|
dist_coeff = np.zeros((4, 1))
|
||||||
|
|
||||||
|
|
||||||
class Environment:
|
class Environment:
|
||||||
"""The environment is the main class of the application.
|
"""The environment is the main class of the application.
|
||||||
|
@ -49,17 +57,39 @@ class Environment:
|
||||||
|
|
||||||
# create body parts
|
# create body parts
|
||||||
self.body_parts = [
|
self.body_parts = [
|
||||||
LeftEar(self),
|
# LeftEar(self),
|
||||||
RightEar(self),
|
# RightEar(self),
|
||||||
Head(self),
|
# Head(self),
|
||||||
RightMoustache(self),
|
# RightMoustache(self),
|
||||||
LeftMoustache(self),
|
# LeftMoustache(self),
|
||||||
LeftEye(self),
|
# LeftEye(self),
|
||||||
RightEye(self),
|
# RightEye(self),
|
||||||
Crown(self),
|
# Crown(self),
|
||||||
Mouth(self),
|
# Mouth(self),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
self.pcf = PCF(
|
||||||
|
near=1,
|
||||||
|
far=10000,
|
||||||
|
frame_height=self.camera_height,
|
||||||
|
frame_width=self.camera_width,
|
||||||
|
fy=self.camera_width,
|
||||||
|
)
|
||||||
|
|
||||||
|
# pseudo camera internals
|
||||||
|
self.focal_length = self.camera_width
|
||||||
|
self.center = (self.camera_width / 2, self.camera_height / 2)
|
||||||
|
self.camera_matrix = np.array(
|
||||||
|
[
|
||||||
|
[self.focal_length, 0, self.center[0]],
|
||||||
|
[0, self.focal_length, self.center[1]],
|
||||||
|
[0, 0, 1],
|
||||||
|
],
|
||||||
|
dtype="double",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.refine_landmarks = True
|
||||||
|
|
||||||
def start(self) -> None:
|
def start(self) -> None:
|
||||||
"""Start the environment."""
|
"""Start the environment."""
|
||||||
while self.cam.isOpened():
|
while self.cam.isOpened():
|
||||||
|
@ -82,7 +112,7 @@ class Environment:
|
||||||
self.draw_axis()
|
self.draw_axis()
|
||||||
|
|
||||||
# draw keypoints on top of frame
|
# draw keypoints on top of frame
|
||||||
# self.draw_keypoints()
|
self.draw_keypoints()
|
||||||
|
|
||||||
# draw avatar
|
# draw avatar
|
||||||
self.draw_avatar()
|
self.draw_avatar()
|
||||||
|
@ -99,7 +129,8 @@ class Environment:
|
||||||
"""Detect the keypoints on the frame."""
|
"""Detect the keypoints on the frame."""
|
||||||
with self.mp_face_mesh.FaceMesh(
|
with self.mp_face_mesh.FaceMesh(
|
||||||
max_num_faces=1,
|
max_num_faces=1,
|
||||||
refine_landmarks=True,
|
refine_landmarks=self.refine_landmarks,
|
||||||
|
static_image_mode=False,
|
||||||
min_detection_confidence=0.5,
|
min_detection_confidence=0.5,
|
||||||
min_tracking_confidence=0.5,
|
min_tracking_confidence=0.5,
|
||||||
) as face_mesh:
|
) as face_mesh:
|
||||||
|
@ -122,46 +153,37 @@ class Environment:
|
||||||
def compute_face_axis(self) -> None:
|
def compute_face_axis(self) -> None:
|
||||||
"""Compute the face axis."""
|
"""Compute the face axis."""
|
||||||
if self.results.multi_face_landmarks:
|
if self.results.multi_face_landmarks:
|
||||||
for face_landmarks in self.results.multi_face_landmarks:
|
face_landmarks = self.results.multi_face_landmarks[0]
|
||||||
# retreive points
|
landmarks = np.array([(lm.x, lm.y, lm.z) for lm in face_landmarks.landmark])
|
||||||
left_points = np.array([landmark2vec(face_landmarks.landmark[i]) for i in LANDMARKS_LEFT_SIDE])
|
landmarks = landmarks.T
|
||||||
right_points = np.array([landmark2vec(face_landmarks.landmark[i]) for i in LANDMARKS_RIGHT_SIDE])
|
|
||||||
bottom_points = np.array([landmark2vec(face_landmarks.landmark[i]) for i in LANDMARKS_BOTTOM_SIDE])
|
|
||||||
top_points = np.array([landmark2vec(face_landmarks.landmark[i]) for i in LANDMARKS_TOP_SIDE])
|
|
||||||
|
|
||||||
# compute center
|
if self.refine_landmarks:
|
||||||
self.center = np.mean(np.concatenate((left_points, right_points, bottom_points, top_points)), axis=0)
|
landmarks = landmarks[:, :468]
|
||||||
|
|
||||||
# compute axis
|
metric_landmarks, pose_transform_mat = get_metric_landmarks(landmarks.copy(), self.pcf)
|
||||||
self.x = np.mean(right_points - left_points, axis=0)
|
|
||||||
self.y = np.mean(top_points - bottom_points, axis=0)
|
|
||||||
self.z = np.cross(self.x, self.y)
|
|
||||||
|
|
||||||
# normalize axis
|
self.model_points = metric_landmarks[0:3, points_idx].T
|
||||||
self.x = self.x / np.linalg.norm(self.x)
|
|
||||||
self.y = self.y / np.linalg.norm(self.y)
|
# see here:
|
||||||
self.z = self.z / np.linalg.norm(self.z)
|
# https://github.com/google/mediapipe/issues/1379#issuecomment-752534379
|
||||||
|
pose_transform_mat[1:3, :] = -pose_transform_mat[1:3, :]
|
||||||
|
self.mp_rotation_vector, _ = cv2.Rodrigues(pose_transform_mat[:3, :3])
|
||||||
|
self.mp_translation_vector = pose_transform_mat[:3, 3, None]
|
||||||
|
|
||||||
def draw_axis(self) -> None:
|
def draw_axis(self) -> None:
|
||||||
"""Draw the face axis on the frame."""
|
"""Draw the face axis on the frame."""
|
||||||
for (axis, color, letter) in [
|
nose_tip = self.model_points[0]
|
||||||
(self.x, (0, 0, 255), "X"),
|
nose_tip_extended = 2.5 * self.model_points[0]
|
||||||
(self.y, (0, 255, 0), "Y"),
|
(nose_pointer2D, jacobian) = cv2.projectPoints(
|
||||||
(self.z, (255, 0, 0), "Z"),
|
np.array([nose_tip, nose_tip_extended]),
|
||||||
]:
|
self.mp_rotation_vector,
|
||||||
# compute start and end of axis
|
self.mp_translation_vector,
|
||||||
start = (
|
self.camera_matrix,
|
||||||
int(self.center[0] * self.camera_width),
|
dist_coeff,
|
||||||
int(self.center[1] * self.camera_height),
|
)
|
||||||
)
|
|
||||||
end = (
|
|
||||||
int(self.center[0] * self.camera_width + axis[0] * 100),
|
|
||||||
int(self.center[1] * self.camera_height + axis[1] * 100),
|
|
||||||
)
|
|
||||||
|
|
||||||
# draw axis + letter
|
nose_tip_2D, nose_tip_2D_extended = nose_pointer2D.squeeze().astype(int)
|
||||||
cv2.line(self.frame, start, end, color, 2)
|
cv2.line(self.frame, nose_tip_2D, nose_tip_2D_extended, (255, 0, 0), 2)
|
||||||
cv2.putText(self.frame, letter, end, cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
|
|
||||||
|
|
||||||
def draw_keypoints(self) -> None:
|
def draw_keypoints(self) -> None:
|
||||||
"""Draw the keypoints on the screen."""
|
"""Draw the keypoints on the screen."""
|
||||||
|
|
2659
src/face_geometry.py
Normal file
2659
src/face_geometry.py
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue