Gaze-LIPE / src /utils /hardening.py
thanhhuyvan's picture
Initial release of LIPE V2 GOLD
a10ba7f
Raw
History Blame Contribute Delete
2.08 kB
import cv2
import numpy as np
import torch
def apply_phase1_hardening(patch, landmarks, apply_dropout=True, apply_denoise=True, apply_clahe=True, apply_noise=True, apply_jitter=True):
"""
Applies Domain Adaptation Phase 1 (Data Hardening) to a single sample.
patch: (4, H, W) numpy array, uint8
landmarks: (N, 2) or (956,) numpy array
"""
processed_patch = patch.copy()
processed_landmarks = landmarks.copy()
# 1. Resolution Dropout (16x16 -> 8x8)
if apply_dropout and np.random.rand() > 0.5:
h, w = processed_patch.shape[1], processed_patch.shape[2]
for i in range(4):
# Simulated distance: downsample and upsample
small = cv2.resize(processed_patch[i], (8, 8), interpolation=cv2.INTER_CUBIC)
processed_patch[i] = cv2.resize(small, (w, h), interpolation=cv2.INTER_CUBIC)
# 2. Edge-Preserving Denoising (Bilateral Filter)
if apply_denoise:
for i in range(4):
processed_patch[i] = cv2.bilateralFilter(processed_patch[i], 5, 20, 20)
# 3. Tuned CLAHE
if apply_clahe:
clahe = cv2.createCLAHE(clipLimit=1.1, tileGridSize=(4, 4))
for i in range(4):
processed_patch[i] = clahe.apply(processed_patch[i])
# 4. Random Gaussian Noise
if apply_noise and np.random.rand() > 0.5:
noise = np.random.normal(0, 3, processed_patch.shape).astype(np.float32)
processed_patch = np.clip(processed_patch.astype(np.float32) + noise, 0, 255).astype(np.uint8)
# 5. Landmark Jitter
if apply_jitter and np.random.rand() > 0.5:
noise_lm = np.random.normal(0, 0.003, processed_landmarks.shape).astype(np.float32)
processed_landmarks = processed_landmarks + noise_lm
return processed_patch, processed_landmarks
def preprocess_for_model(patch, landmarks):
"""
Final conversion to torch tensors and normalization.
"""
patch_tensor = torch.from_numpy(patch).float() / 255.0
landmarks_tensor = torch.from_numpy(landmarks).float().view(-1)
return patch_tensor, landmarks_tensor