File size: 5,265 Bytes
80b326d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import cv2
import numpy as np
import os
import sys
from contextlib import contextmanager
import warnings

# Suppress warnings
warnings.filterwarnings("ignore")

try:
    from insightface.app import FaceAnalysis
    INSIGHTFACE_AVAILABLE = True
except ImportError:
    INSIGHTFACE_AVAILABLE = False

app = None

@contextmanager
def suppress_stdout_stderr():
    """A context manager that redirects stdout and stderr to devnull"""
    with open(os.devnull, "w") as devnull:
        old_stdout = sys.stdout
        old_stderr = sys.stderr
        sys.stdout = devnull
        sys.stderr = devnull
        try:
            yield
        finally:
            sys.stdout = old_stdout
            sys.stderr = old_stderr

def init_insightface():
    """Explicit initialization if needed outside import."""
    global app
    if not INSIGHTFACE_AVAILABLE:
        raise ImportError("InsightFace not installed. Please install it.")
    
    if app is None:
        # Provider options to reduce logging if possible (often needs env var)
        # But redirection is safer for C++ logs
        providers = ['CUDAExecutionProvider', 'CPUExecutionProvider']
        
        try:
            import onnxruntime as ort
            available = ort.get_available_providers()
            print(f"InsightFace: Available ONNX Providers: {available}")
            if 'CUDAExecutionProvider' not in available:
                print("WARNING: CUDAExecutionProvider not found. InsightFace will likely run on CPU.")
                print("To fix, install onnxruntime-gpu: pip install onnxruntime-gpu")
        except Exception as e:
            print(f"InsightFace: Could not check available providers: {e}")

        with suppress_stdout_stderr():
            app = FaceAnalysis(name='buffalo_l', providers=providers)
            app.prepare(ctx_id=0, det_size=(640, 640))
    return app

def detect_faces_insightface(frame):
    """

    Detect faces using InsightFace.

    Returns a list of dicts with 'bbox' and 'kps'.

    bbox is [x1, y1, x2, y2], kps is 5 keypoints (eyes, nose, mouth corners).

    """
    global app
    if app is None:
        init_insightface()

    faces = app.get(frame)
    results = []
    for face in faces:
        # Convert bbox to int
        bbox = face.bbox.astype(int)
        res = {
            'bbox': bbox, # [x1, y1, x2, y2]
            'kps': face.kps,
            'det_score': face.det_score
        }
        if hasattr(face, 'landmark_2d_106') and face.landmark_2d_106 is not None:
             res['landmark_2d_106'] = face.landmark_2d_106
        if hasattr(face, 'landmark_3d_68') and face.landmark_3d_68 is not None:
             res['landmark_3d_68'] = face.landmark_3d_68
             
        results.append(res)
    return results

def crop_and_resize_insightface(frame, face_bbox, target_width=1080, target_height=1920):
    """

    Crops and resizes the frame to target dimensions centered on the face_bbox.

    face_bbox: [x1, y1, x2, y2]

    """
    h, w, _ = frame.shape
    x1, y1, x2, y2 = face_bbox
    
    face_center_x = (x1 + x2) // 2
    face_center_y = (y1 + y2) // 2
    
    # Calculate crop area based on target aspect ratio and face position
    # We want to keep the face roughly in the upper-middle or center?
    # Usually center for simple implementation, or slightly upper for "talking head".
    
    # Logic similar to one_face.py but adapted
    
    # Determine the scaling factor to ensure the crop covers the target height
    # Ideally we want the height of the video to match the target height after resize
    # But usually we source from landscape (16:9) to portrait (9:16).
    # We need to crop a 9:16 area from the source.
    
    # Calculate source crop height/width maintaining 9:16 ratio
    # Trying to maximize height usage of the source frame usually.
    
    # Let's say we want to use the full height of the source if possible
    source_h = h
    source_w = int(source_h * (target_width / target_height))
    
    if source_w > w:
        # If the calculated width is wider than the source image, we are limited by width
        source_w = w
        source_h = int(source_w * (target_height / target_width))

    # Calculate top-left corner of the crop
    crop_x1 = face_center_x - (source_w // 2)
    crop_y1 = face_center_y - (source_h // 2) # Center vertically on face
    
    # Adjust to stay within bounds
    if crop_x1 < 0: 
        crop_x1 = 0
    elif crop_x1 + source_w > w:
        crop_x1 = w - source_w
        
    if crop_y1 < 0:
        crop_y1 = 0
    elif crop_y1 + source_h > h:
        crop_y1 = h - source_h
        
    crop_x2 = crop_x1 + source_w
    crop_y2 = crop_y1 + source_h
    
    # Crop
    cropped = frame[crop_y1:crop_y2, crop_x1:crop_x2]
    
    # Resize to final target
    result = cv2.resize(cropped, (target_width, target_height), interpolation=cv2.INTER_LINEAR)
    
    return result

if __name__ == "__main__":
    # Test block
    print("Testing InsightFace...")
    # Create a dummy image or try to load one if available, but for now just print config
    print("InsightFace initialized.")