Plate_Reader / app.py
muddasser's picture
Update app.py
a34cd68 verified
raw
history blame
4.39 kB
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)