Spaces:
Sleeping
Sleeping
Download legacy/d3.py from ansarzeinulla/9OCR: direct link, hf CLI and curl.
- Browser
- Download file 3.84 kB
-
https://huggingface.co/spaces/ansarzeinulla/9OCR/resolve/1b69166ff3b566e4c64f3a39f6730abc742e6bf4/legacy/d3.py
- Command line
-
hf download hf://spaces/ansarzeinulla/9OCR@1b69166ff3b566e4c64f3a39f6730abc742e6bf4/legacy/d3.py
-
curl -L -o d3.py https://huggingface.co/spaces/ansarzeinulla/9OCR/resolve/1b69166ff3b566e4c64f3a39f6730abc742e6bf4/legacy/d3.py
3.84 kB
| import torch | |
| import torch.nn as nn | |
| from torchvision import transforms, models | |
| from PIL import Image | |
| import json | |
| import sys | |
| import cv2 | |
| import numpy as np | |
| # --- EXACT SAME FUNCTION FROM b2.py --- | |
| def crop_and_center_ink(cv2_gray_img, target_w=80, target_h=40, margin=4): | |
| ink_mask = cv2.bitwise_not(cv2_gray_img) | |
| coords = cv2.findNonZero(ink_mask) | |
| if coords is not None: | |
| x, y, w, h = cv2.boundingRect(coords) | |
| if w > 0 and h > 0: | |
| crop = cv2_gray_img[y:y+h, x:x+w] | |
| scale = min((target_w - 2*margin) / w, (target_h - 2*margin) / h) | |
| new_w = max(1, int(w * scale)) | |
| new_h = max(1, int(h * scale)) | |
| resized_crop = cv2.resize(crop, (new_w, new_h), interpolation=cv2.INTER_AREA) | |
| canvas = np.full((target_h, target_w), 255, dtype=np.uint8) | |
| start_x = (target_w - new_w) // 2 | |
| start_y = (target_h - new_h) // 2 | |
| canvas[start_y:start_y+new_h, start_x:start_x+new_w] = resized_crop | |
| return canvas | |
| return np.full((target_h, target_w), 255, dtype=np.uint8) | |
| # ... (imports and crop_and_center_ink stay the same) ... | |
| def preprocess_for_ai(image_path): | |
| img = cv2.imread(image_path) | |
| gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) | |
| # Use a sharper threshold to keep lines crisp | |
| blurred = cv2.GaussianBlur(gray, (3, 3), 0) | |
| thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, | |
| cv2.THRESH_BINARY, 21, 7) | |
| # Clean up small noise dots ONLY | |
| ink_is_white = cv2.bitwise_not(thresh) | |
| contours, _ = cv2.findContours(ink_is_white, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) | |
| for cnt in contours: | |
| if cv2.contourArea(cnt) < 15: # Smaller threshold for noise | |
| cv2.drawContours(ink_is_white, [cnt], -1, 0, -1) | |
| # DO NOT dilate here. Let the centering handle the size. | |
| final_img = cv2.bitwise_not(ink_is_white) | |
| # Center it | |
| centered_np = crop_and_center_ink(final_img, target_w=80, target_h=40) | |
| # Optional: Apply a standard 2x2 dilation to match training "thick" mode | |
| # if the handwriting is very thin. | |
| # centered_np = cv2.erode(centered_np, np.ones((2,2), np.uint8)) | |
| pil_img = Image.fromarray(centered_np).convert('RGB') | |
| pil_img.save("debug_AI_eyes.png") | |
| return pil_img | |
| # ... (main function stays same as previous) ... | |
| def main(image_path): | |
| device = torch.device("mps") if torch.backends.mps.is_available() else torch.device("cpu") | |
| with open("class_mapping.json", "r") as f: | |
| class_to_idx = json.load(f) | |
| idx_to_class = {int(v): k for k, v in class_to_idx.items()} | |
| NUM_CLASSES = len(idx_to_class) | |
| model = models.resnet18(weights=None) | |
| model.fc = nn.Linear(model.fc.in_features, NUM_CLASSES) | |
| model.load_state_dict(torch.load("togyzkumalak_model.pth", map_location=device)) | |
| model = model.to(device) | |
| model.eval() | |
| pil_image = preprocess_for_ai(image_path) | |
| transform = transforms.Compose([ | |
| transforms.Resize((40, 80)), # MUST match the 2:1 ratio | |
| transforms.ToTensor(), | |
| transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) | |
| ]) | |
| image_tensor = transform(pil_image).unsqueeze(0).to(device) | |
| with torch.no_grad(): | |
| outputs = model(image_tensor) | |
| probabilities = torch.nn.functional.softmax(outputs[0], dim=0) | |
| top_probs, top_classes = torch.topk(probabilities, 3) | |
| print(f"\n--- AI PREDICTIONS FOR '{image_path}' ---") | |
| for i in range(3): | |
| print(f"Choice {i+1}: Move '{idx_to_class[top_classes[i].item()]}' with {top_probs[i].item() * 100:.2f}% conf") | |
| if __name__ == '__main__': | |
| if len(sys.argv) < 2: | |
| print("Usage: python d2.py <path_to_image>") | |
| else: | |
| main(sys.argv[1]) |