Spaces:
Sleeping
Sleeping
| import torch | |
| from ultralytics import YOLO | |
| import easyocr | |
| import cv2 | |
| import numpy as np | |
| import gradio as gr | |
| import os | |
| import logging | |
| import re | |
| # Set up logging | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| # Ensure directories exist | |
| os.makedirs(os.getenv('EASYOCR_MODULE_PATH', '/app/.EasyOCR'), exist_ok=True) | |
| os.makedirs(os.getenv('YOLO_CONFIG_DIR', '/app/.config/Ultralytics'), exist_ok=True) | |
| # Download pretrained model | |
| ANPR_WEIGHTS = "anpr_yolov8.pt" | |
| if not os.path.exists(ANPR_WEIGHTS): | |
| logger.info(f"Downloading model weights to {ANPR_WEIGHTS}") | |
| os.system(f"wget -O {ANPR_WEIGHTS} https://github.com/ultralytics/assets/releases/download/v8.2.0/yolov8n.pt") | |
| # Load YOLO model | |
| try: | |
| model = YOLO(ANPR_WEIGHTS) | |
| logger.info(f"Successfully loaded YOLO model from {ANPR_WEIGHTS}") | |
| except Exception as e: | |
| logger.error(f"Error loading YOLO model from {ANPR_WEIGHTS}: {str(e)}") | |
| raise | |
| # Load OCR reader | |
| try: | |
| reader = easyocr.Reader(['en'], model_storage_directory=os.getenv('EASYOCR_MODULE_PATH', '/app/.EasyOCR')) | |
| logger.info("Successfully initialized EasyOCR reader") | |
| except Exception as e: | |
| logger.error(f"Error initializing EasyOCR reader: {str(e)}") | |
| raise | |
| def detect_and_read_plate(image): | |
| logger.info("Starting image processing for license plate detection") | |
| try: | |
| detected_texts = [] | |
| results = model(image, conf=0.1) # Low confidence for broader detection | |
| logger.info(f"YOLO model returned {len(results)} results") | |
| for result in results: | |
| boxes = result.boxes.xyxy.cpu().numpy() | |
| confidences = result.boxes.conf.cpu().numpy() | |
| logger.info(f"Detected {len(boxes)} bounding boxes") | |
| for box, conf in zip(boxes, confidences): | |
| x1, y1, x2, y2 = map(int, box) | |
| # Minimal size filter | |
| if (x2 - x1) < 20 or (y2 - y1) < 10: | |
| logger.warning(f"Skipping small box: ({x1}, {y1}, {x2}, {y2})") | |
| continue | |
| # Crop the detected license plate | |
| plate_img = image[y1:y2, x1:x2] | |
| if plate_img.size == 0: | |
| logger.warning("Empty cropped image, skipping") | |
| continue | |
| # Run OCR | |
| logger.info("Running EasyOCR on cropped plate") | |
| ocr_result = reader.readtext(plate_img) | |
| if ocr_result: | |
| for res in ocr_result: | |
| text = res[1] | |
| confidence = res[2] | |
| # Light filtering: prefer alphanumeric, avoid overly long text | |
| if len(text) <= 12 and confidence > 0.2 and re.match(r'^[A-Z0-9\s\-]+$', text): | |
| detected_texts.append(f"{text} (conf: {conf:.2f})") | |
| logger.info(f"Detected Plate: {text} (YOLO conf: {conf:.2f}, OCR conf: {confidence:.2f})") | |
| else: | |
| logger.info(f"Rejected text: {text} (OCR conf: {confidence:.2f})") | |
| # Draw bounding box | |
| cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2) | |
| output_text = "\n".join(detected_texts) if detected_texts else "No license plate detected" | |
| logger.info(f"Output text: {output_text}") | |
| return image, output_text | |
| except Exception as e: | |
| logger.error(f"Error during detection: {str(e)}") | |
| return image, f"Error processing image: {str(e)}" | |
| # Create Gradio interface | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# Automatic Number Plate Recognition (ANPR)") | |
| gr.Markdown("Upload an image of a car to detect and read its license plate. Results may take a few seconds.") | |
| with gr.Row(): | |
| image_input = gr.Image(type="numpy", label="Upload an image of a car") | |
| with gr.Row(): | |
| image_output = gr.Image(type="numpy", label="Detected License Plate Image") | |
| text_output = gr.Textbox(label="Detected License Plate Number") | |
| submit_button = gr.Button("Detect License Plate") | |
| submit_button.click( | |
| fn=detect_and_read_plate, | |
| inputs=image_input, | |
| outputs=[image_output, text_output], | |
| show_progress=True | |
| ) | |
| demo.launch(server_name="0.0.0.0", server_port=7860) |