Download app_phase2review1.py from Sarvamangalak/Smart_Vehicle_Classification: direct link, hf CLI and curl.
- Browser
- Download file 8.92 kB
-
https://huggingface.co/spaces/Sarvamangalak/Smart_Vehicle_Classification/resolve/main/app_phase2review1.py
- Command line
-
hf download hf://spaces/Sarvamangalak/Smart_Vehicle_Classification/app_phase2review1.py
-
curl -L -o app_phase2review1.py https://huggingface.co/spaces/Sarvamangalak/Smart_Vehicle_Classification/resolve/main/app_phase2review1.py
8.92 kB
| # Author Sarvamangala Kokatanur | |
| # Import libraries | |
| import gradio as gr | |
| import torch | |
| import numpy as np | |
| import cv2 | |
| import sqlite3 | |
| import pandas as pd | |
| import matplotlib.pyplot as plt | |
| from datetime import datetime, timedelta | |
| from PIL import Image, ImageDraw | |
| from transformers import ( | |
| YolosImageProcessor, | |
| YolosForObjectDetection | |
| ) | |
| # Load model | |
| processor = YolosImageProcessor.from_pretrained( | |
| "nickmuchi/yolos-small-finetuned-license-plate-detection" | |
| ) | |
| model = YolosForObjectDetection.from_pretrained( | |
| "nickmuchi/yolos-small-finetuned-license-plate-detection" | |
| ) | |
| model.eval() | |
| # ---------------- DATABASE ---------------- | |
| conn = sqlite3.connect( | |
| "vehicles.db", | |
| check_same_thread=False | |
| ) | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| CREATE TABLE IF NOT EXISTS vehicles( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| timestamp TEXT, | |
| license_plate TEXT, | |
| vehicle_status TEXT, | |
| discount INTEGER | |
| ) | |
| """) | |
| conn.commit() | |
| # -------- Plate Color Classifier -------- # | |
| def classify_plate_color(plate_img): | |
| img = np.array(plate_img) | |
| # Convert RGB → HSV | |
| hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV) | |
| h, w = hsv.shape[:2] | |
| # Only inspect the left 20% of the plate | |
| left = hsv[:, :int(w*0.2)] | |
| # Green mask | |
| green = cv2.inRange( | |
| left, | |
| (35, 40, 40), | |
| (90, 255, 255) | |
| ) | |
| green_ratio = np.count_nonzero(green) / green.size | |
| # If more than 15% of the left strip is green, | |
| # classify as EV | |
| if green_ratio > 0.15: | |
| return "EV" | |
| return "Non-EV" | |
| # Avoid duplicate vehicle details to the dashboard | |
| def is_duplicate_vehicle(plate_number): | |
| cursor.execute(""" | |
| SELECT timestamp | |
| FROM vehicles | |
| WHERE license_plate=? | |
| ORDER BY id DESC | |
| LIMIT 1 | |
| """,(plate_number,)) | |
| row = cursor.fetchone() | |
| if row is None: | |
| return False | |
| last_time = datetime.strptime( | |
| row[0], | |
| "%Y-%m-%d %H:%M:%S" | |
| ) | |
| if datetime.now() - last_time < timedelta(minutes=5): | |
| return True | |
| return False | |
| # to save vehicle details in the database | |
| def save_vehicle(plate,status): | |
| if status=="EV": | |
| discount=50 | |
| else: | |
| discount=0 | |
| if is_duplicate_vehicle(plate): | |
| return "Duplicate" | |
| current_time=datetime.now().strftime( | |
| "%Y-%m-%d %H:%M:%S" | |
| ) | |
| cursor.execute(""" | |
| INSERT INTO vehicles( | |
| timestamp, | |
| license_plate, | |
| vehicle_status, | |
| discount | |
| ) | |
| VALUES(?,?,?,?) | |
| """, | |
| ( | |
| current_time, | |
| plate, | |
| status, | |
| discount | |
| )) | |
| conn.commit() | |
| return "Saved" | |
| # --------get_dashboard function ------# | |
| def get_dashboard(): | |
| df = pd.read_sql( | |
| "SELECT * FROM vehicles", | |
| conn | |
| ) | |
| fig, axs = plt.subplots(2, 2, figsize=(8, 6)) | |
| if df.empty: | |
| for ax in axs.flatten(): | |
| ax.text( | |
| 0.5, | |
| 0.5, | |
| "No Data Available", | |
| ha="center", | |
| va="center", | |
| fontsize=10 | |
| ) | |
| ax.axis("off") | |
| plt.tight_layout() | |
| return fig | |
| status_counts = df["vehicle_status"].value_counts() | |
| axs[0,0].bar( | |
| status_counts.index, | |
| status_counts.values | |
| ) | |
| axs[0,0].set_title("EV vs Non-EV") | |
| if status_counts.empty: | |
| plt.tight_layout() | |
| return fig | |
| axs[0,1].pie( | |
| status_counts.values, | |
| labels=status_counts.index, | |
| autopct="%1.1f%%" | |
| ) | |
| axs[0,1].set_title("Vehicle Distribution") | |
| total_discount = df["discount"].sum() | |
| axs[1,0].bar( | |
| ["Discount"], | |
| [total_discount] | |
| ) | |
| axs[1,0].set_title("Total Discount") | |
| axs[1,1].axis("off") | |
| report = ( | |
| f"Today's Report\n\n" | |
| f"Total Vehicles : {len(df)}\n\n" | |
| f"EV : {len(df[df.vehicle_status=='EV'])}\n\n" | |
| f"Non-EV : {len(df[df.vehicle_status=='Non-EV'])}\n\n" | |
| f"Discount Given : ₹{total_discount}" | |
| ) | |
| axs[1,1].text( | |
| 0, | |
| 1, | |
| report, | |
| fontsize=10, | |
| va="top" | |
| ) | |
| plt.tight_layout() | |
| plt.close(fig) | |
| return fig | |
| # -------- Main Pipeline -------- # | |
| def process_image(img): | |
| if img is None: | |
| return ( | |
| None, | |
| "Please upload an image.", | |
| "0", | |
| "0", | |
| "₹0", | |
| get_dashboard() | |
| ) | |
| image = Image.fromarray(img) | |
| inputs = processor(images=image, return_tensors="pt") | |
| with torch.no_grad(): | |
| outputs = model(**inputs) | |
| target_sizes = torch.tensor([[image.size[1], image.size[0]]]) | |
| results = processor.post_process_object_detection( | |
| outputs, | |
| threshold=0.3, | |
| target_sizes=target_sizes | |
| )[0] | |
| draw = ImageDraw.Draw(image) | |
| ev_count = 0 | |
| non_ev_count = 0 | |
| discount_total = 0 | |
| output_text = "" | |
| # No detection | |
| if len(results["boxes"]) == 0: | |
| return ( | |
| image, | |
| "No license plate detected.", | |
| "0", | |
| "0", | |
| "₹0", | |
| get_dashboard() | |
| ) | |
| # Process each detected plate | |
| for i, box in enumerate(results["boxes"]): | |
| x1, y1, x2, y2 = map(int, box.tolist()) | |
| plate = image.crop((x1, y1, x2, y2)) | |
| status = classify_plate_color(plate) | |
| # Temporary plate number | |
| # Replace with OCR later | |
| plate_number = f"Vehicle_{datetime.now().strftime('%H%M%S%f')}_{i}" | |
| saved = save_vehicle( | |
| plate_number, | |
| status | |
| ) | |
| # Skip duplicate entries | |
| if saved == "Duplicate": | |
| continue | |
| if status == "EV": | |
| ev_count += 1 | |
| discount = 50 | |
| discount_total += discount | |
| color = "green" | |
| label = f"{plate_number}\nEV | ₹{discount}" | |
| else: | |
| non_ev_count += 1 | |
| discount = 0 | |
| color = "red" | |
| label = f"{plate_number}\nNon-EV" | |
| # Draw bounding box | |
| draw.rectangle( | |
| [x1, y1, x2, y2], | |
| outline=color, | |
| width=3 | |
| ) | |
| # Draw label | |
| draw.text( | |
| (x1, max(0, y1 - 30)), | |
| label, | |
| fill=color | |
| ) | |
| output_text += ( | |
| f"Vehicle {i+1}\n" | |
| f"Plate : {plate_number}\n" | |
| f"Status : {status}\n" | |
| f"Discount : ₹{discount}\n\n" | |
| ) | |
| conn.commit() | |
| dashboard = get_dashboard() | |
| return ( | |
| image, | |
| output_text, | |
| str(ev_count), | |
| str(non_ev_count), | |
| f"₹{discount_total}", | |
| dashboard | |
| ) | |
| # -------- Gradio UI -------- # | |
| css = """ | |
| .gradio-container{ | |
| max-width:98% !important; | |
| margin:auto; | |
| } | |
| textarea{ | |
| font-size:15px !important; | |
| } | |
| h1{ | |
| text-align:center; | |
| } | |
| .block{ | |
| border-radius:12px; | |
| } | |
| .gr-image{ | |
| min-height:350px; | |
| } | |
| """ | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# Smart Traffic & EV Analytics System") | |
| gr.Markdown( | |
| "Automatic License Plate Detection • EV Classification • Discount Calculation" | |
| ) | |
| ################################################## | |
| # TOP SECTION | |
| ################################################## | |
| with gr.Row(equal_height=True): | |
| # LEFT | |
| with gr.Column(scale=1): | |
| input_img = gr.Image( | |
| type="numpy", | |
| label="Input Image", | |
| sources=["upload","webcam"], | |
| height=350 | |
| ) | |
| btn = gr.Button( | |
| "Scan Vehicle", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| # CENTER | |
| with gr.Column(scale=1): | |
| output_img = gr.Image( | |
| label="Detection Result", | |
| height=350 | |
| ) | |
| # RIGHT | |
| with gr.Column(scale=1): | |
| summary_box = gr.Textbox( | |
| label="Detection Summary", | |
| lines=16 | |
| ) | |
| ################################################## | |
| # STATISTICS | |
| ################################################## | |
| with gr.Row(): | |
| ev_box = gr.Textbox( | |
| label="EV Vehicles" | |
| ) | |
| non_ev_box = gr.Textbox( | |
| label="Non-EV Vehicles" | |
| ) | |
| discount_box = gr.Textbox( | |
| label="Total Discount" | |
| ) | |
| ################################################## | |
| # DASHBOARD | |
| ################################################## | |
| gr.Markdown("## 📊 Today's Traffic Dashboard") | |
| dashboard = gr.Plot(label="Analytics") | |
| btn.click( | |
| fn=process_image, | |
| inputs=input_img, | |
| outputs=[ | |
| output_img, | |
| summary_box, | |
| ev_box, | |
| non_ev_box, | |
| discount_box, | |
| dashboard | |
| ] | |
| ) | |
| if __name__ == "__main__": | |
| demo.queue() | |
| demo.launch( | |
| ssr_mode=False | |
| ) | |