| import os |
| import sys |
| import glob |
| import subprocess |
| import numpy as np |
| from PIL import Image |
|
|
|
|
| class SplicingDetector: |
| def __init__(self, trufor_dir, python_executable="python"): |
| """ |
| Initialize the detector by pointing it to your TruFor installation. |
| |
| :param trufor_dir: The absolute or relative path to the 'TruFor_train_test' folder. |
| :param python_executable: The python executable to run test.py with. |
| """ |
| self.trufor_dir = os.path.abspath(trufor_dir) |
| self.python_exec = python_executable |
| self.test_script = os.path.join(self.trufor_dir, "test.py") |
| self.weights_path = "pretrained_models/trufor.pth.tar" |
|
|
| def analyze_image(self, image_path, output_dir="./temp_results"): |
| """ |
| Runs the TruFor model on an image and returns the raw forensic data. |
| |
| Returns: |
| dict with keys: anomaly_map, confidence_map, global_score |
| or None if inference fails. |
| """ |
| |
| if not os.path.isdir(self.trufor_dir): |
| raise NotADirectoryError( |
| f"TruFor directory not found or invalid: {self.trufor_dir}\n" |
| f"Tip: TRUFOR_FOLDER must point to the folder that contains test.py." |
| ) |
|
|
| if not os.path.isfile(self.test_script): |
| raise FileNotFoundError( |
| f"Could not find test.py at: {self.test_script}\n" |
| f"Tip: TRUFOR_FOLDER must be the 'TruFor_train_test' folder (the one that contains test.py)." |
| ) |
|
|
| abs_image_path = os.path.abspath(image_path) |
| abs_output_dir = os.path.abspath(output_dir) |
|
|
| os.makedirs(abs_output_dir, exist_ok=True) |
|
|
| print(f"π Analyzing {os.path.basename(abs_image_path)} for splicing...") |
|
|
| command = [ |
| self.python_exec, |
| self.test_script, |
| "-g", |
| "-1", |
| "-in", |
| abs_image_path, |
| "-out", |
| abs_output_dir, |
| "-exp", |
| "trufor_ph3", |
| "TEST.MODEL_FILE", |
| self.weights_path, |
| ] |
|
|
| |
| env = os.environ.copy() |
| env["PYTHONPATH"] = self.trufor_dir + os.pathsep + env.get("PYTHONPATH", "") |
|
|
| try: |
| subprocess.run( |
| command, |
| cwd=self.trufor_dir, |
| env=env, |
| check=True, |
| capture_output=True, |
| text=True, |
| ) |
| except subprocess.CalledProcessError as e: |
| print("π¨ TruFor Execution Failed!") |
| |
| print("STDERR:\n", e.stderr) |
| print("STDOUT:\n", e.stdout) |
| return None |
|
|
| |
| npz_candidates = glob.glob(os.path.join(abs_output_dir, "*.npz")) |
| if not npz_candidates: |
| print(f"Error: No .npz output found in {abs_output_dir}") |
| return None |
|
|
| |
| npz_path = max(npz_candidates, key=os.path.getmtime) |
|
|
| print(f"β
Analysis complete. Extracting forensic data from: {os.path.basename(npz_path)}") |
| data = np.load(npz_path) |
|
|
| results = { |
| "anomaly_map": data["map"], |
| "confidence_map": data["conf"], |
| "global_score": float(data["score"]) if "score" in data else None, |
| } |
| return results |
|
|
| def visualize_results(self, image_path, results): |
| """ |
| Local-only visualization (not needed for Hugging Face Spaces). |
| Kept for convenience when running on your machine. |
| """ |
| import matplotlib.pyplot as plt |
|
|
| original_img = Image.open(image_path).convert("RGB") |
|
|
| plt.figure(figsize=(15, 5)) |
|
|
| plt.subplot(1, 3, 1) |
| plt.imshow(original_img) |
| plt.title("Original Image") |
| plt.axis("off") |
|
|
| plt.subplot(1, 3, 2) |
| plt.imshow(results["anomaly_map"], cmap="jet", vmin=0, vmax=1) |
| score = results.get("global_score") |
| plt.title(f"Anomaly Map\nGlobal Score: {score:.4f}" if score is not None else "Anomaly Map") |
| plt.colorbar(fraction=0.046, pad=0.04) |
| plt.axis("off") |
|
|
| plt.subplot(1, 3, 3) |
| plt.imshow(results["confidence_map"], cmap="magma", vmin=0, vmax=1) |
| plt.title("Confidence Map") |
| plt.colorbar(fraction=0.046, pad=0.04) |
| plt.axis("off") |
|
|
| plt.tight_layout() |
| plt.show() |
|
|
|
|
| if __name__ == "__main__": |
| |
| SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
| TRUFOR_FOLDER = os.path.join(SCRIPT_DIR, "TruFor_train_test") |
|
|
| detector = SplicingDetector(trufor_dir=TRUFOR_FOLDER, python_executable=sys.executable) |
|
|
| test_image = os.path.join(SCRIPT_DIR, "sample.jpg") |
| forensic_data = detector.analyze_image(test_image, output_dir=os.path.join(SCRIPT_DIR, "temp_results_local")) |
|
|
| if forensic_data: |
| print(f"β
Global AI Score: {forensic_data['global_score']:.4f}") |
| detector.visualize_results(test_image, forensic_data) |