File size: 3,638 Bytes
52689dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444ca24
 
 
52689dc
444ca24
 
 
 
 
 
1f86d86
9261c8f
e553ad3
9261c8f
e553ad3
9261c8f
e553ad3
 
9261c8f
e553ad3
9261c8f
 
 
1f86d86
9261c8f
 
e553ad3
97ac331
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# ela_hybrid.py
import numpy as np
import cv2 as cv
from PIL import Image
import matplotlib.pyplot as plt


def compress_jpg(image, quality=75):
    """Compress image using JPEG compression (shared from ela.py)."""
    encode_param = [int(cv.IMWRITE_JPEG_QUALITY), quality]
    _, buffer = cv.imencode('.jpg', image, encode_param)
    return cv.imdecode(buffer, cv.IMREAD_COLOR)


def generate_ela_hybrid(image_path: str, quality: int = 95, scale_factor: int = 150):
    """
    Generate a 6-channel hybrid image combining RGB and ELA (3 channels each).
    
    Args:
        image_path (str): Path to the input image.
        quality (int): JPEG compression quality (1-100).
        scale_factor (int): Scale factor for ELA contrast.
        
    Returns:
        np.ndarray: 6-channel (RGB + ELA) image with shape (H, W, 6), dtype float32, normalized [0,1]
    """
    # Load original image
    original = cv.imread(image_path, cv.IMREAD_COLOR)
    original = original.astype(np.float32) / 255  # Normalize to [0, 1]

    # Compress and reload image
    compressed = compress_jpg(original, quality)
    compressed = compressed.astype(np.float32) / 255  # Normalize to [0, 1]

    # Generate ELA as absolute difference between original and compressed
    ela = cv.absdiff(original, compressed)

    # Apply scale factor to enhance ELA differences
    ela = cv.convertScaleAbs(ela, alpha=scale_factor / 100, beta=0)
    ela = ela.astype(np.float32) / 255  # Normalize back to [0, 1]

    # Stack RGB and ELA (3 channels each) into 6-channel input
    hybrid_image = np.concatenate([original, ela], axis=-1)  # Shape: H×W×6

    return hybrid_image


def save_hybrid_image(hybrid_array, save_path: str):
    """Save the 6-channel hybrid image as a .npy file for model input."""
    np.save(save_path, hybrid_array)
    print(f"Saved hybrid ELA image to {save_path}")

def visualize_hybrid(hybrid_array: np.ndarray):
    """Return a list of 2 images: [RGB Image, ELA Map (grayscale)], as PIL Images."""
    from PIL import Image

    # Extract RGB (3 channels at front)
    rgb_image = Image.fromarray((hybrid_array[:, :, :3] * 255).astype(np.uint8))
    
    # Extract ELA channels (last 3)
    ela_image = Image.fromarray((hybrid_array[:, :, 3:] * 255).astype(np.uint8))

    return [rgb_image, ela_image]
    # ela_hybrid.py
    
def generate_hybrid_ela_func(img_input):
    """
    Returns a list of 2 PIL Images: [Original RGB Image, Hybrid ELA Output].
    """
    from PIL import Image
    import numpy as np

    # Convert input to numpy array if needed
    if not isinstance(img_input, np.ndarray):
        img_input = np.array(img_input)  # Ensure numpy format

    # Generate ELA
    hybrid_array = generate_ela_hybrid(img_input, quality=75, scale_factor=100)
    visualizations = visualize_hybrid(hybrid_array)
    return list(visualizations)  # Returns [RGB PIL Image, ELA PIL Image]


def generate_concatenated_hybrid(img_array):
    """
    Concatenate original RGB and ELA map into a single image.
    Returns a single PIL Image (side-by-side).
    """
    # Extract RGB and ELA channels
    original_rgb = Image.fromarray((img_array[:, :, :3] * 255).astype(np.uint8))  # 3 channels
    ela_map = Image.fromarray((img_array[:, :, 3:] * 255).astype(np.uint8))  # 3 channels

    # Resize to match height
    ela_map = ela_map.resize(original_rgb.size)

    # Concatenate and return as a single PIL Image
    combined = Image.new("RGB", (ela_map.width + original_rgb.width, original_rgb.height))  # Single row
    combined.paste(original_rgb, (0, 0))
    combined.paste(ela_map, (original_rgb.width, 0))
    return combined