Spaces:
Paused
Paused
| import cv2 | |
| import numpy as np | |
| from ..utils.load_model import load_model | |
| class FaceMesh: | |
| def __init__(self, model_path, device="cuda"): | |
| self.model, self.model_type = load_model(model_path, device=device) | |
| self.input_size = (256, 256) # (w, h) | |
| self.output_names = [ | |
| "Identity", | |
| "Identity_1", | |
| "Identity_2", | |
| ] # Identity is the mesh | |
| def project_landmarks(self, points, roi): | |
| width, height = self.input_size | |
| points /= (width, height, width) | |
| sin, cos = np.sin(roi[4]), np.cos(roi[4]) | |
| matrix = np.array([[cos, sin, 0.0], [-sin, cos, 0.0], [1.0, 1.0, 1.0]]) | |
| points -= (0.5, 0.5, 0.0) | |
| rotated = np.matmul(points * (1, 1, 0), matrix) | |
| points *= (0, 0, 1) | |
| points += rotated | |
| points *= (roi[2], roi[3], roi[2]) | |
| points += (roi[0], roi[1], 0.0) | |
| return points | |
| def __call__(self, image, roi): | |
| """ | |
| image: np.ndarray, RGB, (H, W, C), [0, 255] | |
| roi: np.ndarray, (cx, cy, w, h, rotation), rotation in radian | |
| """ | |
| cx, cy, w, h = roi[:4] | |
| w_half, h_half = w / 2, h / 2 | |
| pts = [ | |
| (cx - w_half, cy - h_half), | |
| (cx + w_half, cy - h_half), | |
| (cx + w_half, cy + h_half), | |
| (cx - w_half, cy + h_half), | |
| ] | |
| rotation = roi[4] | |
| s, c = np.sin(rotation), np.cos(rotation) | |
| t = np.array(pts) - (cx, cy) | |
| r = np.array([[c, s], [-s, c]]) | |
| src_pts = np.matmul(t, r) + (cx, cy) | |
| src_pts = src_pts.astype(np.float32) | |
| dst_pts = np.array( | |
| [ | |
| [0.0, 0.0], | |
| [self.input_size[0], 0.0], | |
| [self.input_size[0], self.input_size[1]], | |
| [0.0, self.input_size[1]], | |
| ] | |
| ).astype(np.float32) | |
| M = cv2.getPerspectiveTransform(src_pts, dst_pts) | |
| roi_image = cv2.warpPerspective( | |
| image, M, self.input_size, flags=cv2.INTER_LINEAR | |
| ) | |
| # cv2.imwrite('test.jpg', cv2.cvtColor(roi_image, cv2.COLOR_RGB2BGR)) | |
| roi_image = roi_image / 255.0 | |
| roi_image = roi_image.astype(np.float32) | |
| roi_image = roi_image[np.newaxis, :, :, :] | |
| outputs = {} | |
| if self.model_type == "onnx": | |
| out_list = self.model.run(None, {"input": roi_image}) | |
| for i, name in enumerate(self.output_names): | |
| outputs[name] = out_list[i] | |
| elif self.model_type == "tensorrt": | |
| self.model.setup({"input": roi_image}) | |
| self.model.infer() | |
| for name in self.output_names: | |
| outputs[name] = self.model.buffer[name][0] | |
| else: | |
| raise ValueError(f"Unsupported model type: {self.model_type}") | |
| points = outputs["Identity"].reshape(1434 // 3, 3) | |
| points = self.project_landmarks(points, roi) | |
| return points | |
| if __name__ == "__main__": | |
| import argparse | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--model", type=str, help="model path") | |
| parser.add_argument("--image", type=str, help="image path") | |
| parser.add_argument("--device", type=str, default="cuda", help="device") | |
| args = parser.parse_args() | |
| face_mesh = FaceMesh(args.model, args.device) | |
| image = cv2.imread(args.image, cv2.IMREAD_COLOR) | |
| image = cv2.resize(image, (256, 256)) | |
| image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) | |
| face_mesh = FaceMesh(args.model, args.device) | |
| roi = np.array([128, 128, 256, 256, np.pi / 2]) | |
| mesh = face_mesh(image, roi) | |
| print(mesh.shape) | |