Spaces:
Running on Zero
Running on Zero
Download scripts/benchmark_easyocr.py from Zeyadmohamed21/OCR: direct link, hf CLI and curl.
- Browser
- Download file 3.53 kB
-
https://huggingface.co/spaces/Zeyadmohamed21/OCR/resolve/main/scripts/benchmark_easyocr.py
- Command line
-
hf download hf://spaces/Zeyadmohamed21/OCR/scripts/benchmark_easyocr.py
-
curl -L -o benchmark_easyocr.py https://huggingface.co/spaces/Zeyadmohamed21/OCR/resolve/main/scripts/benchmark_easyocr.py
3.53 kB
| """Reproducible local OCR benchmark; synthetic degradations are not independent documents. | |
| Run from repository root: python -m scripts.benchmark_easyocr --output path.json | |
| """ | |
| import argparse | |
| import json | |
| import time | |
| from pathlib import Path | |
| import cv2 | |
| import numpy as np | |
| from app.infrastructure.ocr.easyocr_engine import EasyOCREngine | |
| from app.services.image_processing.quality import analyze_image_quality | |
| from app.services.image_processing.preprocessor import AdaptivePreprocessor | |
| from app.services.layout.reading_order import organize_reading_order | |
| from app.services.layout.layout_analyzer import LayoutAnalyzer | |
| from app.services.ocr.evaluator import evaluate_detection_quality | |
| from app.services.ocr.passes import run_ocr_passes | |
| from app.services.ocr.metrics import text_metrics | |
| def main(): | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument('--image', type=Path, default=Path('artifacts/easyocr_validation/source.jpg')) | |
| parser.add_argument('--expected', type=Path, default=Path('artifacts/easyocr_validation/expected.txt')) | |
| parser.add_argument('--output', type=Path, required=True) | |
| args = parser.parse_args() | |
| image = cv2.imread(str(args.image)) | |
| if image is None: | |
| raise ValueError('Cannot decode benchmark image') | |
| expected = args.expected.read_text(encoding='utf-8').strip() | |
| h, w = image.shape[:2] | |
| matrix = cv2.getRotationMatrix2D((w / 2, h / 2), 5, 1) | |
| # Expanded canvas preserves all text in the skewed sample. | |
| nw, nh = int(w * abs(matrix[0, 0]) + h * abs(matrix[0, 1])) + 2, int(h * abs(matrix[0, 0]) + w * abs(matrix[0, 1])) + 2 | |
| matrix[0, 2] += nw / 2 - w / 2 | |
| matrix[1, 2] += nh / 2 - h / 2 | |
| rng = np.random.default_rng(42) | |
| samples = { | |
| 'original': image, | |
| 'blur': cv2.GaussianBlur(image, (3, 3), 0.7), | |
| 'low_contrast': np.clip(image.astype(float) * .30 + 145, 0, 255).astype(np.uint8), | |
| 'noise': np.clip(image.astype(float) + rng.normal(0, 7, image.shape), 0, 255).astype(np.uint8), | |
| 'skew_5': cv2.warpAffine(image, matrix, (nw, nh), borderValue=(255, 255, 255)), | |
| 'rotation_90': cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE), | |
| 'small': cv2.resize(image, None, fx=.65, fy=.65, interpolation=cv2.INTER_AREA), | |
| } | |
| engine = EasyOCREngine() # Model load excluded from timings. | |
| rows = [] | |
| for name, sample in samples.items(): | |
| start = time.perf_counter() | |
| quality = analyze_image_quality(sample) | |
| primary, variants = AdaptivePreprocessor.preprocess_adaptive(sample, quality) | |
| result, _, attempts = run_ocr_passes(engine, primary, variants, quality) | |
| calls = len(attempts) | |
| ordered = organize_reading_order(result.blocks, result.image_width) | |
| layout, _, _ = LayoutAnalyzer.analyze(ordered, result.image_width, result.image_height) | |
| actual = '\n'.join(line.text for line in layout.lines) | |
| rows.append(dict(id=name, expected_text=expected, actual_text=actual, | |
| metrics=text_metrics(expected, actual), calls=calls, | |
| latency_ms=round((time.perf_counter()-start)*1000, 2), | |
| confidence=result.average_confidence, | |
| raw_blocks=[dict(text=b.raw_text, confidence=b.confidence, box=b.box.points) for b in ordered])) | |
| args.output.write_text(json.dumps(rows, ensure_ascii=False, indent=2), encoding='utf-8') | |
| print(name, rows[-1]['metrics'], 'calls', calls, flush=True) | |
| if __name__ == '__main__': | |
| main() | |