Skip to content

Commit a2ae55a

Browse files
committed
Initial commit: Veritas Forensic Image Analysis Toolkit with 11 analysis techniques
0 parents  commit a2ae55a

20 files changed

Lines changed: 2533 additions & 0 deletions

.gitignore

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Python
2+
__pycache__/
3+
*.py[cod]
4+
*.pyo
5+
*.pyd
6+
.Python
7+
*.so
8+
*.egg
9+
*.egg-info/
10+
dist/
11+
build/
12+
13+
# Virtual Environment
14+
venv/
15+
env/
16+
ENV/
17+
18+
# IDE
19+
.vscode/
20+
.idea/
21+
*.swp
22+
*.swo
23+
*~
24+
25+
# OS
26+
.DS_Store
27+
Thumbs.db
28+
29+
# Streamlit
30+
.streamlit/secrets.toml
31+
32+
# Temporary files
33+
temp/
34+
*.tmp
35+
36+
# Logs
37+
*.log

.streamlit/config.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[theme]
2+
base="dark"
3+
primaryColor="#00ff41"
4+
backgroundColor="#0e1117"
5+
secondaryBackgroundColor="#262730"
6+
textColor="#fafafa"
7+
font="sans serif"
8+
9+
[server]
10+
headless = true
11+
port = 8501
12+
13+
[client]
14+
showErrorDetails = true
15+
16+
[logger]
17+
level = "info"

analysis/__init__.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from . import (
2+
ela,
3+
metadata_analysis,
4+
histogram_analysis,
5+
noise_map,
6+
jpeg_ghost,
7+
quant_table,
8+
cmfd,
9+
prnu,
10+
frequency_analysis,
11+
deepfake_detector,
12+
resampling_detector,
13+
util
14+
)
15+
16+
__all__ = [
17+
"ela",
18+
"metadata_analysis",
19+
"histogram_analysis",
20+
"noise_map",
21+
"jpeg_ghost",
22+
"quant_table",
23+
"cmfd",
24+
"prnu",
25+
"frequency_analysis",
26+
"deepfake_detector",
27+
"resampling_detector",
28+
"util",
29+
]

analysis/cmfd.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import cv2
2+
import numpy as np
3+
from pathlib import Path
4+
5+
6+
def detect_copy_move(image_path, block_size=32, threshold=100):
7+
"""
8+
Detects copy-move forgery using block matching.
9+
10+
Args:
11+
image_path (str): Path to the image file
12+
block_size (int): Size of blocks for matching (default 32)
13+
threshold (int): Similarity threshold (default 100)
14+
15+
Returns:
16+
dict: Results dictionary or None on error
17+
"""
18+
try:
19+
# Read image
20+
img = cv2.imread(image_path)
21+
if img is None:
22+
return {"error": "Could not read image", "result": "Failed to load image"}
23+
24+
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
25+
26+
# For now, return a placeholder indicating the analysis would happen here
27+
# Full CMFD implementation is complex and requires sophisticated block matching
28+
result = {
29+
"status": "analysis_pending",
30+
"method": "Block Matching (SIFT)",
31+
"block_size": block_size,
32+
"image_shape": gray.shape,
33+
"result": "CMFD analysis is computationally intensive. Implementation pending."
34+
}
35+
36+
return result
37+
38+
except Exception as e:
39+
print(f"Error in CMFD detection: {e}")
40+
return {"error": str(e), "result": f"CMFD error: {str(e)}"}

analysis/deepfake_detector.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import numpy as np
2+
from PIL import Image
3+
4+
5+
def detect_deepfake_artifacts(image_path):
6+
"""
7+
Detects common deepfake/GAN artifacts:
8+
- Blurry boundaries between face and background
9+
- Unnatural skin texture
10+
- Inconsistent lighting
11+
- Face warping artifacts
12+
13+
Args:
14+
image_path (str): Path to image file
15+
16+
Returns:
17+
dict: Deepfake artifact detection results
18+
"""
19+
try:
20+
img = Image.open(image_path).convert('RGB')
21+
img_array = np.array(img, dtype=np.float32)
22+
23+
# Check for common GAN artifacts
24+
# 1. Frequency anomalies (GANs produce artifacts in specific frequency bands)
25+
from scipy.fft import fft2, fftshift
26+
27+
gray = np.mean(img_array, axis=2)
28+
fft_result = fft2(gray)
29+
magnitude = np.abs(fftshift(fft_result))
30+
31+
# Analyze specific frequency bands used by GANs
32+
h, w = magnitude.shape
33+
center_h, center_w = h // 2, w // 2
34+
35+
# High frequency analysis (often shows GAN artifacts)
36+
high_freq_ring = magnitude[center_h -
37+
20:center_h+20, center_w-20:center_w+20]
38+
high_freq_variance = np.var(high_freq_ring)
39+
40+
# 2. Texture consistency check
41+
# GANs often produce subtle texture inconsistencies
42+
r, g, b = img_array[:, :, 0], img_array[:, :, 1], img_array[:, :, 2]
43+
44+
# Channel correlation
45+
rg_correlation = np.corrcoef(r.flatten(), g.flatten())[0, 1]
46+
rb_correlation = np.corrcoef(r.flatten(), b.flatten())[0, 1]
47+
gb_correlation = np.corrcoef(g.flatten(), b.flatten())[0, 1]
48+
49+
avg_channel_correlation = np.mean(
50+
[rg_correlation, rb_correlation, gb_correlation])
51+
52+
# 3. Boundary blur detection
53+
# Calculate gradient magnitude
54+
from scipy.ndimage import sobel
55+
gradient_x = sobel(gray, axis=1)
56+
gradient_y = sobel(gray, axis=0)
57+
gradient_magnitude = np.sqrt(gradient_x**2 + gradient_y**2)
58+
59+
# High gradient at edges is natural; too uniform suggests blurring
60+
edge_sharpness = np.std(gradient_magnitude)
61+
62+
result = {
63+
"status": "analysis_complete",
64+
"method": "GAN/Deepfake Artifact Detection",
65+
"image_size": img_array.shape,
66+
"artifacts": {
67+
"frequency_anomaly_score": float(high_freq_variance),
68+
"channel_correlation_score": float(avg_channel_correlation),
69+
"edge_sharpness_score": float(edge_sharpness)
70+
},
71+
"interpretation": "Scores help identify GAN-generated or deepfake artifacts",
72+
"note": "This is a simplified heuristic detector; professional deepfake detection requires deep learning models"
73+
}
74+
75+
return result
76+
77+
except Exception as e:
78+
return {"error": str(e), "status": "analysis_failed"}
79+
80+
81+
def detect_gan_fingerprint(image_path):
82+
"""
83+
Detects specific fingerprints left by popular GAN architectures (StyleGAN, ProGAN, etc).
84+
85+
Args:
86+
image_path (str): Path to image file
87+
88+
Returns:
89+
dict: GAN fingerprint detection results
90+
"""
91+
try:
92+
img = Image.open(image_path).convert('RGB')
93+
img_array = np.array(img, dtype=np.float32)
94+
95+
# Analyze spectral properties unique to GANs
96+
from scipy.fft import fft2, fftshift
97+
98+
gray = np.mean(img_array, axis=2)
99+
fft_result = fft2(gray)
100+
magnitude = np.abs(fftshift(fft_result))
101+
102+
# Look for characteristic "blob" patterns in frequency domain
103+
h, w = magnitude.shape
104+
center_h, center_w = h // 2, w // 2
105+
106+
# Radial frequency analysis
107+
y, x = np.ogrid[:h, :w]
108+
distance = np.sqrt((y - center_h)**2 + (x - center_w)**2)
109+
110+
radial_profile = []
111+
for r in range(1, min(center_h, center_w), 10):
112+
mask = (distance >= r) & (distance < r + 10)
113+
radial_profile.append(np.mean(magnitude[mask]))
114+
115+
# GANs produce characteristic radial patterns
116+
radial_variance = np.var(radial_profile)
117+
118+
result = {
119+
"status": "analysis_complete",
120+
"method": "GAN Fingerprint Detection (Spectral Analysis)",
121+
"radial_frequency_variance": float(radial_variance),
122+
"potential_gan_likelihood": "Medium" if radial_variance > 1000 else "Low",
123+
"note": "Requires deep learning model for accurate detection; this is pattern-based heuristic"
124+
}
125+
126+
return result
127+
128+
except Exception as e:
129+
return {"error": str(e), "status": "analysis_failed"}

0 commit comments

Comments
 (0)