| import torch |
| import cv2 |
| import numpy as np |
| import sys |
| import os |
| from pathlib import Path |
|
|
| |
| sys.path.append(str(Path(__file__).parent.parent.parent)) |
| from src.models.teacher import load_teacher_model |
| from src.utils.preprocess import GazePreprocessor |
|
|
| def get_face_crop(frame, landmarks, target_size=(224, 224)): |
| h, w, _ = frame.shape |
| coords = np.array([[lm.x * w, lm.y * h] for lm in landmarks]) |
| min_x, min_y = np.min(coords, axis=0) |
| max_x, max_y = np.max(coords, axis=0) |
| width = max_x - min_x |
| height = max_y - min_y |
| center_x = (min_x + max_x) / 2 |
| center_y = (min_y + max_y) / 2 |
| size = max(width, height) * 1.5 |
| x1 = int(max(0, center_x - size / 2)) |
| y1 = int(max(0, center_y - size / 2)) |
| x2 = int(min(w, center_x + size / 2)) |
| y2 = int(min(h, center_y + size / 2)) |
| face_img = frame[y1:y2, x1:x2] |
| if face_img.size == 0: return None |
| face_img = cv2.resize(face_img, target_size) |
| face_img = cv2.cvtColor(face_img, cv2.COLOR_BGR2RGB) |
| face_img = face_img.astype(np.float32) / 255.0 |
| mean = np.array([0.485, 0.456, 0.406], dtype=np.float32) |
| std = np.array([0.229, 0.224, 0.225], dtype=np.float32) |
| face_img = (face_img - mean) / std |
| face_img = np.transpose(face_img, (2, 0, 1)) |
| return face_img, (x1, y1, x2, y2) |
|
|
| def draw_gaze(image, pitch, yaw, length=100, color=(0, 255, 0)): |
| |
| |
| |
| h, w = image.shape[:2] |
| cx, cy = w // 2, h // 2 |
| |
| |
| dx = -length * np.sin(np.radians(yaw)) |
| dy = -length * np.sin(np.radians(pitch)) |
| |
| cv2.line(image, (cx, cy), (int(cx + dx), int(cy + dy)), color, 3) |
| return image |
|
|
| def visualize_teacher(): |
| checkpoint_path = 'checkpoints/resnet50.pt' |
| |
| model_path = os.path.abspath('face_landmarker.task') |
| |
| device = 'cpu' |
| model = load_teacher_model(checkpoint_path, backbone='resnet50', device=device) |
| preprocessor = GazePreprocessor(model_path=model_path) |
| |
| |
| img_dir = 'data/MPIIGaze/MPIIGaze/MPIIGaze/Data/Original/p00/day01' |
| for i in range(1, 10): |
| img_path = os.path.join(img_dir, f"{i:04d}.jpg") |
| if not os.path.exists(img_path): continue |
| |
| print(f"Testing on {img_path}...") |
| frame = cv2.imread(img_path) |
| landmarks = preprocessor.get_landmarks(frame) |
| if landmarks is None: |
| print(f"No landmarks found for {img_path}.") |
| continue |
| |
| face_input, (x1, y1, x2, y2) = get_face_crop(frame, landmarks) |
| input_tensor = torch.from_numpy(face_input).unsqueeze(0).to(device) |
| |
| with torch.no_grad(): |
| p_logits, y_logits = model(input_tensor) |
| p_deg, y_deg = model.get_angles(p_logits, y_logits) |
| |
| print(f"Predicted: Pitch {p_deg.item():.2f}, Yaw {y_deg.item():.2f}") |
| |
| |
| face_vis = frame[y1:y2, x1:x2].copy() |
| face_vis = draw_gaze(face_vis, p_deg.item(), y_deg.item()) |
| |
| output_path = f'data/verification/teacher_test_{i}.png' |
| cv2.imwrite(output_path, face_vis) |
| print(f"Saved to {output_path}") |
| break |
|
|
| if __name__ == '__main__': |
| visualize_teacher() |
|
|