From a7a2551820703b1bd665dd0d4404e6d871078300 Mon Sep 17 00:00:00 2001 From: akafrenchy Date: Fri, 1 May 2026 09:31:59 +1000 Subject: [PATCH 1/5] Refactors MediaPipe FaceMesh imports for better flexibility --- src/dot/simswap/mediapipe/face_mesh.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/dot/simswap/mediapipe/face_mesh.py b/src/dot/simswap/mediapipe/face_mesh.py index 692c3e2..d3cb0a5 100644 --- a/src/dot/simswap/mediapipe/face_mesh.py +++ b/src/dot/simswap/mediapipe/face_mesh.py @@ -1,17 +1,16 @@ #!/usr/bin/env python3 -from typing import List, Optional, Tuple +from typing import List, Optional, Tuple, TYPE_CHECKING import cv2 -import mediapipe as mp import numpy as np -from mediapipe.framework.formats.landmark_pb2 import NormalizedLandmark + +if TYPE_CHECKING: + from mediapipe.framework.formats.landmark_pb2 import NormalizedLandmark from .utils import face_align_ffhqandnewarc as face_align from .utils import mediapipe_landmarks -mp_face_mesh = mp.solutions.face_mesh - class FaceMesh: """Wrapper class of Mediapipe's FaceMesh module. Extracts facial landmarks @@ -38,6 +37,14 @@ def __init__( min_detection_confidence: float = 0.5, mode: str = "None", ): + # Deferred MediaPipe import + try: + import mediapipe as mp + from mediapipe.framework.formats.landmark_pb2 import NormalizedLandmark + self.mp_face_mesh = mp.solutions.face_mesh + except ImportError as e: + raise RuntimeError(f"MediaPipe import failed: {e}") + self.MediaPipeIds = mediapipe_landmarks.MediaPipeLandmarks self.static_image_mode = static_image_mode self.max_num_faces = max_num_faces @@ -45,11 +52,11 @@ def __init__( self.min_detection_confidence = min_detection_confidence self.mode = mode - def _get_centroid(self, landmarks: List[NormalizedLandmark]) -> Tuple[float, float]: + def _get_centroid(self, landmarks: List["NormalizedLandmark"]) -> Tuple[float, float]: """Given a set of normalized landmarks/points finds centroid point Args: - landmarks (List[NormalizedLandmark]): List of relative points that form a polygon + landmarks (List["NormalizedLandmark"]): List of relative points that form a polygon Returns: Tuple[float, float]: x,y coordinates of polygon centroid @@ -88,7 +95,7 @@ def get_face_landmarks(self, image: np.ndarray) -> Optional[np.array]: """ # keypoints for all detected faces detection_kpss = [] - with mp_face_mesh.FaceMesh( + with self.mp_face_mesh.FaceMesh( static_image_mode=self.static_image_mode, max_num_faces=self.max_num_faces, refine_landmarks=self.refine_landmarks, From 57b1243fd122d4e94688534cd8ec905ec73ca624 Mon Sep 17 00:00:00 2001 From: akafrenchy Date: Fri, 1 May 2026 09:31:59 +1000 Subject: [PATCH 2/5] Improves directory handling for pretrained model loading --- src/dot/gpen/retinaface/retinaface_detection.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/dot/gpen/retinaface/retinaface_detection.py b/src/dot/gpen/retinaface/retinaface_detection.py index a371003..c4778dd 100644 --- a/src/dot/gpen/retinaface/retinaface_detection.py +++ b/src/dot/gpen/retinaface/retinaface_detection.py @@ -21,7 +21,11 @@ class RetinaFaceDetection(object): def __init__(self, base_dir, network="RetinaFace-R50", use_gpu=True): torch.set_grad_enabled(False) cudnn.benchmark = True - self.pretrained_path = os.path.join(base_dir, "weights", network + ".pth") + # If base_dir is empty or relative path, use saved_models/gpen/weights + if not base_dir or base_dir == "./": + self.pretrained_path = os.path.join("saved_models", "gpen", "weights", network + ".pth") + else: + self.pretrained_path = os.path.join(base_dir, "saved_models", "gpen", "weights", network + ".pth") if use_gpu: self.device = "mps" if torch.backends.mps.is_available() else "cuda" else: From 1f02caefff9817929210c742e3df5bfbd75b2898 Mon Sep 17 00:00:00 2001 From: akafrenchy Date: Fri, 1 May 2026 09:31:59 +1000 Subject: [PATCH 3/5] Fixes variable usage in video cropping logic --- src/dot/commons/video/video_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dot/commons/video/video_utils.py b/src/dot/commons/video/video_utils.py index 73a28f9..a14ab49 100644 --- a/src/dot/commons/video/video_utils.py +++ b/src/dot/commons/video/video_utils.py @@ -61,7 +61,7 @@ def _crop_and_pose( ) try: - crop_image = image[ytop:ybot, xleft:xright] + crop_image = image[yinset-block-start:ybot, xinset-inline-start:xright] if estimate_pose: if pose_estimation(image=crop_image, roll=3, pitch=3, yaw=3) != 0: return -1 From 8d88b7c98ca748b416aabdaca59129fc92191751 Mon Sep 17 00:00:00 2001 From: akafrenchy Date: Fri, 1 May 2026 09:31:59 +1000 Subject: [PATCH 4/5] Adds empty model checkpoint file --- dot_model_checkpoints.zip | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 dot_model_checkpoints.zip diff --git a/dot_model_checkpoints.zip b/dot_model_checkpoints.zip new file mode 100644 index 0000000..e69de29 From 4d77060e7c99fdb6a6a40a713d50b2a7c66e3bb4 Mon Sep 17 00:00:00 2001 From: akafrenchy Date: Fri, 1 May 2026 09:38:05 +1000 Subject: [PATCH 5/5] Handles missing dependencies with safe imports --- src/dot/commons/model_option.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/dot/commons/model_option.py b/src/dot/commons/model_option.py index 653198a..749824e 100644 --- a/src/dot/commons/model_option.py +++ b/src/dot/commons/model_option.py @@ -8,13 +8,19 @@ from abc import ABC, abstractmethod from typing import Dict, List, Optional, Tuple, Union -import cv2 -import torch +try: + import cv2 +except ModuleNotFoundError: + cv2 = None +try: + import torch +except ModuleNotFoundError: + torch = None from ..gpen.face_enhancement import FaceEnhancement from .camera_utils import camera_pipeline, fetch_camera from .utils import find_images_from_path, generate_random_file_idx, rand_idx_tuple -from .video.video_utils import video_pipeline +# from .video.video_utils import video_pipeline # Deferred import class ModelOption(ABC): @@ -211,6 +217,7 @@ def generate_from_video( duration (int): Trim target video in seconds. limit (int, optional): Limit number of video-swaps. Defaults to None. """ + from .video.video_utils import video_pipeline # Deferred import with torch.no_grad(): self.create_model(**kwargs) video_pipeline(