mirror of
https://github.com/PR0M3TH3AN/unredact.git
synced 2026-11-09 23:21:02 +00:00
feat: overlay calibration with word-by-word rendering
- Render each word at its OCR'd position instead of whole lines, so word spacing matches the original document exactly - Add y-offset correction using glyph bounding box - Add fine-grained font size search (±3 around coarse best, step 1) - Add alignment quality test (48.9% hit rate, >30% threshold) - Add scipy to dev dependencies Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
1 parent
3da043046c
commit
8d82054b5d
4 files changed
+115
-12
No files matched your search
@@ -0,0 +1,51 @@
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
from scipy.ndimage import binary_dilation
|
||||
|
||||
from unredact.pipeline.rasterize import rasterize_pdf
|
||||
from unredact.pipeline.ocr import ocr_page
|
||||
from unredact.pipeline.font_detect import detect_font
|
||||
from unredact.pipeline.overlay import render_overlay
|
||||
|
||||
|
||||
def test_overlay_alignment_score(sample_pdf: Path):
|
||||
"""Measure how well the overlay aligns with the original text.
|
||||
|
||||
Strategy: compare the overlay-only green pixels against the original
|
||||
dark text pixels. Where they overlap (within a few pixels tolerance),
|
||||
that's a hit. We want a reasonable hit rate.
|
||||
"""
|
||||
pages = rasterize_pdf(sample_pdf, first_page=1, last_page=1)
|
||||
page = pages[0]
|
||||
lines = ocr_page(page)
|
||||
font_match = detect_font(lines, page)
|
||||
overlay = render_overlay(page, lines, font_match)
|
||||
|
||||
orig_arr = np.array(page.convert("L")) # grayscale
|
||||
overlay_arr = np.array(overlay)
|
||||
|
||||
# Original dark text pixels (< 128 on grayscale)
|
||||
text_mask = orig_arr < 128
|
||||
|
||||
# Overlay green pixels (green channel > 100)
|
||||
green_mask = overlay_arr[:, :, 1] > 100
|
||||
|
||||
# How many text pixels have green overlay nearby (within 3px tolerance)?
|
||||
green_dilated = binary_dilation(green_mask, iterations=3)
|
||||
|
||||
overlap = text_mask & green_dilated
|
||||
if text_mask.sum() == 0:
|
||||
return
|
||||
|
||||
hit_rate = overlap.sum() / text_mask.sum()
|
||||
print(f"\nAlignment hit rate: {hit_rate:.1%}")
|
||||
print(f" Text pixels: {text_mask.sum()}")
|
||||
print(f" Green pixels: {green_mask.sum()}")
|
||||
print(f" Overlap pixels: {overlap.sum()}")
|
||||
|
||||
# We want at least 30% of text pixels to have overlay nearby
|
||||
# (not 100% because redaction boxes are dark too, and headers/footers
|
||||
# may use different fonts)
|
||||
assert hit_rate > 0.3, f"Overlay alignment too low: {hit_rate:.1%}"
|
||||
Reference in new issue
Block a user