File size: 11,435 Bytes
82dccf5 | 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 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | """
dl_module.py - Deep Learning Module
Image classification using pretrained MobileNetV2/ResNet50 + OpenCV object detection
"""
import streamlit as st
import numpy as np
import cv2
import io
import warnings
warnings.filterwarnings("ignore")
from PIL import Image
# βββ Lazy imports ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def _load_tf_model(model_name):
"""Load a Keras pretrained model."""
import tensorflow as tf
from tensorflow.keras.applications import MobileNetV2, ResNet50, VGG16
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input as mn_pre, decode_predictions as mn_dec
from tensorflow.keras.applications.resnet50 import preprocess_input as rn_pre, decode_predictions as rn_dec
from tensorflow.keras.applications.vgg16 import preprocess_input as vg_pre, decode_predictions as vg_dec
models_map = {
"MobileNetV2": (MobileNetV2, mn_pre, mn_dec, (224, 224)),
"ResNet50": (ResNet50, rn_pre, rn_dec, (224, 224)),
"VGG16": (VGG16, vg_pre, vg_dec, (224, 224)),
}
ModelClass, preprocess, decode, size = models_map[model_name]
model = ModelClass(weights="imagenet")
return model, preprocess, decode, size
def _classify_image_tf(image_pil, model_name):
"""Classify an image using TF/Keras pretrained model."""
import numpy as np
from tensorflow.keras.preprocessing.image import img_to_array
model, preprocess, decode, (h, w) = _load_tf_model(model_name)
img = image_pil.convert("RGB").resize((w, h))
arr = img_to_array(img)
arr = np.expand_dims(arr, axis=0)
arr = preprocess(arr)
preds = model.predict(arr, verbose=0)
top = decode(preds, top=5)[0]
results = [{"Rank": i+1, "Label": label.replace("_", " ").title(),
"Confidence": f"{prob*100:.2f}%", "Score": round(prob, 4)}
for i, (_, label, prob) in enumerate(top)]
return results
def _classify_image_torch(image_pil, model_name):
"""Classify an image using PyTorch pretrained model."""
import torch
import torchvision.transforms as T
import torchvision.models as models_tv
import json
import urllib.request
# Load imagenet class labels
LABELS_URL = "https://raw.githubusercontent.com/anishathalye/imagenet-simple-labels/master/imagenet-simple-labels.json"
try:
with urllib.request.urlopen(LABELS_URL, timeout=5) as r:
class_labels = json.load(r)
except Exception:
class_labels = [str(i) for i in range(1000)]
torch_models = {
"MobileNetV2": models_tv.mobilenet_v2,
"ResNet50": models_tv.resnet50,
}
model_fn = torch_models.get(model_name, models_tv.mobilenet_v2)
model = model_fn(pretrained=True)
model.eval()
transform = T.Compose([
T.Resize(256),
T.CenterCrop(224),
T.ToTensor(),
T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
img = image_pil.convert("RGB")
tensor = transform(img).unsqueeze(0)
with torch.no_grad():
output = model(tensor)
probs = torch.nn.functional.softmax(output[0], dim=0)
top_probs, top_idxs = torch.topk(probs, 5)
results = []
for i, (prob, idx) in enumerate(zip(top_probs, top_idxs)):
label = class_labels[idx.item()] if idx.item() < len(class_labels) else str(idx.item())
results.append({
"Rank": i+1,
"Label": label.replace("_", " ").title(),
"Confidence": f"{prob.item()*100:.2f}%",
"Score": round(prob.item(), 4),
})
return results
def detect_edges_opencv(image_pil):
"""Apply Canny edge detection using OpenCV."""
img_array = np.array(image_pil.convert("RGB"))
gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.Canny(blurred, threshold1=50, threshold2=150)
return edges
def detect_faces_opencv(image_pil):
"""Detect faces using Haar Cascade classifier."""
img_array = np.array(image_pil.convert("RGB"))
img_bgr = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR)
gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
cascade_path = cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
face_cascade = cv2.CascadeClassifier(cascade_path)
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
result_img = img_array.copy()
for (x, y, w, h) in faces:
cv2.rectangle(result_img, (x, y), (x+w, y+h), (0, 200, 255), 2)
cv2.putText(result_img, "Face", (x, y-8), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 200, 255), 2)
return result_img, len(faces)
def apply_image_filters(image_pil):
"""Apply various OpenCV image processing filters and return dict of results."""
img = np.array(image_pil.convert("RGB"))
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
blurred = cv2.GaussianBlur(img, (15, 15), 0)
sharpened = cv2.addWeighted(img, 1.5, blurred, -0.5, 0)
thresh = cv2.adaptiveThreshold(
gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2
)
contours_img = img.copy()
contours, _ = cv2.findContours(
cv2.Canny(gray, 50, 150), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
cv2.drawContours(contours_img, contours, -1, (0, 255, 120), 1)
return {
"Grayscale": gray,
"Blurred": blurred,
"Sharpened": sharpened,
"Threshold": thresh,
"Contours": contours_img,
}
# βββ Streamlit UI βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def render_dl_module():
st.header("π§ Deep Learning Module")
st.markdown("Upload an image to classify it with pretrained CNNs or run OpenCV computer vision pipelines.")
uploaded = st.file_uploader("Upload Image (JPG/PNG)", type=["jpg", "jpeg", "png"], key="dl_upload")
if uploaded is None:
st.info("π Upload an image (JPG or PNG) to begin. Try uploading a photo of an animal, vehicle, or everyday object.")
return
image_pil = Image.open(uploaded)
st.image(image_pil, caption="Uploaded Image", use_column_width=True)
tabs = st.tabs(["π·οΈ Image Classification", "ποΈ OpenCV Analysis", "π¨ Image Filters"])
# ββ Tab 1: Classification βββββββββββββββββββββββββββββββββββββββββββββββββ
with tabs[0]:
st.subheader("Image Classification (ImageNet)")
backend = st.radio("Choose Backend", ["TensorFlow/Keras", "PyTorch"], horizontal=True)
if backend == "TensorFlow/Keras":
model_choice = st.selectbox("Model", ["MobileNetV2", "ResNet50", "VGG16"])
else:
model_choice = st.selectbox("Model", ["MobileNetV2", "ResNet50"])
if st.button("π Classify Image", type="primary"):
with st.spinner(f"Running {model_choice} inference..."):
try:
if backend == "TensorFlow/Keras":
results = _classify_image_tf(image_pil, model_choice)
else:
results = _classify_image_torch(image_pil, model_choice)
import pandas as pd
import matplotlib.pyplot as plt
st.success(f"β
Top prediction: **{results[0]['Label']}** ({results[0]['Confidence']})")
st.subheader("Top 5 Predictions")
df_preds = pd.DataFrame(results)
st.dataframe(df_preds, use_container_width=True)
# Bar chart of confidences
fig, ax = plt.subplots(figsize=(8, 4))
labels = [r["Label"][:30] for r in results]
scores = [r["Score"] for r in results]
colors = ["#0ea5e9" if i == 0 else "#334155" for i in range(len(scores))]
bars = ax.barh(labels[::-1], scores[::-1], color=colors[::-1])
ax.set_xlabel("Confidence Score")
ax.set_title("Top 5 Predictions")
ax.set_xlim(0, max(scores) * 1.2)
for bar, score in zip(bars, scores[::-1]):
ax.text(bar.get_width() + 0.005, bar.get_y() + bar.get_height()/2,
f"{score*100:.1f}%", va="center", fontsize=9)
plt.tight_layout()
st.pyplot(fig)
except Exception as e:
st.error(f"Classification failed: {e}")
st.info("Make sure TensorFlow or PyTorch is installed. Run: `pip install tensorflow` or `pip install torch torchvision`")
# ββ Tab 2: OpenCV Analysis ββββββββββββββββββββββββββββββββββββββββββββββββ
with tabs[1]:
st.subheader("OpenCV Computer Vision")
cv_task = st.selectbox("Select Analysis", ["Edge Detection", "Face Detection"])
if st.button("βΆ Run OpenCV Analysis", type="primary"):
with st.spinner("Processing with OpenCV..."):
if cv_task == "Edge Detection":
edges = detect_edges_opencv(image_pil)
col1, col2 = st.columns(2)
with col1:
st.image(image_pil, caption="Original", use_column_width=True)
with col2:
st.image(edges, caption="Canny Edge Detection", use_column_width=True, clamp=True)
st.info(f"Detected approximately **{np.sum(edges > 0):,}** edge pixels.")
elif cv_task == "Face Detection":
result_img, face_count = detect_faces_opencv(image_pil)
col1, col2 = st.columns(2)
with col1:
st.image(image_pil, caption="Original", use_column_width=True)
with col2:
st.image(result_img, caption="Face Detection", use_column_width=True)
if face_count > 0:
st.success(f"β
Detected **{face_count}** face(s).")
else:
st.warning("No faces detected. Try a clear portrait photo.")
# ββ Tab 3: Image Filters ββββββββββββββββββββββββββββββββββββββββββββββββββ
with tabs[2]:
st.subheader("OpenCV Image Processing Filters")
if st.button("π¨ Apply All Filters", type="primary"):
with st.spinner("Applying filters..."):
filters = apply_image_filters(image_pil)
cols = st.columns(3)
for i, (name, img) in enumerate(filters.items()):
with cols[i % 3]:
if len(img.shape) == 2:
st.image(img, caption=name, use_column_width=True, clamp=True)
else:
st.image(img, caption=name, use_column_width=True) |