| import os |
| import sys |
| import cv2 |
| import pandas as pd |
| import numpy as np |
| import json |
|
|
| sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) |
| from features import extract_features |
|
|
| def main(): |
| reports_dir = os.path.join(os.path.dirname(__file__), '..', 'reports') |
| csv_path = os.path.join(reports_dir, 'phone_test_results.csv') |
| |
| if not os.path.exists(csv_path): |
| print("Test results CSV not found.") |
| sys.exit(1) |
| |
| df = pd.read_csv(csv_path) |
| failures = df[df['correct'] == False].copy() |
| |
| if failures.empty: |
| print("No failures found! Perfect score.") |
| sys.exit(0) |
| |
| print(f"Analyzing {len(failures)} failures...") |
| |
| analysis_results = [] |
| |
| for _, row in failures.iterrows(): |
| filepath = row['filepath'] |
| true_label = row['true_label'] |
| predicted_score = row['predicted_score'] |
| |
| |
| subfolder = 'real' if true_label == 0 else 'screen' |
| full_path = os.path.join(os.path.dirname(__file__), '..', 'dataset', 'my_photos', subfolder, filepath) |
| |
| if not os.path.exists(full_path): |
| print(f"File not found: {full_path}") |
| continue |
| |
| img = cv2.imread(full_path) |
| if img is None: |
| continue |
| |
| h, w = img.shape[:2] |
| is_whatsapp = "WhatsApp" in filepath or "WA" in filepath |
| |
| _, group_dict = extract_features(img) |
| |
| |
| flat_feats = {} |
| for feat_name, feat_val in group_dict.items(): |
| flat_feats[feat_name] = feat_val |
| |
| analysis_results.append({ |
| "filepath": filepath, |
| "true_label": true_label, |
| "predicted_score": predicted_score, |
| "failure_type": "False Positive" if true_label == 0 else "False Negative", |
| "is_whatsapp": is_whatsapp, |
| "resolution": f"{w}x{h}", |
| **flat_feats |
| }) |
| |
| analysis_df = pd.DataFrame(analysis_results) |
| |
| out_csv = os.path.join(reports_dir, 'phone_failure_analysis.csv') |
| analysis_df.to_csv(out_csv, index=False) |
| |
| |
| out_md = os.path.join(reports_dir, 'phone_failure_summary.md') |
| with open(out_md, 'w') as f: |
| f.write("# Phone Failure Analysis\n\n") |
| f.write(f"**Total Failures:** {len(failures)}\n") |
| f.write(f"- False Positives (Real flagged as Screen): {len(failures[failures['true_label'] == 0])}\n") |
| f.write(f"- False Negatives (Screen flagged as Real): {len(failures[failures['true_label'] == 1])}\n\n") |
| |
| f.write("## Insights\n") |
| wa_count = analysis_df['is_whatsapp'].sum() |
| f.write(f"- **WhatsApp Compression:** {wa_count} out of {len(failures)} failed images were heavily compressed via WhatsApp.\n") |
| |
| avg_res = analysis_df['resolution'].value_counts().idxmax() |
| f.write(f"- **Most Common Resolution of failures:** {avg_res}\n\n") |
| |
| f.write("### Average Feature Values for False Positives\n") |
| fp_df = analysis_df[analysis_df['true_label'] == 0] |
| if not fp_df.empty: |
| f.write("False positives (real images) are likely triggering on these features (high values typically indicate a screen):\n") |
| f.write(f"- `fft_hf_ratio`: {fp_df['fft_hf_ratio'].mean():.4f}\n") |
| f.write(f"- `laplacian_var`: {fp_df['laplacian_var'].mean():.4f}\n") |
| f.write(f"- `edge_density`: {fp_df['edge_density'].mean():.4f}\n") |
| f.write(f"- `banding_score`: {fp_df['banding_score'].mean():.4f}\n") |
| |
| f.write("\n### Conclusion\n") |
| f.write("The current features are heavily sensitive to high-frequency noise introduced by lossy JPEG compression. Before feature extraction, images must be resized/normalized and optionally smoothed to strip out compression blockiness while retaining true physical screen Moiré.\n") |
| |
| print(f"Saved analysis to {out_csv} and {out_md}") |
|
|
| if __name__ == "__main__": |
| main() |
|
|