Nikhileswara Rao Sulake1, Sai Manikanta Eswar Machara1, Sivalal Kethavath1
1 Rajiv Gandhi University of Knowledge Technologies, Nuzvid, Andhra Pradesh
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.
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
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.
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.
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:
Clusters with
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:
A component is flagged only when β₯ 2 signals exceed their Z-thresholds simultaneously, with a hard per-page cap to prevent mass false positives.
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:
- HSV Color Segmentation, isolates red/blue ink artifacts common in Indian medical documents
- Shape Geometry, circularity for round stamps, high aspect ratio for signatures
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:
Digitally erased regions lack the natural noise floor present in scanned paper, this ratio reliably separates real whitespace from artificial erasure.
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:
When
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 |
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
| Check | Condition | Catches |
|---|---|---|
| Large Gap |
|
Inserted whitespace |
| Tight Gap |
|
Compressed text |
| Extreme Gap |
|
Single huge anomaly |
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
C8if total evidence score crosses threshold.
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):
Regions edited after initial compression show different ELA levels from surrounding authentic content.
Safety Rail: If
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 precisionEach preset controls all 9 classes independently, Z-score thresholds, minimum areas, per-page caps, and scoring weights are all parameterized per class.
| 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

