"""
đąđļ Cat vs Dog Classifier - Streamlit Web App
================================================
Upload an image and get instant prediction
"""
import streamlit as st
import tensorflow as tf
from tensorflow.keras.preprocessing import image
from tensorflow.keras.models import load_model
import numpy as np
from PIL import Image
import os
import time
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
# PAGE CONFIGURATION
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
st.set_page_config(
page_title="đą Cat vs Dog Classifier",
page_icon="đž",
layout="centered"
)
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
# CUSTOM CSS
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
st.markdown("""
""", unsafe_allow_html=True)
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
# LOAD MODEL (Cached)
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
@st.cache_resource
def load_classifier_model():
"""Load the trained model"""
model_path = 'cat_dog_model.h5'
if not os.path.exists(model_path):
st.error(f"â Model file not found: {model_path}")
st.info("Please train the model first using cat_dog_classifier.py")
return None
try:
model = load_model(model_path)
return model
except Exception as e:
st.error(f"â Error loading model: {e}")
return None
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
# IMAGE PREPROCESSING
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
def preprocess_image(img, target_size=(150, 150)):
"""Preprocess image for model prediction"""
# Resize image
img = img.resize(target_size)
# Convert to array
img_array = image.img_to_array(img)
# Expand dimensions for batch
img_array = np.expand_dims(img_array, axis=0)
# Normalize
img_array = img_array / 255.0
return img_array
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
# PREDICTION FUNCTION
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
def predict_image(model, img):
"""Make prediction on uploaded image"""
# Preprocess
processed_img = preprocess_image(img)
# Predict
prediction = model.predict(processed_img, verbose=0)
# Get confidence
confidence = float(prediction[0][0])
# Determine class
if confidence > 0.5:
predicted_class = "đļ Dog"
dog_conf = confidence * 100
cat_conf = (1 - confidence) * 100
else:
predicted_class = "đą Cat"
cat_conf = (1 - confidence) * 100
dog_conf = confidence * 100
return predicted_class, cat_conf, dog_conf, confidence
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
# MAIN APP
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
def main():
# Title
st.markdown('
đą Cat vs Dog Classifier đļ
',
unsafe_allow_html=True)
# Load model
model = load_classifier_model()
if model is None:
st.warning("â ī¸ Please train the model first or check the model file path.")
return
st.success("â
Model loaded successfully!")
# Sidebar
with st.sidebar:
st.header("âšī¸ About")
st.markdown("""
This app uses a **CNN (Convolutional Neural Network)**
trained on cat and dog images to classify your uploaded photos.
**How to use:**
1. Upload an image of a cat or dog
2. Click "Predict" button
3. See the result with confidence score
**Supported formats:** JPG, JPEG, PNG
**Model:** Custom CNN
**Accuracy:** ~85% (may vary)
""")
st.markdown("---")
# Model info
st.subheader("đ Model Info")
st.markdown(f"""
- **Type:** Convolutional Neural Network
- **Input size:** 150Ã150 pixels
- **Layers:** 3 Conv + 3 Pool + 2 Dense
- **Parameters:** ~3.5M
""")
st.markdown("---")
# Example images
st.subheader("đŧī¸ Sample Predictions")
col1, col2 = st.columns(2)
with col1:
st.markdown("**Cat Example**")
st.markdown("Confidence threshold: > 0.5 = Dog")
with col2:
st.markdown("**Dog Example**")
st.markdown("Confidence threshold: < 0.5 = Cat")
# Main content
col1, col2 = st.columns([1, 1])
with col1:
st.markdown("### đ¤ Upload Image")
# File uploader
uploaded_file = st.file_uploader(
"Choose an image of a cat or dog...",
type=['jpg', 'jpeg', 'png'],
help="Upload a clear image for best results"
)
with col2:
st.markdown("### đ¸ Or Use Camera")
camera_image = st.camera_input("Take a photo")
# Process uploaded image
image_to_process = None
if uploaded_file is not None:
image_to_process = Image.open(uploaded_file)
source = "uploaded"
elif camera_image is not None:
image_to_process = Image.open(camera_image)
source = "camera"
if image_to_process is not None:
st.markdown("---")
# Display image and prediction
col1, col2 = st.columns([1, 1])
with col1:
st.markdown("### đŧī¸ Your Image")
st.image(image_to_process, use_column_width=True)
# Image details
st.markdown(f"""
Image Details:
đ Size: {image_to_process.size[0]}Ã{image_to_process.size[1]} px
đ¨ Mode: {image_to_process.mode}
đ Source: {source.capitalize()}
""", unsafe_allow_html=True)
with col2:
st.markdown("### đ¤ Prediction")
# Predict button
if st.button("đ Predict", type="primary", use_container_width=True):
with st.spinner("đ§ Analyzing image..."):
# Add small delay for effect
time.sleep(0.5)
# Make prediction
predicted_class, cat_conf, dog_conf, confidence = predict_image(
model, image_to_process
)
# Display result
if "Cat" in predicted_class:
result_class = "cat-result"
emoji = "đą"
else:
result_class = "dog-result"
emoji = "đļ"
st.markdown(f"""
{emoji} {predicted_class}
Confidence: {max(cat_conf, dog_conf):.1f}%
""", unsafe_allow_html=True)
# Confidence bars
st.markdown("#### đ Confidence Breakdown")
col_a, col_b = st.columns(2)
with col_a:
st.markdown("**Cat Probability**")
st.progress(int(cat_conf) / 100)
st.markdown(f"{cat_conf:.1f}%")
with col_b:
st.markdown("**Dog Probability**")
st.progress(int(dog_conf) / 100)
st.markdown(f"{dog_conf:.1f}%")
# Raw prediction value
with st.expander("đŦ Technical Details"):
st.markdown(f"""
- **Raw prediction value:** {confidence:.6f}
- **Threshold:** 0.5
- **Prediction logic:** Value > 0.5 = Dog, < 0.5 = Cat
- **Model output:** Sigmoid activation
""")
# Footer
st.markdown("---")
st.markdown(
""
"đž Cat vs Dog Classifier | Built with TensorFlow & Streamlit | "
"Upload an image to get started!"
"
",
unsafe_allow_html=True
)
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
# MULTIPLE IMAGES BATCH PREDICTION (Optional)
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
def batch_prediction_section(model):
"""Optional section for batch predictions"""
st.markdown("---")
st.markdown("### đ Batch Prediction (Multiple Images)")
uploaded_files = st.file_uploader(
"Upload multiple images",
type=['jpg', 'jpeg', 'png'],
accept_multiple_files=True,
key="batch_upload"
)
if uploaded_files:
st.markdown(f"**{len(uploaded_files)} images uploaded**")
if st.button("đ Predict All", type="secondary"):
results = []
progress_bar = st.progress(0)
for i, file in enumerate(uploaded_files):
img = Image.open(file)
predicted_class, cat_conf, dog_conf, _ = predict_image(model, img)
results.append({
'filename': file.name,
'prediction': predicted_class,
'cat_confidence': f"{cat_conf:.1f}%",
'dog_confidence': f"{dog_conf:.1f}%"
})
# Update progress
progress_bar.progress((i + 1) / len(uploaded_files))
# Display results table
import pandas as pd
df = pd.DataFrame(results)
st.dataframe(df, use_container_width=True)
# Summary
cats = sum(1 for r in results if 'Cat' in r['prediction'])
dogs = len(results) - cats
col1, col2 = st.columns(2)
with col1:
st.metric("đą Cats", cats)
with col2:
st.metric("đļ Dogs", dogs)
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
# RUN APP
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
if __name__ == "__main__":
main()