Skip to content

Latest commit

Β 

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ” NHA PS3 - Document Forgery & Deepfake Detection

Nikhileswara Rao Sulake1, Sai Manikanta Eswar Machara1, Sivalal Kethavath1

1 Rajiv Gandhi University of Knowledge Technologies, Nuzvid, Andhra Pradesh


Internal Validation Score: 0.5315 Β Β·Β  Leaderboard Position: Top 3


Image 1 Image 2

This pipeline is a completely classical computer vision–based solution, where no models or other heavy components are required. Just using traditional, pre-defined libraries, our solution is capable enough to detect document forgery across all 9 tampering categories.

Why did we choose this classical CV approach over the big guns, CLIP, ViT, ManTra-Net, MVSS-Net, CAT-Net, or DTD?

Because our main motive is making the solution highly scalable, computationally lightweight, and 100% explainable, aligning perfectly with the core demands of the AB-PMJAY ecosystem. These are government health insurance claim documents. They need to be processed at scale, across thousands of hospitals, on infrastructure that may not have GPUs. And when you flag a document as forged, you need to explain why, not just point to a confidence score from a black-box model.

Deep Learning Approaches Our Classical CV Pipeline
Scalability GPU-bound, memory-heavy βœ… Runs on any CPU, anywhere
Explainability Black-box, "the model says so" βœ… Every flag traces back to a math equation
Deployment Needs ONNX/TensorRT, model hosting βœ… Single notebook, zero model files
Latency Seconds per image even on GPU βœ… ~1–3s per page on plain CPU
AB-PMJAY Fit Over-engineered for document scans βœ… Purpose-built for Indian medical docs

If you can explain why a region is tampered using math, you don't need a neural network to do it for you.


Instructions to try our solution

πŸ“ Project Structure

NHA PS3 Final Updated/
β”œβ”€β”€ nha_ps3_skeletal_notebook_main.ipynb            # ← Main solution notebook (run this)
β”œβ”€β”€ README.md                          # This file
β”œβ”€β”€ output/
β”‚   β”œβ”€β”€ output.json                    # Final JSON submission
β”‚   └── ***.yaml                       # Per-page YAML bounding boxes
└── 1ae9a4db-.../Claim_Documents/      # Input dataset

πŸš€ How to Run the Code

Change the input directory path to pointing towards the folder containing all the health reports in PDFs, JPEGs, JPGs formats. You can change the path using this variable in the second code cell: INPUT_DIR

And just click run all button in the notebook, that's it. The code will take care of it, we also show the results processing using a TQDM bar for better visualization of when will the process will be completed.

🌐 How to Run the Website Locally

We will set the local API URL to 127.0.0.1 on 8000 port, we can do any toggle in the configs in the respective config files in frontend and backend. Now, open the powershell and to first start the backend from the repo root, run the below code:

cd .\backend\
$env:DATA_DIR="$PWD\data"
$env:CORS_ORIGINS="http://127.0.0.1:5500,http://localhost:5500"
$env:AUTH_REQUIRED="false"
$env:CLOUDINARY_ENABLED="false"
uvicorn app.main:app --reload

To start the frontend from the repo root, run the below code in a new powershell:

cd .\frontend\
python -m http.server 5500

Then you can open the http://127.0.0.1:5500/app.html to see the website, and run all the things properly. Mentioning that the code will run purely on your CPU.


πŸ”¬ Per-Class Detection Methodology

C1, Copy-Paste Detection

Signal: Duplicate regions within the same document displaced spatially.

Grayscale Image
  β†’ ORB Keypoints (4000 features)
  β†’ BFMatcher Self-Matching (k=2)
  β†’ Lowe's Ratio Test (m.dist < 0.75Β·n.dist)
  β†’ Spatial Shift Filter (β€–shiftβ€– > min_px)
  β†’ Shift-Vector Clustering (bin_size = 12px)
  β†’ Cluster β‰₯ N pairs β†’ Bounding Boxes

Core Math, Shift-Vector Clustering:

$$\vec{s}_i = \vec{p}_{\text{dst}} - \vec{p}_{\text{src}}, \quad \text{bin}(i) = \left(\left\lfloor \frac{s_x}{b} \right\rceil,; \left\lfloor \frac{s_y}{b} \right\rceil\right)$$

Clusters with $|\text{bin}| \geq N_{\min}$ indicate copy-paste with consistent translation.


C2, Overwrite Detection

Signal: Text components within a line that show anomalous edge density, stroke width, or ink darkness relative to their neighbours.

Per-Line Text Components
  β”œβ”€β”€ Edge Density (Canny)
  β”œβ”€β”€ Stroke Width (Distance Transform)
  └── Ink Darkness (mean intensity)
        ↓
  Robust Z-Score per feature
        ↓
  Z > threshold on β‰₯2 signals? β†’ Yes β†’ Flag as Overwritten

Core Math, MAD-Based Robust Z-Score:

$$Z_{\text{MAD}} = \frac{0.6745 \cdot (x_i - \tilde{x})}{\text{MAD}}, \quad \text{MAD} = \text{median}(|x_j - \tilde{x}|)$$

A component is flagged only when β‰₯ 2 signals exceed their Z-thresholds simultaneously, with a hard per-page cap to prevent mass false positives.


C3, Added Content Detection

Signal: Stamps (red/blue), signatures, and pasted elements that sit outside normal text lines.

Engine 1 (Color):                    Engine 2 (Shape):
  Color Image (BGR)                    Grayscale
  β†’ HSV Conversion                     β†’ Component Stats
  β†’ Red Mask (H∈[0,10]βˆͺ[160,180])      β†’ Circularity > Ο„ ? β†’ Stamp
  β†’ Blue Mask (H∈[100,130])            β†’ Aspect > Ο„ ?      β†’ Signature
  β†’ Morphological Clean-up
  β†’ Contour Extraction
  β†’ Stamp / Seal Bounding Boxes

Two-Engine Approach:

  1. HSV Color Segmentation, isolates red/blue ink artifacts common in Indian medical documents
  2. Shape Geometry, circularity for round stamps, high aspect ratio for signatures

C4, Erasure Detection

Signal: Gaps within text lines that are unnaturally smooth compared to surrounding content.

Text Lines
  β†’ Detect Gaps (token spacing)
  β†’ Gap > median Γ— Ο„ AND Gap > min_abs?
      ↓ Yes
  β†’ Measure Gap Noise & Gradient
  β†’ Compare vs Context Ring
  β†’ noise_gap/noise_ctx < 0.3 AND grad_gap/grad_ctx < 0.4?
      ↓ Yes
  β†’ Flag as Erasure

Core Principle:

$$\text{Score} = \mathbb{1}!\left[\frac{\bar{N}_{\text{gap}}}{\bar{N}_{\text{ctx}}} &lt; \tau_n\right] \cdot 2 + \mathbb{1}!\left[\frac{\bar{G}_{\text{gap}}}{\bar{G}_{\text{ctx}}} &lt; \tau_g\right] \cdot 2 + \mathbb{1}!\left[\sigma^2_{\text{gap}} &lt; 100\right]$$

Digitally erased regions lack the natural noise floor present in scanned paper, this ratio reliably separates real whitespace from artificial erasure.


C5, Document Merge Detection

Signal: Header and body originate from different physical documents with distinct noise fingerprints.

Page Image
  β†’ Segment into Horizontal Bands
  β†’ Per-Band Noise Fingerprint
  β†’ Compare Adjacent Band Profiles
  β†’ Profile Distance > threshold? β†’ Yes β†’ Flag Merge Boundary

Noise Fingerprint Vector:

$$\vec{f}_b = \left[;\bar{N}_b,; \sigma_{N_b},; \bar{G}_b,; \bar{\mu}_b,; \sigma_b;\right]$$

$$d(b_i, b_j) = \frac{1}{K} \sum_{k=1}^{K} \frac{|f_{b_i}^{(k)} - f_{b_j}^{(k)}|}{|f_{b_i}^{(k)}| + |f_{b_j}^{(k)}| + \epsilon}$$

When $d(\text{top}, \text{bottom}) &gt; \tau$, the page is flagged as a merge of two different source documents.


C6, Watermark Removal Detection

Signal: Removed watermarks leave frequency-domain ghosts and unnaturally smooth background.

Grayscale Image
  β”œβ”€β”€ FFT Radial Power Spectrum β†’ Autocorrelation Peak Count
  β”œβ”€β”€ CLAHE Enhancement         β†’ Ghost Region Extraction
  └── Background Variance Map   β†’ Low-Variance Anomaly Ratio
        ↓
  Combined Score β‰₯ Ο„? β†’ Yes β†’ Flag Watermark Removal

Three complementary signals scored additively:

Signal What it catches Points
FFT Periodicity Peaks Residual repeating patterns from watermark grid 0.8–1.5
CLAHE Ghost Detection Faint remnants invisible to naked eye 1.0
Background Smoothness Over-smoothed regions where watermark was painted over 1.0

C7, Irregular Spacing Detection

Signal: Statistically anomalous inter-word or inter-line gaps within OCR-extracted text.

OCR Token Boxes
  β†’ Group by Text Line
  β†’ Compute Inter-Word Gaps
  β†’ Global Median & MAD
  β†’ Per-Gap Z-Score
  β†’ Z > Ο„_large OR Z < Ο„_tight? β†’ Yes β†’ Flag Irregular Spacing

Anomaly Criteria (three checks per gap)

Check Condition Catches
Large Gap $Z &gt; \tau_{large}$ AND $g &gt; \tau_{abs}$ AND $g &gt; \tau_{med} \cdot \tilde{g}_{line}$ Inserted whitespace
Tight Gap $Z &lt; \tau_{tight}$ AND $\tilde{g}_{line} &gt; 3$ Compressed text
Extreme Gap $g &gt; \tau_{singleabs}$ AND $g &gt; \tau_{singlemed} \cdot \tilde{g}_{line}$ Single huge anomaly

C8, Fully AI-Generated Document

Signal: Multi-signal scoring across spectral, noise, texture, and typographic domains.

β”Œβ”€ Spectral Analysis ──────────────────────────┐
β”‚  FFT Radial Spectrum β†’ Spectral Flatness     β”‚
β”‚                      β†’ HF Energy Ratio       β”‚
β”‚                      β†’ GAN Peak Count        β”‚
β”œβ”€ Noise Floor ─────────────────────────────────
β”‚  Background Noise Residual β†’ Variance < Ο„ ?  β”‚
β”‚                            β†’ Kurtosis Check  β”‚
β”œβ”€ Typography ──────────────────────────────────
β”‚  OCR Token Heights β†’ Height CV < Ο„ ?         β”‚
β”‚                    β†’ Stroke Width CV < Ο„ ?   β”‚
β”œβ”€ Texture ─────────────────────────────────────
β”‚  LBP Histogram β†’ Entropy < Ο„ ?               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        ↓ All signals summed
  Total Score β‰₯ Ο„? β†’ Yes β†’ Category: C8

Category-only, no bounding boxes required. Returns C8 if total evidence score crosses threshold.


C9, Partial AI Edits

Signal: Individual text components with anomalous noise, edge, gradient, or ELA profiles relative to their line context.

Per-Line Components
  β”œβ”€β”€ Noise Residual per Component
  β”œβ”€β”€ Edge Density per Component
  β”œβ”€β”€ Gradient Energy per Component
  └── ELA Level per Component
        ↓
  MAD Z-Score vs Line Peers
        ↓
  Score β‰₯ Ο„ on β‰₯2 signals? β†’ Yes β†’ Flag AI-Edited Field

ELA (Error Level Analysis):

$$\text{ELA}(x,y) = |I(x,y) - I_{\text{recomp}}(x,y)|, \quad I_{\text{recomp}} = \text{JPEG}(I, Q{=}90)$$

Regions edited after initial compression show different ELA levels from surrounding authentic content.

Safety Rail: If $&gt;,20%$ of all components on a page are flagged, the entire page result is suppressed (likely systematic noise, not targeted AI edits).


βš™οΈ Tuning System

All thresholds are decoupled from detection logic via a preset system. No code changes needed, just switch presets:

set_preset("normal")       # Precision-first, tight thresholds
set_preset("loose")        # Balanced
set_preset("very_loose")   # Recall-first
set_preset("ultra_loose")  # Aggressive detection
set_preset("super_loose")  # Maximum recall, lower precision

Each preset controls all 9 classes independently, Z-score thresholds, minimum areas, per-page caps, and scoring weights are all parameterized per class.


πŸ›‘οΈ Robustness Design

Feature Implementation
Crash-proof Every detector wrapped in try/except with fallback_ functions
Per-page caps Prevents mass false positives (max N detections per page)
IoU deduplication Removes overlapping boxes within same category (IoU > 0.7)
Quality gating Skips unreadable/blurry pages via Laplacian variance check
Graceful degradation Missing Tesseract β†’ OCR-dependent classes silently skip

Built for NHA Hackathon PS-03 Β Β·Β  Zero Models Β Β·Β  Pure Math Β Β·Β  Full Explainability

About

Forgensic: Forgery meets forensic clarity

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages