CoolFace
Apppublic

frknuzn/ocr-poc

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
utils.py173 linesDownload Raw Back to src
1from __future__ import annotations2 3from typing import List, Tuple4 5import numpy as np6 7 8def load_image(path_or_img) -> np.ndarray:9    if isinstance(path_or_img, np.ndarray):10        return path_or_img11    try:12        import cv213    except Exception as e:14        raise RuntimeError("OpenCV (opencv-python) gerekli: pip install -r requirements.txt") from e15    img = cv2.imread(str(path_or_img))16    if img is None:17        raise FileNotFoundError(f"Görsel yüklenemedi veya bulunamadı: {path_or_img}")18    return img19 20 21def _preprocess_variants(img: np.ndarray) -> list:22    try:23        import cv224    except Exception:25        return [img]26    variants = [img]27    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) if img.ndim == 3 else img.copy()28    try:29        clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))30        eq = clahe.apply(gray)31        variants.append(eq)32    except Exception:33        pass34    try:35        th = cv2.adaptiveThreshold(36            gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 1137        )38        variants.append(th)39    except Exception:40        pass41    return variants42 43 44_ocr_instance = None45 46 47def _get_ocr():48    global _ocr_instance49    if _ocr_instance is None:50        try:51            from paddleocr import PaddleOCR52        except Exception as e:53            raise RuntimeError(54                "PaddleOCR kurulumu eksik. Lütfen şu adımları izleyin:\n"55                "1) pip install -U pip wheel setuptools\n"56                "2) pip uninstall -y paddleocr paddlex PyMuPDF pymupdf\n"57                "3) pip install \"paddleocr==2.7.0.3\" --no-deps\n"58                "4) pip install -r requirements.txt\n"59            ) from e60        _ocr_instance = PaddleOCR(lang="tr", use_angle_cls=True, show_log=False)61    return _ocr_instance62 63 64def read_text_with_paddle(image_or_path) -> List[str]:65    ocr = _get_ocr()66    # Collect OCR results from multiple variants67    variants = []68    if isinstance(image_or_path, np.ndarray):69        variants = _preprocess_variants(image_or_path)70    else:71        try:72            img = load_image(image_or_path)73            variants = _preprocess_variants(img)74        except Exception:75            variants = []76 77    results = []78    if variants:79        for v in variants:80            try:81                results.append(ocr.ocr(v, cls=True))82            except Exception:83                continue84    else:85        results.append(ocr.ocr(image_or_path, cls=True))86 87    grouped_lines: List[str] = []88    plain_tokens: List[str] = []89 90    for res in results:91        for page in res:92            items: List[Tuple[float, float, float, str]] = []93            for box, (text, conf) in page:94                text = (text or "").strip()95                if not text:96                    continue97                xs = [p[0] for p in box]98                ys = [p[1] for p in box]99                x_min = float(min(xs))100                y_c = float(sum(ys) / len(ys))101                h = float(max(ys) - min(ys))102                items.append((y_c, x_min, h, text))103                plain_tokens.append(text)104 105            if not items:106                continue107            items.sort(key=lambda t: (t[0], t[1]))108            hs = [h for _, _, h, _ in items if h > 0]109            tol = (np.median(hs) * 0.6) if hs else 10.0110 111            buckets: List[List[Tuple[float, float, float, str]]] = []112            cur_y = None113            cur_bucket: List[Tuple[float, float, float, str]] = []114            for it in items:115                yc, x, h, tx = it116                if cur_y is None or abs(yc - cur_y) <= tol:117                    cur_bucket.append(it)118                    cur_y = yc if cur_y is None else cur_y119                else:120                    buckets.append(cur_bucket)121                    cur_bucket = [it]122                    cur_y = yc123            if cur_bucket:124                buckets.append(cur_bucket)125 126            for bucket in buckets:127                bucket.sort(key=lambda t: t[1])128                line = " ".join(tx for _, _, _, tx in bucket).strip()129                if line:130                    grouped_lines.append(line)131 132    if len(grouped_lines) < max(8, int(len(plain_tokens) * 0.5)):133        # Simple fallback: join tokens in reading order with a separator for large X jumps134        approx_lines: List[str] = []135        try:136            # Build from the first OCR pass if available137            first = results[0] if results else []138            last_x = None139            buf: List[str] = []140            for page in first:141                items: List[Tuple[float, float, float, str]] = []142                for box, (text, conf) in page:143                    text = (text or "").strip()144                    if not text:145                        continue146                    xs = [p[0] for p in box]147                    ys = [p[1] for p in box]148                    x_min = float(min(xs))149                    y_c = float(sum(ys) / len(ys))150                    items.append((y_c, x_min, 0.0, text))151                items.sort(key=lambda t: (t[0], t[1]))152                for yc, x, _, tx in items:153                    if last_x is None or (x - last_x) < 60:154                        buf.append(tx)155                    else:156                        if buf:157                            approx_lines.append(" ".join(buf).strip())158                            buf = [tx]159                    last_x = x160            if buf:161                approx_lines.append(" ".join(buf).strip())162        except Exception:163            pass164        seen = set()165        merged: List[str] = []166        for ln in approx_lines + grouped_lines:167            if ln and ln not in seen:168                merged.append(ln)169                seen.add(ln)170        return merged171 172    return grouped_lines173