Upload app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
π Human Activity Recognition β Gradio Demo
|
| 3 |
+
Fine-tuned MobileNetV2 classifying 15 human activities from images.
|
| 4 |
+
Model: Rishi2455/Human-Activity-Recognition
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import os
|
| 8 |
+
import gradio as gr
|
| 9 |
+
import tensorflow as tf
|
| 10 |
+
import numpy as np
|
| 11 |
+
from PIL import Image
|
| 12 |
+
from huggingface_hub import hf_hub_download
|
| 13 |
+
from datasets import load_dataset
|
| 14 |
+
|
| 15 |
+
# ββ Configuration ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 16 |
+
MODEL_REPO = "Rishi2455/Human-Activity-Recognition"
|
| 17 |
+
MODEL_FILE = "mobilenetv2_finetuned.h5"
|
| 18 |
+
IMG_SIZE = (224, 224)
|
| 19 |
+
|
| 20 |
+
CLASS_NAMES = [
|
| 21 |
+
"Calling", "Clapping", "Cycling", "Dancing", "Drinking",
|
| 22 |
+
"Eating", "Fighting", "Hugging", "Laughing", "Listening to Music",
|
| 23 |
+
"Running", "Sitting", "Sleeping", "Texting", "Using Laptop",
|
| 24 |
+
]
|
| 25 |
+
|
| 26 |
+
ACTIVITY_EMOJI = {
|
| 27 |
+
"Calling": "π", "Clapping": "π", "Cycling": "π΄", "Dancing": "π",
|
| 28 |
+
"Drinking": "π₯€", "Eating": "π½οΈ", "Fighting": "π₯", "Hugging": "π€",
|
| 29 |
+
"Laughing": "π", "Listening to Music": "π§", "Running": "π",
|
| 30 |
+
"Sitting": "πͺ", "Sleeping": "π΄", "Texting": "π±", "Using Laptop": "π»",
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
# ββ Download & load model βββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 34 |
+
print("β¬οΈ Downloading model...")
|
| 35 |
+
model_path = hf_hub_download(repo_id=MODEL_REPO, filename=MODEL_FILE)
|
| 36 |
+
print("π§ Loading model...")
|
| 37 |
+
model = tf.keras.models.load_model(model_path, compile=False)
|
| 38 |
+
print("β
Model loaded!")
|
| 39 |
+
|
| 40 |
+
# ββ Prepare example images from dataset βββββββββββββββββββββββββββββββββββββ
|
| 41 |
+
EXAMPLE_DIR = "examples"
|
| 42 |
+
os.makedirs(EXAMPLE_DIR, exist_ok=True)
|
| 43 |
+
|
| 44 |
+
example_paths = []
|
| 45 |
+
try:
|
| 46 |
+
print("π¦ Loading example images from dataset...")
|
| 47 |
+
ds = load_dataset("Bingsu/Human_Action_Recognition", split="test")
|
| 48 |
+
# Pick one example per class (first 8 classes for a clean grid)
|
| 49 |
+
selected_classes = [2, 3, 10, 11, 5, 14, 0, 8] # cycling, dancing, running, sitting, eating, laptop, calling, laughing
|
| 50 |
+
class_names_lower = [
|
| 51 |
+
"calling", "clapping", "cycling", "dancing", "drinking",
|
| 52 |
+
"eating", "fighting", "hugging", "laughing", "listening_to_music",
|
| 53 |
+
"running", "sitting", "sleeping", "texting", "using_laptop",
|
| 54 |
+
]
|
| 55 |
+
seen = set()
|
| 56 |
+
for row in ds:
|
| 57 |
+
label = row["labels"]
|
| 58 |
+
if label in selected_classes and label not in seen:
|
| 59 |
+
img = row["image"]
|
| 60 |
+
fname = f"{EXAMPLE_DIR}/{class_names_lower[label]}.jpg"
|
| 61 |
+
img.save(fname)
|
| 62 |
+
example_paths.append(fname)
|
| 63 |
+
seen.add(label)
|
| 64 |
+
if len(seen) == len(selected_classes):
|
| 65 |
+
break
|
| 66 |
+
print(f"β
Saved {len(example_paths)} example images.")
|
| 67 |
+
except Exception as e:
|
| 68 |
+
print(f"β οΈ Could not load examples: {e}")
|
| 69 |
+
|
| 70 |
+
# ββ Inference ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 71 |
+
def predict(pil_img: Image.Image) -> dict:
|
| 72 |
+
"""Classify a human activity from an image."""
|
| 73 |
+
if pil_img is None:
|
| 74 |
+
return {}
|
| 75 |
+
img = pil_img.convert("RGB").resize(IMG_SIZE)
|
| 76 |
+
arr = np.expand_dims(np.array(img, dtype=np.float32), axis=0)
|
| 77 |
+
arr = tf.keras.applications.mobilenet_v2.preprocess_input(arr)
|
| 78 |
+
preds = model.predict(arr, verbose=0)[0]
|
| 79 |
+
emoji_labels = {
|
| 80 |
+
f"{ACTIVITY_EMOJI.get(c, '')} {c}": float(preds[i])
|
| 81 |
+
for i, c in enumerate(CLASS_NAMES)
|
| 82 |
+
}
|
| 83 |
+
return emoji_labels
|
| 84 |
+
|
| 85 |
+
# ββ Gradio UI ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 86 |
+
DESCRIPTION = """
|
| 87 |
+
Upload a photo of a person performing an activity, and the model will predict which of **15 activities** they are doing.
|
| 88 |
+
|
| 89 |
+
**Supported activities:** Calling Β· Clapping Β· Cycling Β· Dancing Β· Drinking Β· Eating Β· Fighting Β· Hugging Β· Laughing Β· Listening to Music Β· Running Β· Sitting Β· Sleeping Β· Texting Β· Using Laptop
|
| 90 |
+
|
| 91 |
+
**Model:** [MobileNetV2](https://huggingface.co/Rishi2455/Human-Activity-Recognition) fine-tuned on the [Human Action Recognition dataset](https://huggingface.co/datasets/Bingsu/Human_Action_Recognition)
|
| 92 |
+
"""
|
| 93 |
+
|
| 94 |
+
css = """
|
| 95 |
+
.main-header { text-align: center; margin-bottom: 0.5rem; }
|
| 96 |
+
.main-header h1 { font-size: 2.2rem; margin-bottom: 0; }
|
| 97 |
+
.footer { text-align: center; margin-top: 1rem; color: #888; font-size: 0.85rem; }
|
| 98 |
+
"""
|
| 99 |
+
|
| 100 |
+
with gr.Blocks(
|
| 101 |
+
theme=gr.themes.Soft(
|
| 102 |
+
primary_hue="blue",
|
| 103 |
+
secondary_hue="sky",
|
| 104 |
+
font=gr.themes.GoogleFont("Inter"),
|
| 105 |
+
),
|
| 106 |
+
css=css,
|
| 107 |
+
title="π Human Activity Recognition",
|
| 108 |
+
analytics_enabled=False,
|
| 109 |
+
) as demo:
|
| 110 |
+
|
| 111 |
+
# Header
|
| 112 |
+
gr.HTML("""
|
| 113 |
+
<div class="main-header">
|
| 114 |
+
<h1>π Human Activity Recognition</h1>
|
| 115 |
+
<p style="color: #555; font-size: 1.1rem;">Powered by MobileNetV2 Β· 15 Activity Classes</p>
|
| 116 |
+
</div>
|
| 117 |
+
""")
|
| 118 |
+
|
| 119 |
+
gr.Markdown(DESCRIPTION)
|
| 120 |
+
|
| 121 |
+
with gr.Row(equal_height=True):
|
| 122 |
+
with gr.Column(scale=1):
|
| 123 |
+
image_input = gr.Image(
|
| 124 |
+
type="pil",
|
| 125 |
+
label="πΈ Upload Image",
|
| 126 |
+
sources=["upload", "webcam", "clipboard"],
|
| 127 |
+
height=380,
|
| 128 |
+
)
|
| 129 |
+
with gr.Row():
|
| 130 |
+
clear_btn = gr.ClearButton(
|
| 131 |
+
[image_input],
|
| 132 |
+
value="ποΈ Clear",
|
| 133 |
+
variant="secondary",
|
| 134 |
+
size="sm",
|
| 135 |
+
)
|
| 136 |
+
submit_btn = gr.Button(
|
| 137 |
+
"π Classify Activity",
|
| 138 |
+
variant="primary",
|
| 139 |
+
size="lg",
|
| 140 |
+
)
|
| 141 |
+
|
| 142 |
+
with gr.Column(scale=1):
|
| 143 |
+
label_output = gr.Label(
|
| 144 |
+
num_top_classes=5,
|
| 145 |
+
label="π Prediction Results",
|
| 146 |
+
)
|
| 147 |
+
gr.Markdown(
|
| 148 |
+
"""
|
| 149 |
+
<div style="background: #f0f7ff; border-radius: 8px; padding: 12px; margin-top: 8px;">
|
| 150 |
+
<b>π‘ Tips for best results:</b>
|
| 151 |
+
<ul style="margin: 4px 0;">
|
| 152 |
+
<li>Use a clear photo with the person visible</li>
|
| 153 |
+
<li>Single person in the frame works best</li>
|
| 154 |
+
<li>Good lighting improves accuracy</li>
|
| 155 |
+
</ul>
|
| 156 |
+
</div>
|
| 157 |
+
"""
|
| 158 |
+
)
|
| 159 |
+
|
| 160 |
+
# Examples
|
| 161 |
+
if example_paths:
|
| 162 |
+
gr.Examples(
|
| 163 |
+
examples=sorted(example_paths),
|
| 164 |
+
inputs=image_input,
|
| 165 |
+
outputs=label_output,
|
| 166 |
+
fn=predict,
|
| 167 |
+
cache_examples=True,
|
| 168 |
+
label="πΌοΈ Try these examples",
|
| 169 |
+
)
|
| 170 |
+
|
| 171 |
+
# Event handlers
|
| 172 |
+
submit_btn.click(
|
| 173 |
+
fn=predict,
|
| 174 |
+
inputs=image_input,
|
| 175 |
+
outputs=label_output,
|
| 176 |
+
api_name="predict",
|
| 177 |
+
)
|
| 178 |
+
image_input.change(
|
| 179 |
+
fn=predict,
|
| 180 |
+
inputs=image_input,
|
| 181 |
+
outputs=label_output,
|
| 182 |
+
api_name=False,
|
| 183 |
+
)
|
| 184 |
+
|
| 185 |
+
# Footer
|
| 186 |
+
gr.HTML("""
|
| 187 |
+
<div class="footer">
|
| 188 |
+
Made with β€οΈ using <a href="https://www.gradio.app/" target="_blank">Gradio</a> &
|
| 189 |
+
<a href="https://huggingface.co/" target="_blank">Hugging Face</a> Β·
|
| 190 |
+
<a href="https://huggingface.co/Rishi2455/Human-Activity-Recognition" target="_blank">Model Card</a>
|
| 191 |
+
</div>
|
| 192 |
+
""")
|
| 193 |
+
|
| 194 |
+
# Launch with show_api=True
|
| 195 |
+
demo.launch(show_api=True)
|