"""OCR helpers for lab report images (EasyOCR + OpenCV + regex). 13 extracted fields: Gender, Age, Hemoglobin, RBC, WBC, AST, ALT, Cholesterol, Spirometry, Creatinine, Glucose, Lipase, Troponin. Missing values are returned as None. """ import re _reader = None def get_reader(): """Lazy singleton EasyOCR reader (downloads ~100MB weights on first call).""" global _reader if _reader is None: import easyocr _reader = easyocr.Reader(['en'], gpu=False) return _reader def ocr_image(image_path: str) -> str: """Run OCR on an image file and return raw text.""" import cv2 reader = get_reader() img = cv2.imread(image_path) if img is None: raise ValueError("Could not read image. Use JPG/PNG.") # EasyOCR handles numpy arrays (BGR) directly. results = reader.readtext(img) return " ".join([t[1] for t in results]) def _num(patterns, text, cast=float): for pat in patterns: m = re.search(pat, text, re.IGNORECASE) if m: try: return cast(m.group(1).replace(',', '')) except (ValueError, IndexError): continue return None def extract_lab_values(text: str) -> dict: """Regex-extract the 13 lab fields from OCR text (None if not found).""" t = text or "" gender = None if re.search(r'\bfemale\b', t, re.IGNORECASE): gender = "Female" elif re.search(r'\bmale\b', t, re.IGNORECASE): gender = "Male" return { "Gender": gender, "Age": _num([r'age\D{0,10}(\d{1,3})'], t, int), "Hemoglobin": _num([r'h(?:ae)?moglobin\D{0,15}(\d+\.?\d*)', r'\bHb\D{0,10}(\d+\.?\d*)'], t), "RBC": _num([r'\bRBC\D{0,10}(\d+\.?\d*)'], t), "WBC": _num([r'\bWBC\D{0,10}([\d,]+\.?\d*)', r'W\.?B\.?C\.?\D{0,10}([\d,]+\.?\d*)'], t), "AST": _num([r'\bAST\D{0,10}(\d+\.?\d*)', r'\bSGOT\D{0,10}(\d+\.?\d*)'], t), "ALT": _num([r'\bALT\D{0,10}(\d+\.?\d*)', r'\bSGPT\D{0,10}(\d+\.?\d*)'], t), "Cholesterol": _num([r'cholesterol\D{0,15}(\d+\.?\d*)'], t), "Spirometry": _num([r'spirometry\D{0,15}(\d+\.?\d*)', r'\bFEV1?\D{0,10}(\d+\.?\d*)'], t), "Creatinine": _num([r'creatinine\D{0,15}(\d+\.?\d*)'], t), "Glucose": _num([r'glucose\D{0,15}(\d+\.?\d*)', r'blood sugar\D{0,15}(\d+\.?\d*)'], t), "Lipase": _num([r'lipase\D{0,15}(\d+\.?\d*)'], t), "Troponin": _num([r'troponin\D{0,15}(\d+\.?\d*)'], t), }