license_plate / app.py
AnsMurtaza's picture
Update app.py
56c372d verified
import gradio as gr
from ultralytics import YOLO
import cv2
import numpy as np
from paddleocr import PaddleOCR
import re
# Load models once
model_path = 'yolo11x.pt'
model2_path = r"yolo11_anpr_ghd.pt"
model = YOLO(model_path)
model2 = YOLO(model2_path)
# Initialize PaddleOCR globally to avoid re-initializing on each call
# For Hugging Face Spaces, ensure necessary PaddleOCR models are downloaded (e.g., within Dockerfile or setup script)
# Using 'en' for English license plates and disabling angle classification for simplicity
ocr = PaddleOCR(use_doc_orientation_classify=False,
use_doc_unwarping=False,
use_textline_orientation=False,
lang='en') # Added lang='en' for better English OCR
# Example images paths - these might need adjustment for Hugging Face Spaces
# If these are locally stored, they need to be part of the uploaded files in your Space.
example_images = [
r"examples/car1.png",
r"examples/car2.png",
r"examples/car3.png",
r"examples/car4.png",
r"examples/car5.png",
]
def detect_and_annotate(image):
# Convert PIL image to OpenCV format
img = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
# Initialize message
output_message = ""
# Start with a copy of the original image for annotations
annotated_frame = img.copy()
# Vehicle detection
results = model(img, classes=[2, 5, 7, 3]) # vehicle classes
# IMPORTANT FIX: The .plot() method on results[0] already returns a new image with annotations.
# We should use this directly as our base annotated_frame.
if results and results[0].boxes and len(results[0].boxes) > 0: # Check if vehicle results exist and have boxes
# Plot vehicle detections. This returns an annotated NumPy array (BGR format).
annotated_frame = results[0].plot(line_width=3)
# License plate detection only if vehicle is detected
license_plate_results = model2(img)
if license_plate_results and len(license_plate_results[0].boxes) > 0:
# Iterate through detected license plates if there are multiple
for license_box_data in license_plate_results[0].boxes:
license_box = license_box_data.xyxy[0].cpu().numpy()
x1, y1, x2, y2 = map(int, license_box)
# Draw rectangle for license plate on the annotated frame
cv2.rectangle(annotated_frame, (x1, y1), (x2, y2), (255, 0, 0), 3)
# OCR on license plate region
license_plate_region = img[y1:y2, x1:x2]
try:
# IMPORTANT FIX: Pass the NumPy array directly to PaddleOCR's ocr method
# This avoids the file read/write error.
ocr_result = ocr.ocr(img=license_plate_region, cls=True) # Changed from .predict to .ocr
license_plate_text = ""
if ocr_result and ocr_result[0] and ocr_result[0][0]: # Check for valid OCR result structure
# The OCR result structure for ocr.ocr is different: it's a list of blocks, each containing [bbox, (text, score)]
# We are interested in the text from the first block's first item
text = ocr_result[0][0][1][0]
text = re.sub(r'[^a-zA-Z0-9]', '', text)
license_plate_text = text
output_message += f"Detected License Plate Text: {license_plate_text}\n"
else:
output_message += "No text found on license plate.\n"
# Put text on the annotated frame (still show on image for visual feedback)
display_text_on_image = license_plate_text if license_plate_text else "No text found"
cv2.putText(annotated_frame, display_text_on_image, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
except Exception as e:
output_message += f"OCR Error: {e}\n"
print(f"OCR error on region: {e}")
else:
output_message = "No number plate detected in vehicle.\n"
else:
output_message = "No vehicles detected."
# If no vehicles are detected, simply return the original image (or a copy)
# as there's no need to annotate it with a "No vehicles detected" message on the image itself.
annotated_frame = img.copy() # Ensure we always return an image
# Convert back to RGB for display in Gradio
annotated_frame = cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB)
return annotated_frame, output_message
iface = gr.Interface(
fn=detect_and_annotate,
inputs=gr.Image(type="pil"),
outputs=[gr.Image(type="numpy", label="Annotated Image"),
gr.Textbox(label="Detection Messages")], # Added Textbox for messages
title="Vehicle & License Plate Detection with OCR",
description="Upload an image. The app will detect vehicles and license plates, perform OCR, and display the result with annotations and messages.",
examples=example_images,
cache_examples=False
)
if __name__ == "__main__":
iface.launch(share=True)