| | import os |
| |
|
| | import streamlit as st |
| | from PIL import Image |
| |
|
| | from predictor import predict_image |
| |
|
| | APP_DIR = os.path.dirname(os.path.abspath(__file__)) |
| | ASSETS_DIR = os.path.join(APP_DIR, "assets") |
| |
|
| | |
| | st.set_page_config(page_title="Image Classifier App", page_icon="π€", layout="centered") |
| | st.html(""" |
| | <style> |
| | .stMainBlockContainer { |
| | max-width: 70rem; |
| | } |
| | </style> |
| | """) |
| |
|
| | |
| | if "uploaded_image" not in st.session_state: |
| | st.session_state["uploaded_image"] = None |
| | if "example_selected" not in st.session_state: |
| | st.session_state["example_selected"] = False |
| | if "prediction_result" not in st.session_state: |
| | st.session_state["prediction_result"] = None |
| |
|
| | |
| | with st.container(): |
| | st.title( |
| | body="πΌοΈ Image Classifier with CNN", |
| | help="An interactive application to classify images into over 1000 categories.", |
| | ) |
| | st.html("<br>") |
| |
|
| | |
| | tab_app, tab_description = st.tabs(["**App**", "**Description**"]) |
| |
|
| | |
| | with tab_app: |
| | |
| | col_upload, col_results = st.columns(2, gap="large") |
| |
|
| | |
| | with col_upload: |
| | st.header("Upload an Image", divider=True) |
| |
|
| | |
| | uploaded_file = st.file_uploader( |
| | label="Drag and drop an image here or click to browse", |
| | type=["jpg", "jpeg", "png", "webp", "avif"], |
| | help="Maximum file size is 200MB", |
| | key="image_uploader", |
| | ) |
| |
|
| | st.html("<br>") |
| | st.subheader("Or Try an Example", divider=True) |
| |
|
| | |
| | selected_example = st.segmented_control( |
| | label="Categories", |
| | options=["Animal", "Vehicle", "Object", "Building"], |
| | default=None, |
| | help="Select one of the pre-loaded examples", |
| | ) |
| |
|
| | st.html("<br>") |
| |
|
| | |
| | classify_button = st.button( |
| | label="Classify Image", |
| | key="classify_btn", |
| | type="primary", |
| | icon="β¨", |
| | ) |
| |
|
| | |
| | |
| | if uploaded_file or selected_example: |
| | st.session_state.prediction_result = None |
| |
|
| | image_to_process = None |
| |
|
| | if uploaded_file: |
| | image_to_process = Image.open(uploaded_file) |
| |
|
| | elif selected_example: |
| | try: |
| | img_path = os.path.join( |
| | APP_DIR, "assets", f"{selected_example.lower()}.jpg" |
| | ) |
| | image_to_process = Image.open(img_path) |
| | except FileNotFoundError: |
| | st.error( |
| | f"Error: The example image '{selected_example.lower()}.jpg' was not found." |
| | ) |
| | st.stop() |
| |
|
| | |
| | with col_results: |
| | st.header("Results", divider=True) |
| |
|
| | |
| | if not image_to_process and not st.session_state.prediction_result: |
| | st.info("Choose an image or an example to get a prediction.") |
| |
|
| | |
| | if image_to_process: |
| | st.image(image_to_process, caption="Image to be classified") |
| |
|
| | |
| | if classify_button and image_to_process: |
| | with st.spinner(text="π§ Analyzing image..."): |
| | try: |
| | from predictor import predict_image |
| |
|
| | predicted_label, predicted_score = predict_image( |
| | image_to_process |
| | ) |
| | st.session_state.prediction_result = { |
| | "label": predicted_label.replace("_", " ").title(), |
| | "score": predicted_score, |
| | } |
| | except Exception as e: |
| | st.error(f"An error occurred during prediction: {e}") |
| |
|
| | |
| | if st.session_state.prediction_result: |
| | st.metric( |
| | label="Prediction", |
| | value=st.session_state.prediction_result["label"], |
| | delta=f"{st.session_state.prediction_result['score'] * 100:.2f}%", |
| | help="The predicted category and its confidence score.", |
| | delta_color="normal", |
| | ) |
| | st.balloons() |
| |
|
| | elif image_to_process: |
| | st.info("Click 'Classify Image' to see the prediction.") |
| |
|
| |
|
| | |
| | with tab_description: |
| | st.header("About This Project", divider=True) |
| | st.markdown( |
| | """ |
| | This project showcases a Convolutional Neural Network (CNN) model that automatically |
| | classifies images into over 1000 different categories. |
| | |
| | ### Original Architecture |
| | The original project was built as a multi-service architecture, featuring: |
| | * **Streamlit:** For the web user interface. |
| | * **FastAPI:** As a RESTful API to handle image processing and model serving. |
| | * **Redis:** A message broker for communication between the services. |
| | |
| | ### Portfolio Adaptation |
| | For a live and cost-effective demo, this application has been adapted into a single-service |
| | solution. The core logic of the FastAPI backend has been integrated directly into |
| | the Streamlit app. This demonstrates the ability to adapt a solution for |
| | specific deployment and resource constraints. |
| | |
| | ### Technologies Used |
| | * **Streamlit:** For the interactive web interface. |
| | * **TensorFlow:** For loading and running the pre-trained CNN model. |
| | * **Pre-trained Model:** ResNet50 with weights trained on the ImageNet dataset. |
| | """ |
| | ) |
| |
|