| import streamlit as st
|
| import pandas as pd
|
| from datetime import datetime
|
| import plotly.express as px
|
| import plotly.graph_objects as go
|
|
|
|
|
| st.set_page_config(
|
| page_title="License Plate Detection Results",
|
| page_icon="🚗",
|
| layout="wide"
|
| )
|
|
|
|
|
| st.markdown("""
|
| <style>
|
| .metric-container {
|
| background-color: #f0f2f6;
|
| border-radius: 10px;
|
| padding: 15px;
|
| margin: 10px 0;
|
| }
|
| .stMetric {
|
| background-color: white !important;
|
| border-radius: 5px;
|
| padding: 10px;
|
| box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
| }
|
| </style>
|
| """, unsafe_allow_html=True)
|
|
|
|
|
| st.title("📊 License Plate Detection Dashboard")
|
| st.markdown("""
|
| This dashboard shows the results of license plate detections from video surveillance.
|
| """)
|
|
|
|
|
| @st.cache_data
|
| def load_data():
|
| try:
|
| df = pd.read_csv("car_plate_data_stored.csv")
|
|
|
|
|
| if 'NumberPlate' in df.columns:
|
| df = df.rename(columns={'NumberPlate': 'ID'})
|
| elif 'ImageFile' in df.columns:
|
| df = df.rename(columns={'ImageFile': 'ID'})
|
|
|
|
|
| if 'Confidence' not in df.columns:
|
| df['Confidence'] = 'N/A'
|
|
|
|
|
| df['DateTime'] = pd.to_datetime(df['Date'] + ' ' + df['Time'],
|
| format='%d-%m-%Y %H:%M:%S',
|
| dayfirst=True)
|
|
|
| return df
|
| except Exception as e:
|
| st.error(f"Error loading data: {str(e)}")
|
| return pd.DataFrame(columns=['ID', 'Date', 'Time', 'Confidence', 'DateTime'])
|
|
|
|
|
| df = load_data()
|
|
|
|
|
| col1, col2 = st.columns([2, 1])
|
|
|
| with col1:
|
|
|
| st.markdown('<div class="metric-container">', unsafe_allow_html=True)
|
| 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)
|
| st.markdown('</div>', unsafe_allow_html=True)
|
|
|
|
|
| if not df.empty:
|
| st.subheader("Detection Timeline")
|
| detections_by_time = df.groupby(df['DateTime'].dt.floor('H')).size().reset_index(name='count')
|
|
|
| fig = go.Figure()
|
| fig.add_trace(go.Scatter(
|
| x=detections_by_time['DateTime'],
|
| y=detections_by_time['count'],
|
| mode='lines+markers',
|
| line=dict(color='#1f77b4', width=2),
|
| marker=dict(size=6),
|
| name='Detections'
|
| ))
|
|
|
| fig.update_layout(
|
| title="Detections Over Time",
|
| xaxis_title="Time",
|
| yaxis_title="Number of Detections",
|
| height=400,
|
| hovermode='x unified',
|
| plot_bgcolor='white',
|
| paper_bgcolor='white',
|
| xaxis=dict(
|
| showgrid=True,
|
| gridcolor='#f0f0f0',
|
| ),
|
| yaxis=dict(
|
| showgrid=True,
|
| gridcolor='#f0f0f0',
|
| )
|
| )
|
| st.plotly_chart(fig, use_container_width=True)
|
|
|
| with col2:
|
| st.subheader("Recent Detections")
|
| if not df.empty:
|
| recent = df.tail(5)
|
| for _, row in recent.iterrows():
|
| with st.container():
|
| st.markdown(f"""
|
| <div style="padding: 10px; background-color: #f0f2f6; border-radius: 5px; margin: 5px 0;">
|
| <p><strong>ID:</strong> {row['ID']}</p>
|
| <p><strong>Time:</strong> {row['Time']}</p>
|
| <p><strong>Confidence:</strong> {row['Confidence'] if row['Confidence'] != 'N/A' else 'N/A'}</p>
|
| </div>
|
| """, unsafe_allow_html=True)
|
|
|
|
|
| st.subheader("Detection Records")
|
| if not df.empty:
|
| col1, col2 = st.columns([1, 2])
|
|
|
| with col1:
|
| date_filter = st.date_input(
|
| "Filter by date",
|
| pd.to_datetime(df['Date']).min()
|
| )
|
|
|
| with col2:
|
| confidence_filter = st.slider(
|
| "Minimum confidence",
|
| 0.0, 100.0, 0.0,
|
| help="Filter detections by minimum confidence score"
|
| )
|
|
|
|
|
| filtered_df = df[df['DateTime'].dt.date == date_filter]
|
| if confidence_filter > 0:
|
| numeric_conf = pd.to_numeric(filtered_df['Confidence'].replace('N/A', -1), errors='coerce')
|
| filtered_df = filtered_df[numeric_conf >= confidence_filter]
|
|
|
|
|
| st.dataframe(
|
| filtered_df[['ID', 'Date', 'Time', 'Confidence']].style.format({
|
| 'Confidence': lambda x: f"{x:.2f}%" if isinstance(x, (int, float)) else x
|
| }),
|
| use_container_width=True
|
| )
|
|
|
|
|
| if not df.empty:
|
| st.subheader("Detection Statistics")
|
| col1, col2 = st.columns(2)
|
|
|
| with col1:
|
|
|
| hourly_stats = df.groupby(df['DateTime'].dt.hour).size()
|
| fig = px.bar(
|
| x=hourly_stats.index,
|
| y=hourly_stats.values,
|
| labels={'x': 'Hour of Day', 'y': 'Number of Detections'},
|
| title='Detections by Hour of Day'
|
| )
|
| fig.update_layout(bargap=0.2)
|
| st.plotly_chart(fig, use_container_width=True)
|
|
|
| with col2:
|
|
|
| confidence_values = pd.to_numeric(df['Confidence'].replace('N/A', float('nan')), errors='coerce')
|
| confidence_values = confidence_values.dropna()
|
|
|
| if not confidence_values.empty:
|
| fig = px.histogram(
|
| confidence_values,
|
| nbins=20,
|
| labels={'value': 'Confidence Score', 'count': 'Number of Detections'},
|
| title='Distribution of Confidence Scores'
|
| )
|
| fig.update_layout(bargap=0.2)
|
| st.plotly_chart(fig, use_container_width=True) |