File size: 3,762 Bytes
91491b1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
frame_processor.py
==================
Utilitas untuk preprocessing frame video sebelum dimasukkan ke model.
Termasuk: resize, quality enhancement, dan konversi format.
"""

import cv2
import numpy as np
from typing import Tuple, Optional


def decode_base64_frame(b64_string: str) -> Optional[np.ndarray]:
    """
    Decode string base64 menjadi frame OpenCV BGR.
    
    Args:
        b64_string: String base64 (dengan atau tanpa data URL prefix)
        
    Returns:
        numpy array [H, W, 3] BGR, atau None jika gagal
    """
    import base64

    # Hapus prefix data URL jika ada
    if "," in b64_string:
        b64_string = b64_string.split(",", 1)[1]

    try:
        # Decode base64 → bytes → numpy
        raw_bytes = base64.b64decode(b64_string)
        arr = np.frombuffer(raw_bytes, dtype=np.uint8)
        frame = cv2.imdecode(arr, cv2.IMREAD_COLOR)
        return frame
    except Exception:
        return None


def preprocess_frame(
    frame: np.ndarray,
    target_size: Tuple[int, int] = (640, 480),
    enhance_quality: bool = True
) -> np.ndarray:
    """
    Preprocess frame video untuk optimasi deteksi.
    
    Args:
        frame       : Frame BGR dari OpenCV
        target_size : (width, height) target untuk resize
        enhance_quality: Terapkan CLAHE untuk perbaikan kontras
        
    Returns:
        Frame BGR yang sudah dipreprocess
    """
    # Resize frame jika terlalu besar (menghemat waktu proses)
    h, w = frame.shape[:2]
    target_w, target_h = target_size

    # Hanya resize jika lebih besar dari target
    if w > target_w or h > target_h:
        frame = cv2.resize(frame, target_size, interpolation=cv2.INTER_LINEAR)

    # CLAHE (Contrast Limited Adaptive Histogram Equalization)
    # Meningkatkan kontras lokal untuk membantu deteksi wajah
    if enhance_quality:
        lab = cv2.cvtColor(frame, cv2.COLOR_BGR2LAB)  # Konversi ke LAB color space
        l_channel, a, b = cv2.split(lab)

        # Terapkan CLAHE hanya pada channel L (luminance/kecerahan)
        clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
        l_enhanced = clahe.apply(l_channel)

        # Gabungkan kembali channel
        enhanced_lab = cv2.merge([l_enhanced, a, b])
        frame = cv2.cvtColor(enhanced_lab, cv2.COLOR_LAB2BGR)

    return frame


def draw_detection_overlay(
    frame: np.ndarray,
    face_boxes: list,
    label: str,
    score: float
) -> np.ndarray:
    """
    Gambar bounding box dan label deteksi di atas frame.
    
    Args:
        frame    : Frame BGR
        face_boxes: List of [x, y, w, h] dalam piksel
        label    : Label deteksi ('REAL', 'FAKE', 'UNCERTAIN')
        score    : Skor keaslian (0.0 - 1.0)
        
    Returns:
        Frame dengan overlay
    """
    # Pilih warna berdasarkan label
    color_map = {
        "REAL"     : (0, 255, 100),    # Hijau neon
        "FAKE"     : (0, 50, 255),      # Merah
        "UNCERTAIN": (0, 165, 255),     # Oranye
        "NO_FACE"  : (128, 128, 128),   # Abu-abu
    }
    color = color_map.get(label, (255, 255, 255))

    # Gambar bounding box untuk setiap wajah
    for (x, y, w, h) in face_boxes:
        # Bounding box utama
        cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)

        # Label teks di atas bounding box
        label_text = f"{label} {score:.0%}"
        cv2.putText(
            frame, label_text,
            (x, max(y - 10, 10)),        # Posisi: di atas bbox, minimal y=10
            cv2.FONT_HERSHEY_SIMPLEX,     # Font
            0.7,                           # Scale
            color,                         # Warna
            2,                             # Tebal
            cv2.LINE_AA                    # Anti-aliasing
        )

    return frame