""" ♻️ RecycleVision - Garbage Image Classification System Streamlit Application — Deep Learning based Waste Classification & Recycling Assistant """ import streamlit as st import tensorflow as tf from tensorflow.keras.models import load_model from tensorflow.keras.applications.efficientnet import preprocess_input import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import plotly.express as px import plotly.graph_objects as go from plotly.subplots import make_subplots from PIL import Image import cv2 import os from datetime import datetime import time import random import warnings warnings.filterwarnings('ignore') # Page configuration st.set_page_config( page_title="♻️ RecycleVision - Garbage Classifier", page_icon="♻️", layout="wide", initial_sidebar_state="expanded" ) # Custom CSS for professional styling st.markdown(""" """, unsafe_allow_html=True) # Title with animation st.markdown('

♻️ RecycleVision

', unsafe_allow_html=True) st.markdown('

AI-Powered Waste Classification System for Smart Recycling

', unsafe_allow_html=True) # Sidebar navigation st.sidebar.markdown("## 📊 Navigation") page = st.sidebar.radio( "Go to:", ["🏠 Home & Classification", "📈 Model Performance", "ℹ️ About & Info", "⚙️ Settings"] ) # ========== FIXED FUNCTION: load_model_and_classes ========== @st.cache_resource(show_spinner=False) def load_model_and_classes(): """Load the trained model and class labels""" try: # Try to load from current directory model_paths = [ "RecycleVision_EfficientNetB0_Final.keras", "best_efficientnet.keras", "model.keras", "RecycleVision_Final_Model.keras" ] model = None loaded_path = None for path in model_paths: if os.path.exists(path): try: model = load_model(path) loaded_path = path break except Exception as e: st.sidebar.warning(f"Failed to load {path}: {str(e)}") continue # Class labels (always return these) class_labels = ['cardboard', 'glass', 'metal', 'paper', 'plastic', 'trash'] if model is None: st.sidebar.warning("⚠️ Model file not found. Running in DEMO MODE.") return None, class_labels st.sidebar.success(f"✅ Model loaded from: {loaded_path}") return model, class_labels except Exception as e: st.sidebar.error(f"Error loading model: {str(e)}") class_labels = ['cardboard', 'glass', 'metal', 'paper', 'plastic', 'trash'] return None, class_labels # ========== LOAD MODEL AND HANDLE RETURN VALUES ========== load_result = load_model_and_classes() # Default values (in case model not found) class_colors = { 'cardboard': '#FFEEAD', 'glass': '#45B7D1', 'metal': '#96CEB4', 'paper': '#4ECDC4', 'plastic': '#FF6B6B', 'trash': '#D4A5A5' } recycling_info = { 'cardboard': { 'type': '📦 Paper/Cardboard', 'recyclable': '✅ Fully Recyclable', 'bin_color': 'Blue Bin', 'processing': 'Pulped and remanufactured into paper products', 'facts': 'Cardboard can be recycled 5-7 times before fibers become too short', 'icon': '📦', 'tips': 'Flatten boxes before recycling to save space' }, 'glass': { 'type': '🥃 Glass', 'recyclable': '✅ 100% Recyclable', 'bin_color': 'Green Bin', 'processing': 'Crushed, melted, and molded into new glass products', 'facts': 'Glass takes 1 million years to decompose in landfill', 'icon': '🥃', 'tips': 'Rinse containers; labels can stay on' }, 'metal': { 'type': '🔩 Metal', 'recyclable': '✅ Highly Recyclable', 'bin_color': 'Yellow Bin', 'processing': 'Shredded, melted, and purified', 'facts': 'Recycling aluminum saves 95% of energy needed to make new metal', 'icon': '🔩', 'tips': 'Cans can be crushed to save space' }, 'paper': { 'type': '📄 Paper', 'recyclable': '✅ Recyclable', 'bin_color': 'Blue Bin', 'processing': 'Mixed with water to create pulp, then pressed and dried', 'facts': 'Each ton of recycled paper saves 17 trees', 'icon': '📄', 'tips': 'Keep paper dry and clean' }, 'plastic': { 'type': '🧴 Plastic', 'recyclable': '⚠️ Depends on type', 'bin_color': 'White/Clear Bin', 'processing': 'Sorted by type, shredded, melted, and pelletized', 'facts': 'Plastic takes 450+ years to decompose', 'icon': '🧴', 'tips': 'Check recycling number on bottom' }, 'trash': { 'type': '🗑️ General Waste', 'recyclable': '❌ Not Recyclable', 'bin_color': 'Black Bin', 'processing': 'Landfill or incineration', 'facts': 'Reduce waste by choosing reusable products', 'icon': '🗑️', 'tips': 'Consider if items can be reused or repaired' } } # Check what was returned from load_model_and_classes if load_result is None: st.error("Failed to initialize application") st.stop() elif len(load_result) == 2: model, class_labels = load_result # class_colors and recycling_info already defined above else: st.error("Unexpected return value from load_model_and_classes()") st.stop() # Check if model is None (demo mode) if model is None: st.sidebar.info("🔧 Running in DEMO MODE - Showing sample predictions") st.sidebar.warning("Train the model and place it in the project folder for real predictions") # ========== FIXED FUNCTION: predict_image ========== def predict_image(model, image): """Make prediction on image""" try: if model is None: # Dummy prediction for UI demonstration # Return realistic-looking predictions # Random but biased towards certain classes for demo pred = np.random.random(6) pred = pred / pred.sum() # Normalize to sum to 1 return pred processed_img = preprocess_image(image) if processed_img is not None: predictions = model.predict(processed_img, verbose=0)[0] return predictions return None except Exception as e: st.error(f"Error making prediction: {str(e)}") return None # Helper functions (unchanged) def preprocess_image(image): """Preprocess image for model prediction""" try: # Convert to RGB if necessary if image.mode != 'RGB': image = image.convert('RGB') # Resize image = image.resize((224, 224)) # Convert to array img_array = np.array(image) # Add batch dimension img_array = np.expand_dims(img_array, axis=0) # Preprocess for EfficientNet img_array = preprocess_input(img_array) return img_array except Exception as e: st.error(f"Error preprocessing image: {str(e)}") return None def get_top_predictions(predictions, class_labels, top_n=3): """Get top N predictions""" top_indices = np.argsort(predictions)[-top_n:][::-1] return [(class_labels[i], predictions[i] * 100) for i in top_indices] def create_confidence_chart(predictions, class_labels): """Create confidence bar chart""" df = pd.DataFrame({ 'Class': class_labels, 'Confidence': predictions * 100 }).sort_values('Confidence', ascending=True) fig = px.bar( df, x='Confidence', y='Class', orientation='h', title='Classification Confidence Scores', color='Confidence', color_continuous_scale='Greens', text=df['Confidence'].round(1).astype(str) + '%' ) fig.update_layout( xaxis_title='Confidence (%)', yaxis_title='Waste Class', height=400, showlegend=False, plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)', font=dict(size=12) ) fig.update_traces(textposition='outside') return fig def create_donut_chart(confidence, class_name): """Create donut chart for main prediction""" fig = go.Figure(data=[go.Pie( values=[confidence, 100-confidence], labels=[class_name, 'Other'], hole=.7, marker_colors=['#4CAF50', '#E0E0E0'], textinfo='none' )]) fig.update_layout( annotations=[dict(text=f'{confidence:.1f}%', x=0.5, y=0.5, font_size=20, showarrow=False)], height=200, showlegend=False, margin=dict(t=0, b=0, l=0, r=0) ) return fig # ==================== PAGE 1: HOME & CLASSIFICATION ==================== if page == "🏠 Home & Classification": # Create two columns for layout col1, col2 = st.columns([1, 1]) with col1: st.markdown('
', unsafe_allow_html=True) st.markdown("### 📤 Upload Waste Image") # File uploader with camera option uploaded_file = st.file_uploader( "Choose an image...", type=["jpg", "jpeg", "png"] ) if uploaded_file is not None: image = Image.open(uploaded_file).convert("RGB") st.success("✅ Image uploaded successfully!") else: image = None st.info("👆 Please upload an image to begin") st.markdown('
', unsafe_allow_html=True) # Display uploaded image if image is not None: st.markdown('
', unsafe_allow_html=True) st.markdown("### 🖼️ Preview") # Create columns for image display img_col1, img_col2, img_col3 = st.columns([1, 2, 1]) with img_col2: st.image(image, caption="Uploaded Image", use_column_width=True) # Classify button if st.button("🔍 Classify Waste", use_container_width=True): with st.spinner("🔄 Analyzing image..."): time.sleep(1) # Simulate processing # Make prediction predictions = predict_image(model, image) if predictions is not None: # Store predictions in session state st.session_state['predictions'] = predictions st.session_state['image'] = image st.session_state['classified'] = True st.success("✅ Classification complete!") st.rerun() else: st.error("❌ Classification failed. Please try again.") st.markdown('
', unsafe_allow_html=True) with col2: # Display results if classified if 'classified' in st.session_state and st.session_state['classified']: predictions = st.session_state['predictions'] image = st.session_state['image'] # Main prediction pred_class_idx = np.argmax(predictions) pred_class = class_labels[pred_class_idx] confidence = predictions[pred_class_idx] * 100 # Get top 3 predictions top_3 = get_top_predictions(predictions, class_labels) st.markdown('
', unsafe_allow_html=True) st.markdown("### 🎯 Classification Results") # Main result with styling result_col1, result_col2 = st.columns([1, 1]) with result_col1: # Donut chart for main prediction fig_donut = create_donut_chart(confidence, pred_class) st.plotly_chart(fig_donut, use_container_width=True) with result_col2: # Main prediction details st.markdown(f"### **Predicted Class:**") class_color = class_colors.get(pred_class, '#E0E0E0') st.markdown(f"
" f"

{recycling_info[pred_class]['icon']} {pred_class.upper()}

" f"

Confidence: {confidence:.2f}%

" f"
", unsafe_allow_html=True) st.markdown("---") # Top 3 predictions st.markdown("### 📊 Top 3 Predictions") for i, (class_name, conf) in enumerate(top_3): st.markdown(f"""
{i+1}. {recycling_info[class_name]['icon']} {class_name.capitalize()}
{conf:.1f}%
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) # Recycling Information st.markdown('
', unsafe_allow_html=True) st.markdown(f"### {recycling_info[pred_class]['icon']} Recycling Information") info = recycling_info[pred_class] # Info boxes col_a, col_b, col_c = st.columns(3) with col_a: st.markdown(f"""
♻️ Recyclability
{info['recyclable']}
""", unsafe_allow_html=True) with col_b: st.markdown(f"""
🗑️ Bin Color
{info['bin_color']}
""", unsafe_allow_html=True) with col_c: st.markdown(f"""
🔧 Processing
{info['processing'][:50]}...
""", unsafe_allow_html=True) # Facts and tips st.markdown("---") st.markdown(f"**📌 Did you know?** {info['facts']}") st.markdown(f"**💡 Tip:** {info['tips']}") st.markdown('
', unsafe_allow_html=True) # Confidence chart st.markdown('
', unsafe_allow_html=True) fig = create_confidence_chart(predictions, class_labels) st.plotly_chart(fig, use_container_width=True) st.markdown('
', unsafe_allow_html=True) # Environmental impact st.markdown('
', unsafe_allow_html=True) st.markdown("### 🌍 Environmental Impact") impact_data = { 'cardboard': {'trees': 0.5, 'co2': 2.0, 'water': 100}, 'glass': {'trees': 0, 'co2': 3.5, 'water': 50}, 'metal': {'trees': 0, 'co2': 4.0, 'water': 75}, 'paper': {'trees': 1.0, 'co2': 2.5, 'water': 150}, 'plastic': {'trees': 0, 'co2': 1.5, 'water': 25}, 'trash': {'trees': 0, 'co2': 0.5, 'water': 10} } impact = impact_data[pred_class] col_imp1, col_imp2, col_imp3 = st.columns(3) with col_imp1: st.metric("Trees Saved", f"{impact['trees']} per kg" if impact['trees'] > 0 else "N/A") with col_imp2: st.metric("CO₂ Reduced", f"{impact['co2']} kg per kg") with col_imp3: st.metric("Water Saved", f"{impact['water']} L per kg") st.markdown('
', unsafe_allow_html=True) # Download report st.markdown('
', unsafe_allow_html=True) st.markdown("### 📥 Download Analysis Report") report_content = f""" RECYCLEVISION - WASTE CLASSIFICATION REPORT ============================================ ANALYSIS DATE: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} CLASSIFICATION RESULTS: - Primary Class: {pred_class.upper()} - Confidence: {confidence:.2f}% TOP 3 PREDICTIONS: 1. {top_3[0][0].upper()}: {top_3[0][1]:.2f}% 2. {top_3[1][0].upper()}: {top_3[1][1]:.2f}% 3. {top_3[2][0].upper()}: {top_3[2][1]:.2f}% RECYCLING INFORMATION: - Recyclability: {info['recyclable']} - Bin Color: {info['bin_color']} - Processing: {info['processing']} ENVIRONMENTAL IMPACT: - CO₂ Reduction: {impact['co2']} kg per kg - Water Saved: {impact['water']} L per kg - Trees Saved: {impact['trees']} per kg EDUCATIONAL TIP: {info['tips']} INTERESTING FACT: {info['facts']} -- Generated by RecycleVision AI System -- """ st.download_button( label="📄 Download Report (TXT)", data=report_content, file_name=f"recyclevision_report_{pred_class}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt", mime="text/plain", use_container_width=True ) st.markdown('
', unsafe_allow_html=True) else: # Welcome message when no image classified st.markdown('
', unsafe_allow_html=True) st.markdown("### 👋 Welcome to RecycleVision!") st.markdown(""" **Get started by:** 1. 📤 Uploading an image of your waste item 2. 📸 Taking a photo using your camera 3. 🔍 Clicking "Classify Waste" button **Supported waste types:** - 📦 Cardboard - 🥃 Glass - 🔩 Metal - 📄 Paper - 🧴 Plastic - 🗑️ Trash """) st.markdown('
', unsafe_allow_html=True) # Sample classifications st.markdown('
', unsafe_allow_html=True) st.markdown("### 🎯 Sample Classifications") sample_col1, sample_col2, sample_col3 = st.columns(3) with sample_col1: st.markdown("""

📦

Cardboard

98% confidence
""", unsafe_allow_html=True) with sample_col2: st.markdown("""

🥃

Glass

95% confidence
""", unsafe_allow_html=True) with sample_col3: st.markdown("""

🧴

Plastic

92% confidence
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) # Quick stats st.markdown('
', unsafe_allow_html=True) st.markdown("### 📊 Quick Stats") stat_col1, stat_col2, stat_col3, stat_col4 = st.columns(4) with stat_col1: st.metric("Model Accuracy", "84%", "+2.5%") with stat_col2: st.metric("Classes", "6", "") with stat_col3: st.metric("Training Images", "2,027", "") with stat_col4: st.metric("Inference Time", "<1s", "Fast") st.markdown('
', unsafe_allow_html=True) # ==================== PAGE 2: MODEL PERFORMANCE ==================== elif page == "📈 Model Performance": st.markdown('
', unsafe_allow_html=True) st.markdown("### 📈 Model Performance Metrics") # Model metrics col1, col2, col3, col4 = st.columns(4) with col1: st.metric("Accuracy", "83.2%", "↑ 2.1%") with col2: st.metric("Precision", "84.0%", "↑ 1.8%") with col3: st.metric("Recall", "83.0%", "↑ 1.5%") with col4: st.metric("F1-Score", "83.0%", "↑ 1.6%") st.markdown('
', unsafe_allow_html=True) # Confusion Matrix st.markdown('
', unsafe_allow_html=True) st.markdown("### 🔍 Confusion Matrix") # Confusion matrix data from validation cm_data = np.array([ [63, 0, 2, 9, 0, 7], [0, 86, 9, 0, 4, 1], [0, 7, 70, 1, 4, 1], [2, 1, 2, 111, 1, 2], [1, 2, 4, 4, 68, 17], [0, 2, 1, 2, 2, 20] ]) fig_cm = px.imshow( cm_data, x=class_labels, y=class_labels, text_auto=True, aspect="auto", color_continuous_scale='Blues', title="Confusion Matrix - Validation Set" ) fig_cm.update_layout( xaxis_title="Predicted Label", yaxis_title="True Label", height=500 ) st.plotly_chart(fig_cm, use_container_width=True) st.markdown('
', unsafe_allow_html=True) # Class-wise Performance st.markdown('
', unsafe_allow_html=True) st.markdown("### 📊 Class-wise Performance") performance_data = pd.DataFrame({ 'Class': class_labels, 'Precision': [0.97, 0.80, 0.80, 0.87, 0.87, 0.50], 'Recall': [0.78, 0.86, 0.85, 0.93, 0.71, 0.74], 'F1-Score': [0.86, 0.83, 0.82, 0.90, 0.78, 0.60], 'Support': [81, 100, 82, 119, 96, 27] }) fig_perf = px.bar( performance_data.melt(id_vars=['Class'], value_vars=['Precision', 'Recall', 'F1-Score']), x='Class', y='value', color='variable', barmode='group', title="Class-wise Performance Metrics", labels={'value': 'Score', 'variable': 'Metric'} ) st.plotly_chart(fig_perf, use_container_width=True) st.markdown('
', unsafe_allow_html=True) # Training History st.markdown('
', unsafe_allow_html=True) st.markdown("### 📈 Training History") # Simulated training history epochs = list(range(1, 13)) train_acc = [0.47, 0.76, 0.78, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.87, 0.88] val_acc = [0.76, 0.77, 0.80, 0.80, 0.82, 0.84, 0.82, 0.83, 0.83, 0.84, 0.83, 0.84] train_loss = [1.86, 0.72, 0.70, 0.56, 0.55, 0.47, 0.46, 0.45, 0.38, 0.35, 0.36, 0.33] val_loss = [0.70, 0.62, 0.53, 0.51, 0.51, 0.48, 0.50, 0.56, 0.55, 0.51, 0.49, 0.50] history_df = pd.DataFrame({ 'Epoch': epochs, 'Training Accuracy': train_acc, 'Validation Accuracy': val_acc, 'Training Loss': train_loss, 'Validation Loss': val_loss }) fig_history = make_subplots( rows=1, cols=2, subplot_titles=('Model Accuracy', 'Model Loss') ) fig_history.add_trace( go.Scatter(x=epochs, y=train_acc, mode='lines+markers', name='Training Accuracy', line=dict(color='#4CAF50')), row=1, col=1 ) fig_history.add_trace( go.Scatter(x=epochs, y=val_acc, mode='lines+markers', name='Validation Accuracy', line=dict(color='#2196F3')), row=1, col=1 ) fig_history.add_trace( go.Scatter(x=epochs, y=train_loss, mode='lines+markers', name='Training Loss', line=dict(color='#FF5722')), row=1, col=2 ) fig_history.add_trace( go.Scatter(x=epochs, y=val_loss, mode='lines+markers', name='Validation Loss', line=dict(color='#9C27B0')), row=1, col=2 ) fig_history.update_layout(height=400, showlegend=True) fig_history.update_xaxes(title_text="Epoch", row=1, col=1) fig_history.update_xaxes(title_text="Epoch", row=1, col=2) fig_history.update_yaxes(title_text="Accuracy", row=1, col=1) fig_history.update_yaxes(title_text="Loss", row=1, col=2) st.plotly_chart(fig_history, use_container_width=True) st.markdown('
', unsafe_allow_html=True) # ==================== PAGE 3: ABOUT & INFO ==================== elif page == "ℹ️ About & Info": st.markdown('
', unsafe_allow_html=True) st.markdown("### ℹ️ About RecycleVision") st.markdown(""" **RecycleVision** is an advanced deep learning system designed to automatically classify waste materials into six categories, helping streamline recycling processes and promoting environmental sustainability. #### 🎯 Project Objectives - Automate waste sorting for recycling facilities - Reduce manual sorting time and labor costs - Educate people about proper waste segregation - Provide environmental impact insights #### 🤖 Technology Stack - **Deep Learning Framework:** TensorFlow 2.15 / Keras - **Model Architecture:** EfficientNetB0 (Transfer Learning) - **Frontend:** Streamlit 1.28 - **Data Processing:** NumPy, Pandas, OpenCV - **Visualization:** Plotly, Matplotlib, Seaborn #### 📊 Dataset - **Source:** TrashNet / Garbage Classification Dataset - **Total Images:** 2,532 - **Classes:** 6 waste categories - **Split:** 80% Training (2,027) | 20% Validation (505) #### 🏆 Model Performance - **Accuracy:** 83.2% - **Precision:** 84.0% - **Recall:** 83.0% - **F1-Score:** 83.0% """) st.markdown('
', unsafe_allow_html=True) # Class Information st.markdown('
', unsafe_allow_html=True) st.markdown("### 🗑️ Waste Classes Information") for class_name in class_labels: info = recycling_info[class_name] with st.expander(f"{info['icon']} {class_name.capitalize()} - {info['type']}"): col_a, col_b = st.columns(2) with col_a: st.markdown(f"**♻️ Recyclable:** {info['recyclable']}") st.markdown(f"**🗑️ Bin Color:** {info['bin_color']}") st.markdown(f"**🔧 Processing:** {info['processing']}") with col_b: st.markdown(f"**📌 Fact:** {info['facts']}") st.markdown(f"**💡 Tip:** {info['tips']}") st.markdown('
', unsafe_allow_html=True) # Environmental Impact st.markdown('
', unsafe_allow_html=True) st.markdown("### 🌍 Environmental Impact") impact_data = { 'Category': ['CO₂ Reduction (kg/kg)', 'Energy Savings (%)', 'Water Saved (L/kg)', 'Trees Saved (per kg)'], 'Cardboard': [2.0, 75, 100, 0.5], 'Glass': [3.5, 60, 50, 0], 'Metal': [4.0, 95, 75, 0], 'Paper': [2.5, 70, 150, 1.0], 'Plastic': [1.5, 80, 25, 0], 'Trash': [0.5, 0, 10, 0] } impact_df = pd.DataFrame(impact_data) st.dataframe(impact_df.style.highlight_max(color='lightgreen'), use_container_width=True) st.markdown('
', unsafe_allow_html=True) # Team Info st.markdown('
', unsafe_allow_html=True) st.markdown("### 👥 Project Team") col1, col2, col3 = st.columns(3) with col1: st.markdown("""

🧑‍💻 Data Scientist

Model Development & Training

""", unsafe_allow_html=True) with col2: st.markdown("""

🎨 UI/UX Designer

Streamlit App Development

""", unsafe_allow_html=True) with col3: st.markdown("""

🔬 Domain Expert

Waste Management Specialist

""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) # ==================== PAGE 4: SETTINGS ==================== elif page == "⚙️ Settings": st.markdown('
', unsafe_allow_html=True) st.markdown("### ⚙️ Application Settings") # Model settings st.markdown("#### 🤖 Model Configuration") conf_threshold = st.slider( "Confidence Threshold (%)", min_value=0, max_value=100, value=50, help="Minimum confidence for classification" ) top_k = st.slider( "Top-K Predictions", min_value=1, max_value=6, value=3, help="Number of top predictions to show" ) # Display settings st.markdown("#### 🎨 Display Settings") theme = st.selectbox( "Theme", ["Light", "Dark", "System Default"], help="Choose application theme" ) chart_style = st.selectbox( "Chart Style", ["Modern", "Classic", "Minimalist"], help="Choose chart visualization style" ) # Notification settings st.markdown("#### 🔔 Notifications") show_tips = st.checkbox("Show recycling tips", value=True) show_facts = st.checkbox("Show environmental facts", value=True) show_impact = st.checkbox("Show impact metrics", value=True) # Advanced settings st.markdown("#### 🔧 Advanced Settings") batch_size = st.number_input("Batch Size", min_value=1, max_value=32, value=1) use_gpu = st.checkbox("Use GPU if available", value=True) # Save settings button if st.button("💾 Save Settings", use_container_width=True): st.success("✅ Settings saved successfully!") st.markdown('
', unsafe_allow_html=True) # About the model st.markdown('
', unsafe_allow_html=True) st.markdown("### 📊 Model Details") st.markdown(""" **Model Architecture:** EfficientNetB0 - **Input Shape:** 224 × 224 × 3 - **Total Parameters:** 4,384,169 - **Trainable Parameters:** 332,038 - **Non-trainable Parameters:** 4,052,131 **Training Configuration:** - **Optimizer:** Adam (lr=0.001) - **Loss Function:** Categorical Crossentropy - **Batch Size:** 32 - **Epochs:** 25 (with early stopping) - **Class Weights:** Balanced **Data Augmentation:** - Rotation Range: 25° - Zoom Range: 20% - Width/Height Shift: 20% - Horizontal Flip: Yes """) st.markdown('
', unsafe_allow_html=True) # Footer st.markdown(""" """, unsafe_allow_html=True) # Sidebar footer st.sidebar.markdown("---") st.sidebar.markdown("""

♻️ RecycleVision v2.0

AI-Powered Waste Classification

""", unsafe_allow_html=True) # Initialize session state if 'classified' not in st.session_state: st.session_state['classified'] = False