File size: 2,082 Bytes
a10ba7f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
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