This repository was archived by the owner on Feb 18, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathELA Mate_v1.py
More file actions
172 lines (143 loc) · 7.59 KB
/
Copy pathELA Mate_v1.py
File metadata and controls
172 lines (143 loc) · 7.59 KB
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/usr/bin/env python3
"""
ELA2.py
A tool for Error Level Analysis (ELA) on images to help visualize digital compression artifacts,
which can hint at image manipulation. This script generates multiple ELA images at varying JPEG quality
levels, creates an animated GIF of the ELA progression, and produces an "inverted hotspot" image that
highlights areas of compression discrepancy.
The inverted hotspot image is generated by thresholding the ELA output from the most degraded quality,
inverting the mask, and then compositing it over a black background so that only areas that did NOT
exhibit strong artifacts appear from the original image.
Usage:
Run the script and follow the interactive prompts to provide the image path, output directory, and
processing parameters.
Requirements:
Pillow (Python Imaging Library)
"""
import os
import io
from datetime import datetime
from PIL import Image, ImageChops, ImageEnhance
def generate_ela(original, compressed, enhancement_factor):
"""
Generate an Error Level Analysis (ELA) image from the original and its compressed version.
Args:
original (PIL.Image.Image): The original image.
compressed (PIL.Image.Image): The compressed version of the original image.
enhancement_factor (float): Brightness multiplier to amplify differences.
Returns:
PIL.Image.Image: The enhanced ELA image.
"""
ela = ImageChops.difference(original, compressed)
extrema = ela.getextrema()
max_diff = max(val[1] for val in extrema)
if max_diff == 0:
max_diff = 1
scale_factor = (255 / max_diff) * enhancement_factor
return ImageEnhance.Brightness(ela).enhance(scale_factor)
def blend_images(original, ela, overlay_strength):
"""
Blend the original image with its ELA version.
Args:
original (PIL.Image.Image): The original image.
ela (PIL.Image.Image): The ELA image.
overlay_strength (float): A value between 0.0 (only the original) and 1.0 (only the ELA image).
Returns:
PIL.Image.Image: The blended image.
"""
return Image.blend(original.convert('RGBA'), ela.convert('RGBA'), overlay_strength)
def create_animated_gif(original, ela_images, output_path, overlay_strength, frame_duration):
"""
Create an animated GIF by blending the original image with each ELA image.
Args:
original (PIL.Image.Image): The original image.
ela_images (list): A list of ELA images.
output_path (str): The file path to save the animated GIF.
overlay_strength (float): The blend strength for each frame.
frame_duration (int): Duration (in milliseconds) for each frame.
"""
frames = [blend_images(original, ela, overlay_strength) for ela in ela_images]
frames[0].save(output_path, save_all=True, append_images=frames[1:], duration=frame_duration, loop=0)
def generate_inverted_hotspot_image(original, ela, threshold=30):
"""
Generate an inverted hotspot image.
The process involves converting the most degraded ELA image to grayscale, generating a binary mask
where pixels above a certain threshold are set to 255, inverting that mask, and then compositing the
original image over a black background using the inverted mask.
Args:
original (PIL.Image.Image): The original image.
ela (PIL.Image.Image): The ELA image from the most degraded quality.
threshold (int): The threshold value to create the binary mask.
Returns:
PIL.Image.Image: The resulting inverted hotspot image.
"""
# Convert the ELA image to grayscale.
gray = ela.convert("L")
# Create a binary mask: pixels > threshold become 255, else 0.
mask = gray.point(lambda p: 255 if p > threshold else 0)
# Invert the mask.
inverted_mask = Image.eval(mask, lambda p: 255 - p)
# Composite: where inverted_mask is 255, show original; where 0, show black.
result = Image.composite(original, Image.new("RGB", original.size, (0, 0, 0)), inverted_mask)
return result
def process_image(original_path, output_base, enhancement_factor, overlay_strength, frame_duration, start_quality=99, end_quality=1):
"""
Process an image by generating multiple ELA images, creating an animated GIF, and producing
an inverted hotspot image.
Args:
original_path (str): File path to the original image.
output_base (str): Directory where outputs will be saved.
enhancement_factor (float): Factor to enhance ELA differences.
overlay_strength (float): Blend strength for images.
frame_duration (int): Frame duration for the animated GIF (milliseconds).
start_quality (int): Starting JPEG quality level for processing.
end_quality (int): Ending JPEG quality level for processing.
"""
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
output_dir = os.path.join(output_base, f"ELA_{timestamp}_enhance{enhancement_factor}_overlay{overlay_strength}_duration{frame_duration}")
os.makedirs(output_dir, exist_ok=True)
ela_images = []
with Image.open(original_path) as img:
original = img.convert('RGB')
for quality in range(start_quality, end_quality - 1, -1):
# Compress the image in-memory at the specified JPEG quality.
buffer = io.BytesIO()
original.save(buffer, format='JPEG', quality=quality)
buffer.seek(0)
with Image.open(buffer) as compressed:
compressed = compressed.convert('RGB')
ela = generate_ela(original, compressed, enhancement_factor)
ela_images.append(ela)
ela.save(os.path.join(output_dir, f"ela_{quality}.jpg"), 'JPEG', quality=95)
# Create animated GIF from ELA images.
gif_path = os.path.join(output_dir, "ELA_Animation.gif")
create_animated_gif(original, ela_images, gif_path, overlay_strength, frame_duration)
print(f"Animated GIF created at {gif_path}")
# Generate inverted hotspot image using the most degraded ELA image.
if ela_images:
inverted_hotspot = generate_inverted_hotspot_image(original, ela_images[-1])
hotspot_path = os.path.join(output_dir, "ELA_Hotspots.jpg")
inverted_hotspot.save(hotspot_path, 'JPEG', quality=95)
print(f"Inverted hotspots image created at {hotspot_path}")
def main():
"""
Main interactive loop for processing an image.
"""
original_path = input("Enter the full path to your image file: ").strip().strip('"')
output_base = input("Enter the folder where you want to save the results: ").strip().strip('"')
while True:
print("\nEnter new settings for ELA processing:")
try:
enhancement_factor = float(input("Enter the brightness enhancement factor (e.g. 10): "))
overlay_strength = float(input("Enter the overlay strength (0.0 for original only, 1.0 for full ELA overlay): "))
frame_duration = int(input("Enter frame duration (in milliseconds) for the animated GIF: "))
except ValueError:
print("Invalid input. Please enter numerical values for the settings.")
continue
process_image(original_path, output_base, enhancement_factor, overlay_strength, frame_duration)
again = input("Would you like to process the same image with different settings? (y/n): ").strip().lower()
if again not in ('y', 'yes'):
break
input("Processing complete. Press Enter to exit.")
if __name__ == "__main__":
main()