File size: 4,391 Bytes
27213d5
4ba5ed3
3b7e472
 
 
27213d5
3b7e472
18a03cd
2df0a06
18a03cd
 
 
 
83ce000
2b2bc36
 
 
 
f0e8f2a
3b7e472
 
18a03cd
3d93d68
27213d5
f0e8f2a
2b2bc36
 
18a03cd
2b2bc36
18a03cd
2b2bc36
27213d5
f0e8f2a
2b2bc36
 
18a03cd
2b2bc36
18a03cd
2b2bc36
27213d5
3b7e472
18a03cd
 
 
a34cd68
18a03cd
 
 
f0e8f2a
2df0a06
18a03cd
2df0a06
 
18a03cd
a34cd68
27ef20f
 
2df0a06
 
18a03cd
 
 
 
 
2df0a06
f0e8f2a
 
 
 
2df0a06
 
 
a34cd68
27ef20f
2df0a06
 
 
 
 
 
 
18a03cd
 
f0e8f2a
18a03cd
 
 
 
 
f0e8f2a
18a03cd
 
a34cd68
f8ac2af
18a03cd
 
 
 
 
f8ac2af
18a03cd
 
 
 
 
 
 
3b7e472
f8ac2af
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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)