File size: 6,608 Bytes
aee8033 29f6ccc 3f0ccc8 29f6ccc af98bbd aee8033 3f0ccc8 aee8033 3f0ccc8 aee8033 3f0ccc8 aee8033 3f0ccc8 aee8033 3f0ccc8 aee8033 3f0ccc8 aee8033 3f0ccc8 aee8033 3f0ccc8 aee8033 3f0ccc8 aee8033 3f0ccc8 aee8033 3f0ccc8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | 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")
# π PAGE SETUP
st.set_page_config(page_title="Image Classifier App", page_icon="π€", layout="centered")
st.html("""
<style>
.stMainBlockContainer {
max-width: 70rem;
}
</style>
""")
# π INITIALIZE SESSION STATE
# We initialize session state variables to manage app state
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
# π MAIN APP LAYOUT
with st.container():
st.title(
body="πΌοΈ Image Classifier with CNN",
help="An interactive application to classify images into over 1000 categories.",
)
st.html("<br>")
# Use tabs for different sections of the app
tab_app, tab_description = st.tabs(["**App**", "**Description**"])
# π APP TAB
with tab_app:
# Create a two-column layout for the app interface
col_upload, col_results = st.columns(2, gap="large")
# π IMAGE UPLOAD & EXAMPLE SELECTION
with col_upload:
st.header("Upload an Image", divider=True)
# File uploader widget
uploaded_file = st.file_uploader(
label="Drag and drop an image here or click to browse",
type=["jpg", "jpeg", "png"],
help="Maximum file size is 200MB",
key="image_uploader",
)
# Update state when a new file is uploaded
if uploaded_file is not st.session_state.uploaded_image:
st.session_state.uploaded_image = uploaded_file
st.session_state.example_selected = False
st.session_state.prediction_result = None
st.html("<br>")
st.subheader("Or Try an Example", divider=True)
# Segmented control for selecting example images
selected_example = st.segmented_control(
label="Categories",
options=["Animal", "Vehicle", "Object", "Building"],
default="Animal",
help="Select one of the pre-loaded examples",
)
st.html("<br>")
# --- THE SINGLE CLASSIFY BUTTON ---
classify_button = st.button(
label="Classify Image",
key="classify_btn",
type="primary",
icon="β¨",
)
# π PREDICTION RESULTS
with col_results:
st.header("Results", divider=True)
image_to_process = None
# Logic to handle which image to display
if st.session_state.uploaded_image:
# Get the image from the uploaded file
image_to_process = Image.open(st.session_state.uploaded_image)
elif selected_example:
# Load the selected example image using a robust path
try:
img_path = os.path.join(
ASSETS_DIR, 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()
# Display image and run prediction when button is clicked
if image_to_process:
st.image(image_to_process, caption="Image to be classified")
if classify_button:
# Run the prediction logic
with st.spinner("Analyzing image..."):
try:
# π Prediction function call π
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}")
# Display the prediction result if available
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()
else:
st.info("Click 'Classify Image' to see the prediction.")
else:
st.info("Choose an image to get a prediction.")
# π DESCRIPTION TAB
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.
"""
)
|