Spaces:
Sleeping
Sleeping
Aditya-Jadhav150
feat: upgrade to Veritas-AI v3.1 architecture, fast video & image deepfake pipeline, UI enhancements
37b2345 | # -*- coding: utf-8 -*- | |
| """predict_fusion.py | |
| CLI inference script for the Hybrid AI Image Forensics system. | |
| It loads the persisted XGBoost model and StandardScaler, extracts the nine | |
| scalar forensic scores from a single image, and prints a polished report. | |
| """ | |
| import os | |
| import argparse | |
| import joblib | |
| import pandas as pd | |
| import torch | |
| import cv2 | |
| import numpy as np | |
| from sklearn.preprocessing import StandardScaler | |
| # Core components – already in the repo | |
| from core.alignment import GeometricAligner | |
| from core.diffusion_latent import DiffusionErrorLoop | |
| from core.statistical_extraction import StatisticalFeatureExtractor | |
| # -------------------------------------------------------------- | |
| # Helper functions removed: utilizing core.metrics | |
| # -------------------------------------------------------------- | |
| from core.metrics import ForensicMetricExtractor | |
| from core.metadata_forensics import MetadataForensicsEngine | |
| def main(): | |
| parser = argparse.ArgumentParser(description="Run forensic inference on a single image") | |
| parser.add_argument("--image", "-i", required=True, help="Path to image file") | |
| parser.add_argument("--model", default=os.path.join('dataset', 'fusion_engine_best.json'), help="Path to saved XGBoost model JSON") | |
| parser.add_argument("--scaler", default=os.path.join('dataset', 'scaler.json'), help="Path to saved StandardScaler JSON") | |
| parser.add_argument("--device", default="cpu", help="Device to run models on (cpu or cuda)") | |
| args = parser.parse_args() | |
| # Load model & scaler | |
| if not os.path.isfile(args.model): | |
| raise FileNotFoundError(f"Model file not found: {args.model}") | |
| if not os.path.isfile(args.scaler): | |
| raise FileNotFoundError(f"Scaler file not found: {args.scaler}") | |
| from xgboost import XGBClassifier | |
| import json | |
| model = XGBClassifier() | |
| model.load_model(args.model) | |
| scaler = StandardScaler() | |
| with open(args.scaler, 'r') as f: | |
| s_data = json.load(f) | |
| scaler.mean_ = np.array(s_data["mean"]) | |
| scaler.var_ = np.array(s_data["var"]) | |
| scaler.scale_ = np.array(s_data["scale"]) | |
| scaler.n_features_in_ = s_data["n_features_in"] | |
| # -------------------- Load image & align -------------------- | |
| bgr = cv2.imread(args.image) | |
| if bgr is None: | |
| raise ValueError(f"Could not read image: {args.image}") | |
| aligner = GeometricAligner(device=args.device) | |
| aligned = aligner.align_and_crop(bgr, return_tensor=True) | |
| if aligned is None: | |
| raise RuntimeError("Face detection failed – no face found in the image.") | |
| # -------------------- Load Metric Extractor -------------------- | |
| metric_extractor = ForensicMetricExtractor(device=args.device) | |
| metadata_engine = MetadataForensicsEngine() | |
| # -------------------- Extract Metadata Forensics --------------- | |
| metadata_results = metadata_engine.analyze(args.image) | |
| meta_score = metadata_results.get('metadata_forensic_score', 0.5) | |
| # -------------------- Denormalize image -------------------- | |
| mean = np.array([0.485, 0.456, 0.406]).reshape(3, 1, 1) | |
| std = np.array([0.229, 0.224, 0.225]).reshape(3, 1, 1) | |
| aligned_np = aligned.cpu().numpy() | |
| unnorm = (aligned_np * std + mean) * 255.0 | |
| rgb = np.clip(unnorm, 0, 255).transpose(1, 2, 0).astype(np.uint8) | |
| # -------------------- Compute scores -------------------- | |
| feature_dict = metric_extractor.extract_all(aligned, rgb) | |
| # Add metadata forensic score to feature dict | |
| feature_dict['metadata_forensic_score'] = meta_score | |
| df_feat = pd.DataFrame([feature_dict]) | |
| # The scaler expects specific columns in the same order as training. | |
| # The scaler natively expects 10 features now. | |
| df_scaled = scaler.transform(df_feat) | |
| # -------------------- Predict -------------------- | |
| prob_fake = model.predict_proba(df_scaled)[0, 1] | |
| verdict = "AI Generated" if prob_fake >= 0.5 else "Real" | |
| confidence = prob_fake * 100 if prob_fake >= 0.5 else (1 - prob_fake) * 100 | |
| # -------------------- Pretty report -------------------- | |
| print("\n" + "=" * 40) | |
| print(" AI IMAGE FORENSIC REPORT") | |
| print("=" * 40 + "\n") | |
| print(f"Spatial Artifact Score : {feature_dict['spatial_score']:.2f}") | |
| print(f"Frequency Anomaly Score : {feature_dict['freq_score']:.2f}") | |
| print(f"Noise Residual Score : {feature_dict['latent_score']:.2f}") | |
| print(f"Embedding Consistency : {feature_dict['stat_score']:.2f}") | |
| print(f"Entropy Score : {feature_dict['entropy']:.2f}") | |
| print(f"Edge Density Score : {feature_dict['edge_density']:.2f}") | |
| print(f"Laplacian Variance Score : {feature_dict['laplacian_variance']:.2f}") | |
| print(f"Color Kurtosis Score : {feature_dict['color_kurtosis']:.2f}") | |
| print(f"JPEG Consistency Score : {feature_dict['jpeg_consistency']:.2f}") | |
| print("-" * 40) | |
| print("FINAL RESULT:") | |
| print(f"Likely {verdict}") | |
| print(f"Confidence: {confidence:.0f}%") | |
| print("=" * 40 + "\n") | |
| if __name__ == "__main__": | |
| main() | |