| import easyocr |
| import easyocr.easyocr |
| import sys |
| import json |
| import os |
| from PIL import Image |
| import io |
|
|
| |
| easyocr.easyocr.corrupt_msg = "Model error" |
|
|
| def process_image(reader, image_path): |
| try: |
| if not os.path.exists(image_path): |
| return {"error": f"Path not found: {image_path}"} |
|
|
| |
| results = reader.readtext(image_path, detail=1) |
| if not results: |
| return {"error": "No text detected"} |
|
|
| symbols = [] |
| for (bbox, text, prob) in results: |
| text = text.strip().upper() |
| clean_text = "".join([c for c in text if c.isalpha()]) |
| if not clean_text: continue |
| |
| x_center = (bbox[0][0] + bbox[2][0]) / 2 |
| y_center = (bbox[0][1] + bbox[2][1]) / 2 |
| |
| if len(clean_text) > 1: |
| |
| w = bbox[2][0] - bbox[0][0] |
| char_w = w / len(clean_text) |
| for i, char in enumerate(clean_text): |
| symbols.append({ |
| "text": char, |
| "x": bbox[0][0] + (i + 0.5) * char_w, |
| "y": y_center |
| }) |
| else: |
| symbols.append({"text": clean_text, "x": x_center, "y": y_center}) |
|
|
| if not symbols: return [] |
|
|
| |
| def get_lanes(coords, num_lanes=8): |
| coords.sort() |
| if not coords: return [] |
| lanes = [] |
| |
| mi, ma = min(coords), max(coords) |
| if ma == mi: return [mi] |
| |
| bucket_size = (ma - mi) / (num_lanes - 1) if num_lanes > 1 else 1 |
| for i in range(num_lanes): |
| center = mi + i * bucket_size |
| lanes.append(center) |
| return lanes |
|
|
| xs = [s["x"] for s in symbols] |
| ys = [s["y"] for s in symbols] |
| |
| x_lanes = get_lanes(xs, 8) |
| y_lanes = get_lanes(ys, 8) |
| |
| grid = [[" " for _ in range(8)] for _ in range(8)] |
| for s in symbols: |
| |
| r = min(range(8), key=lambda i: abs(s["y"] - y_lanes[i])) |
| c = min(range(8), key=lambda i: abs(s["x"] - x_lanes[i])) |
| grid[r][c] = s["text"] |
|
|
| final_symbols = [] |
| for r in range(8): |
| for c in range(8): |
| if grid[r][c] != " ": |
| final_symbols.append({"text": grid[r][c], "r": r, "c": c}) |
| return final_symbols |
| |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| def main(): |
| |
| try: |
| reader = easyocr.Reader(['en'], gpu=False, verbose=False) |
| |
| print("READY", flush=True) |
| except Exception as e: |
| print(json.dumps({"error": f"Init failed: {str(e)}"}), flush=True) |
| return |
|
|
| |
| while True: |
| line = sys.stdin.readline() |
| if not line: |
| break |
| |
| image_path = line.strip() |
| if not image_path: |
| continue |
| |
| result = process_image(reader, image_path) |
| print(json.dumps(result), flush=True) |
|
|
| if __name__ == "__main__": |
| main() |
|
|