import streamlit as st import pandas as pd import cv2 import os from datetime import datetime import plotly.express as px from PIL import Image # Set page config st.set_page_config( page_title="License Plate Detection Dashboard", page_icon="🚗", layout="wide" ) # Title st.title("License Plate Detection Dashboard") # Sidebar st.sidebar.header("Dashboard Controls") # Read the CSV file @st.cache_data def load_data(): try: # Try to read from the original file first try: df = pd.read_csv("car_plate_data_stored.csv") except: # If that fails, try the new format file df = pd.read_csv("car_plate_data_new.csv") # Ensure we have the correct column names if 'NumberPlate' in df.columns: df = df.rename(columns={'NumberPlate': 'ID'}) elif 'ImageFile' in df.columns: df = df.rename(columns={'ImageFile': 'ID'}) # Ensure we have the right columns if 'NumberPlate' in df.columns: df = df.rename(columns={'NumberPlate': 'ID'}) # Add Confidence column if it doesn't exist if 'Confidence' not in df.columns: df['Confidence'] = 'N/A' # Clean up confidence values df['Confidence'] = df['Confidence'].fillna('N/A') # Parse dates properly df['DateTime'] = pd.to_datetime(df['Date'] + ' ' + df['Time'], format='%d-%m-%Y %H:%M:%S', dayfirst=True) # Convert confidence values to numeric where possible df['Confidence'] = pd.to_numeric(df['Confidence'].replace('N/A', float('nan')), errors='coerce') # Convert date and time to datetime df['DateTime'] = pd.to_datetime(df['Date'] + ' ' + df['Time']) # Fill missing confidence values with None if 'Confidence' in df.columns: df['Confidence'] = df['Confidence'].fillna('N/A') else: df['Confidence'] = 'N/A' return df except FileNotFoundError: return pd.DataFrame(columns=['ID', 'Date', 'Time', 'Confidence', 'DateTime']) df = load_data() # Main content col1, col2 = st.columns([2, 1]) with col1: st.header("Detection Statistics") # Statistics cards stat_col1, stat_col2, stat_col3 = st.columns(3) with stat_col1: st.metric("Total Detections", len(df)) with stat_col2: if not df.empty: numeric_conf = pd.to_numeric(df['Confidence'].replace('N/A', float('nan')), errors='coerce') avg_confidence = numeric_conf.mean() if pd.notnull(avg_confidence): st.metric("Average Confidence", f"{avg_confidence:.2f}%") else: st.metric("Average Confidence", "N/A") with stat_col3: if not df.empty: today = datetime.now().date() today_detections = df[pd.to_datetime(df['Date']).dt.date == today].shape[0] st.metric("Today's Detections", today_detections) # Timeline chart if not df.empty: st.subheader("Detection Timeline") timeline_fig = px.line( df.groupby('DateTime').size().reset_index(name='count'), x='DateTime', y='count', title="Detections Over Time" ) st.plotly_chart(timeline_fig, use_container_width=True) with col2: st.header("Recent Detections") if not df.empty: recent = df.tail(5) for _, row in recent.iterrows(): # Check if the ID is a filename (new format) or a plate number (old format) if row['ID'].endswith('.jpg'): img_path = os.path.join("detected_plates", row['ID']) conf_text = f" ({row['Confidence']}% confidence)" if row['Confidence'] != 'N/A' else "" else: # For old format, there might not be an image img_path = None conf_text = "" if img_path and os.path.exists(img_path): st.image(img_path, caption=f"Detected at {row['Time']}{conf_text}") else: st.write(f"License Plate: {row['ID']} detected at {row['Time']}{conf_text}") # Data table st.header("Detection Records") if not df.empty: # Add filters date_filter = st.date_input("Filter by date", pd.to_datetime(df['Date']).min()) confidence_filter = st.slider("Minimum confidence", 0.0, 100.0, 0.0) # Apply filters filtered_df = df[df['DateTime'].dt.date == date_filter] # Handle confidence filter if confidence_filter > 0: # Convert confidence to numeric, treating non-numeric values as -1 numeric_conf = pd.to_numeric(df['Confidence'], errors='coerce').fillna(-1) filtered_df = filtered_df[numeric_conf >= confidence_filter] st.dataframe( filtered_df[['ID', 'Date', 'Time', 'Confidence']], use_container_width=True ) else: st.info("No detections recorded yet. Start the detection system to collect data.") # Image gallery st.header("Image Gallery") if not df.empty: # Filter for rows that have image files image_df = df[df['ID'].str.endswith('.jpg', na=False)] if not image_df.empty: # Create a grid of images gallery = st.columns(4) for idx, row in image_df.iterrows(): img_path = os.path.join("detected_plates", row['ID']) if os.path.exists(img_path): with gallery[idx % 4]: conf_text = f" ({row['Confidence']}% conf.)" if row['Confidence'] != 'N/A' else "" st.image(img_path, caption=f"{row['Time']}{conf_text}", use_column_width=True) else: st.info("No images available in the gallery. Only text detections are present.")