Download tddfa/utils/pose.py from ozyman/fasd: direct link, hf CLI and curl.
- Browser
- Download file 4.33 kB
-
https://huggingface.co/spaces/ozyman/fasd/resolve/main/tddfa/utils/pose.py
- Command line
-
hf download hf://spaces/ozyman/fasd/tddfa/utils/pose.py
-
curl -L -o pose.py https://huggingface.co/spaces/ozyman/fasd/resolve/main/tddfa/utils/pose.py
4.33 kB
| # coding: utf-8 | |
| """ | |
| Reference: https://github.com/YadiraF/PRNet/blob/master/utils/estimate_pose.py | |
| Calculating pose from the output 3DMM parameters, you can also try to use solvePnP to perform estimation | |
| """ | |
| __author__ = 'cleardusk' | |
| import cv2 | |
| import numpy as np | |
| from math import cos, sin, atan2, asin, sqrt | |
| from .functions import calc_hypotenuse, plot_image | |
| def P2sRt(P): | |
| """ decompositing camera matrix P. | |
| Args: | |
| P: (3, 4). Affine Camera Matrix. | |
| Returns: | |
| s: scale factor. | |
| R: (3, 3). rotation matrix. | |
| t2d: (2,). 2d translation. | |
| """ | |
| t3d = P[:, 3] | |
| R1 = P[0:1, :3] | |
| R2 = P[1:2, :3] | |
| s = (np.linalg.norm(R1) + np.linalg.norm(R2)) / 2.0 | |
| r1 = R1 / np.linalg.norm(R1) | |
| r2 = R2 / np.linalg.norm(R2) | |
| r3 = np.cross(r1, r2) | |
| R = np.concatenate((r1, r2, r3), 0) | |
| return s, R, t3d | |
| def matrix2angle(R): | |
| """ compute three Euler angles from a Rotation Matrix. Ref: http://www.gregslabaugh.net/publications/euler.pdf | |
| refined by: https://stackoverflow.com/questions/43364900/rotation-matrix-to-euler-angles-with-opencv | |
| todo: check and debug | |
| Args: | |
| R: (3,3). rotation matrix | |
| Returns: | |
| x: yaw | |
| y: pitch | |
| z: roll | |
| """ | |
| if R[2, 0] > 0.998: | |
| z = 0 | |
| x = np.pi / 2 | |
| y = z + atan2(-R[0, 1], -R[0, 2]) | |
| elif R[2, 0] < -0.998: | |
| z = 0 | |
| x = -np.pi / 2 | |
| y = -z + atan2(R[0, 1], R[0, 2]) | |
| else: | |
| x = asin(R[2, 0]) | |
| y = atan2(R[2, 1] / cos(x), R[2, 2] / cos(x)) | |
| z = atan2(R[1, 0] / cos(x), R[0, 0] / cos(x)) | |
| return x, y, z | |
| def calc_pose(param): | |
| P = param[:12].reshape(3, -1) # camera matrix | |
| s, R, t3d = P2sRt(P) | |
| P = np.concatenate((R, t3d.reshape(3, -1)), axis=1) # without scale | |
| pose = matrix2angle(R) | |
| pose = [p * 180 / np.pi for p in pose] | |
| return P, pose | |
| def build_camera_box(rear_size=90): | |
| point_3d = [] | |
| rear_depth = 0 | |
| point_3d.append((-rear_size, -rear_size, rear_depth)) | |
| point_3d.append((-rear_size, rear_size, rear_depth)) | |
| point_3d.append((rear_size, rear_size, rear_depth)) | |
| point_3d.append((rear_size, -rear_size, rear_depth)) | |
| point_3d.append((-rear_size, -rear_size, rear_depth)) | |
| front_size = int(4 / 3 * rear_size) | |
| front_depth = int(4 / 3 * rear_size) | |
| point_3d.append((-front_size, -front_size, front_depth)) | |
| point_3d.append((-front_size, front_size, front_depth)) | |
| point_3d.append((front_size, front_size, front_depth)) | |
| point_3d.append((front_size, -front_size, front_depth)) | |
| point_3d.append((-front_size, -front_size, front_depth)) | |
| point_3d = np.array(point_3d, dtype=np.float32).reshape(-1, 3) | |
| return point_3d | |
| def plot_pose_box(img, P, ver, color=(40, 255, 0), line_width=2): | |
| """ Draw a 3D box as annotation of pose. | |
| Ref:https://github.com/yinguobing/head-pose-estimation/blob/master/pose_estimator.py | |
| Args: | |
| img: the input image | |
| P: (3, 4). Affine Camera Matrix. | |
| kpt: (2, 68) or (3, 68) | |
| """ | |
| llength = calc_hypotenuse(ver) | |
| point_3d = build_camera_box(llength) | |
| # Map to 2d image points | |
| point_3d_homo = np.hstack((point_3d, np.ones([point_3d.shape[0], 1]))) # n x 4 | |
| point_2d = point_3d_homo.dot(P.T)[:, :2] | |
| point_2d[:, 1] = - point_2d[:, 1] | |
| point_2d[:, :2] = point_2d[:, :2] - np.mean(point_2d[:4, :2], 0) + np.mean(ver[:2, :27], 1) | |
| point_2d = np.int32(point_2d.reshape(-1, 2)) | |
| # Draw all the lines | |
| cv2.polylines(img, [point_2d], True, color, line_width, cv2.LINE_AA) | |
| cv2.line(img, tuple(point_2d[1]), tuple( | |
| point_2d[6]), color, line_width, cv2.LINE_AA) | |
| cv2.line(img, tuple(point_2d[2]), tuple( | |
| point_2d[7]), color, line_width, cv2.LINE_AA) | |
| cv2.line(img, tuple(point_2d[3]), tuple( | |
| point_2d[8]), color, line_width, cv2.LINE_AA) | |
| return img | |
| def viz_pose(img, param_lst, ver_lst, show_flag=False, wfp=None): | |
| for param, ver in zip(param_lst, ver_lst): | |
| P, pose = calc_pose(param) | |
| img = plot_pose_box(img, P, ver) | |
| # print(P[:, :3]) | |
| print(f'yaw: {pose[0]:.1f}, pitch: {pose[1]:.1f}, roll: {pose[2]:.1f}') | |
| if wfp is not None: | |
| cv2.imwrite(wfp, img) | |
| print(f'Save visualization result to {wfp}') | |
| if show_flag: | |
| plot_image(img) | |
| return img | |