"""Jordanian LPR - Vehicle Plate Detection and Recognition. (نظام التعرف على لوحات المركبات الأردنية). An automated system for detecting and recognizing Jordanian vehicle license plates using computer vision and deep learning. The model handles multiple plate types under varied real-world conditions including daylight, night, and motion blur. Jordanian vehicle license plates are divided into two primary sections, each serving a distinct identification purpose. The left side of the plate contains the vehicle classification and registration category information, which identifies the type of vehicle and its registration class within the Kingdom. Depending on the plate type, this section may include indicators for private vehicles, public transportation, government vehicles, diplomatic vehicles, or other designated categories. The right side of the plate contains the unique vehicle registration number, which serves as the primary identifier for the individual vehicle. This number is unique within its respective classification and is used by authorities and automated recognition systems to distinguish one vehicle from another. Together, these two sections provide both the classification context and the unique identification necessary for vehicle registration, law enforcement, and automated license plate recognition (ALPR) systems. """ import os import numpy as np import gradio as gr from ultralytics import YOLO # Weights ship in the repo; override with a HF Hub path via env if you prefer. VEHICLE_MODEL_PATH = os.environ.get("MODEL_PATH", "yolo26x.pt") PLATE_DETECTION_MODEL_PATH = os.environ.get("MODEL_PATH", "license-plate-finetune-v1l.pt") PLATE_RECOGNITION_MODEL_PATH = os.environ.get("MODEL_PATH", "jordanian-plate-recognition-finetune-v5s.pt") DEFAULT_CONF = 0.70 # matches the production deterrent's localYoloConfidenceThreshold vehicle_model = YOLO(VEHICLE_MODEL_PATH) plate_detection_model = YOLO(PLATE_DETECTION_MODEL_PATH) plate_recognition_model = YOLO(PLATE_RECOGNITION_MODEL_PATH) def detect(image, conf): boxes, rows = [], [] """Run detection and return (annotated image, table rows, deterrent verdict).""" if image is None: return None, [], "Upload a frame to begin." # 1- Detect Vehicles detected_vehicles = vehicle_model.predict(image, conf=0.8, verbose=False, iou=0.45, classes=[2, 3, 5, 7])[0] results = detected_vehicles for vehicle_index, box in enumerate(detected_vehicles.boxes.xyxy.cpu().tolist()): vehicle_x1, vehicle_y1, vehicle_x2, vehicle_y2 = map(int, box) # 2- Crop vehicle ROI vehicle_crop = image.crop((vehicle_x1, vehicle_y1, vehicle_x2, vehicle_y2)) # 3- Detect plate pos detected_plate = plate_detection_model.predict(vehicle_crop, verbose=False, conf=0.5, iou=0.05) # Adjust confidence and IoU thresholds as needed plate_id = 0 # 4- Detect Plates for plate_index, box in enumerate(detected_plate[0].boxes.xyxy.cpu().tolist()): plate_id += 1 plate_x1, plate_y1, plate_x2, plate_y2 = map(int, box) # 5- Detect Vehicles plate_crop = vehicle_crop.crop((plate_x1, plate_y1, plate_x2, plate_y2)) plate_width = plate_x2 - plate_x1 plate_height = plate_y2 - plate_y1 # 6- Recognize Plates detected_plate_artifacts = plate_recognition_model.predict(plate_crop, verbose=False, conf=conf, iou=0.05) # 7- Initial Validations if len(detected_plate_artifacts[0].boxes) == 0: continue # No Detections detections = detected_plate_artifacts[0] ordered_idx = np.argsort(detections.boxes.xyxy.cpu().numpy()[:,0]) # 8- Construct Plate Artifacts cls_str = "" if (plate_width/plate_height >2.2): # tall plate for idx in ordered_idx: box = detections.boxes.xyxy[idx] cls_id = detections.boxes.cls[idx] cls_str += plate_recognition_model.names[int(cls_id)] cls_str = cls_str.replace("jo_pvt", "JO-PVT ") elif plate_width/plate_height > 1.5: # wide plate from_y_highest = detections.boxes.xyxy[:,1].max() from_y_lowest = detections.boxes.xyxy[:,1].min() middle_y = (from_y_highest + from_y_lowest) / 2 for idx in ordered_idx: box = detections.boxes.xyxy[idx] from_y = box[1] if from_y < middle_y: cls_id = detections.boxes.cls[idx] cls_str += plate_recognition_model.names[int(cls_id)] cls_str = cls_str.replace("jo_pvt", "JO-PVT ") for idx in ordered_idx: box = detections.boxes.xyxy[idx] from_y = box[1] if from_y > middle_y: cls_id = detections.boxes.cls[int(idx)] cls_str += plate_recognition_model.names[int(cls_id)] cls_str = cls_str.replace("jo_pvt", "JO-PVT ") else: cls_str = "" # 9- Annotate Dedection if cls_str != "" and len(cls_str) >= 5: plate_number = cls_str top_left = (vehicle_x1+plate_x1, vehicle_y1+plate_y1) bottom_right = (vehicle_x1+plate_x1+(plate_x2-plate_x1), vehicle_y1+plate_y1+(plate_y2-plate_y1)) rectangle_color = (0, 0, 255) # Blue in BGR plate_detections = cls_str avgconf = f"{detected_plate_artifacts[0].boxes.conf.mean():0.2}" rows.append([plate_detections, avgconf]) boxes.append(((int(vehicle_x1+plate_x1), int(vehicle_y1+plate_y1), int(vehicle_x1+plate_x1+(plate_x2-plate_x1)), int(vehicle_y1+plate_y1+(plate_y2-plate_y1))), f"[{plate_detections}]")) verdict = f"✅ ({len(detected_vehicles.boxes)}) Vechiles Detected, and ({len(rows)}) Plates Recognized" return (image, boxes), rows, verdict EXAMPLES = [ ["sample_1.jpg", DEFAULT_CONF], ["sample_2.jpg", DEFAULT_CONF], ["sample_3.jpg", DEFAULT_CONF], ["sample_4.jpg", DEFAULT_CONF] ] # Drop the examples that don't exist yet so the Space still launches. EXAMPLES = [e for e in EXAMPLES if os.path.exists(e[0])] demo = gr.Interface( fn=detect, inputs=[ gr.Image(type="pil", label="Street Captures"), gr.Slider(0.05, 0.90, value=DEFAULT_CONF, step=0.01, label="Confidence threshold"), ], outputs=[ gr.AnnotatedImage(label="Detections"), gr.Dataframe(headers=["Detected Plates", "Avg Confidence"], label="What the model identified"), gr.Textbox(label="Deterrent verdict"), ], examples=EXAMPLES or None, title="🚘 Jordanian LPR - Vehicle Plate Detection and Recognition", description=( "Jordanian vehicle license plates are divided into two primary sections, each serving " "a distinct identification purpose. The left side of the plate contains the vehicle " "classification and registration category information, which identifies the type of " "vehicle and its registration class within the Kingdom. Depending on the plate type, " "this section may include indicators for private vehicles, public transportation, " "government vehicles, diplomatic vehicles, or other designated categories. The right " "side of the plate contains the unique vehicle registration number, which serves as " "the primary identifier for the individual vehicle. This number is unique within its " "respective classification and is used by authorities and automated recognition systems " "to distinguish one vehicle from another. Together, these two sections provide both the " "classification context and the unique identification necessary for vehicle registration, " "law enforcement, and automated license plate recognition (ALPR) systems." ), article=( "Built for the Gradio(Hugging Face) **Build Small** (DigitalBigBrain Mobility AI). " "For more information, visit [https://www.DigitalBigBrain.com](https://www.digitalbigbrain.com)." ), ) if __name__ == "__main__": demo.launch()