STREAMLITE / app5.py
Stroke-ia's picture
Rename app.py to app5.py
a5cb916 verified
Raw
History Blame
6.18 kB
import streamlit as st
from PIL import Image
from ultralytics import YOLO
import cv2, os, logging
from datetime import datetime
import numpy as np
# ---------------- Config générale ----------------
MODEL_PATH = "best.pt"
SAVE_DIR = os.path.join("/tmp", "results")
os.makedirs(SAVE_DIR, exist_ok=True)
# ---------------- Limites version gratuite ----------------
SAVE_LIMIT_FREE = 5 # nombre max d'uploads pour version gratuite
uploads_count = 0
premium_access = False # actif après clé premium
# ---------------- Logger ----------------
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger("stroke-api")
# ---------------- Charger modèle YOLO ----------------
model = YOLO(MODEL_PATH)
# ---------------- Fonctions utilitaires ----------------
def _largest_face_bbox(np_img, min_conf=0.6):
import mediapipe as mp
mp_face_detection = mp.solutions.face_detection
h, w = np_img.shape[:2]
with mp_face_detection.FaceDetection(min_detection_confidence=min_conf) as fd:
results = fd.process(cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR))
if not results.detections:
return None
boxes = []
for det in results.detections:
rel = det.location_data.relative_bounding_box
x1 = int(max(0, rel.xmin) * w)
y1 = int(max(0, rel.ymin) * h)
x2 = int(min(1.0, rel.xmin + rel.width) * w)
y2 = int(min(1.0, rel.ymin + rel.height) * h)
boxes.append((x1, y1, x2, y2))
boxes.sort(key=lambda b: (b[2]-b[0])*(b[3]-b[1]), reverse=True)
return boxes[0] if boxes else None
def predict_image(image, conf=0.85, show_labels=True):
global uploads_count, premium_access
# Limite version gratuite
if not premium_access:
if uploads_count >= SAVE_LIMIT_FREE:
st.warning(f"⚠️ Limite gratuite atteinte ({SAVE_LIMIT_FREE} images). Entrez une clé API pour continuer.")
return None
uploads_count += 1
np_img = np.array(image)
if np_img.shape[2] == 4:
np_img = cv2.cvtColor(np_img, cv2.COLOR_RGBA2BGR)
else:
np_img = cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
# 1) Détection visage
face_bbox = _largest_face_bbox(np_img)
if face_bbox is None:
st.warning("⚠️ Aucun visage humain détecté. Veuillez centrer le visage.")
return None
# 2) YOLO inference
results = model.predict(source=np_img, conf=conf, verbose=False)
# Vérifier si on a une détection valide
if len(results[0].boxes) == 0:
return None # aucune détection au seuil demandé
annotated_image = results[0].plot(labels=show_labels)
out_path = os.path.join(SAVE_DIR, f"image_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png")
cv2.imwrite(out_path, annotated_image)
return out_path
def predict_video(video_path, conf=0.85, show_labels=True):
global uploads_count, premium_access
if not premium_access:
if uploads_count >= SAVE_LIMIT_FREE:
st.warning(f"⚠️ Limite gratuite atteinte ({SAVE_LIMIT_FREE} vidéos). Entrez une clé API pour continuer.")
return None
uploads_count += 1
cap = cv2.VideoCapture(video_path)
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out_path = os.path.join(SAVE_DIR, f"video_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4")
fps = cap.get(cv2.CAP_PROP_FPS) or 30
width, height = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
out = cv2.VideoWriter(out_path, fourcc, fps, (width, height))
detections = 0
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 1) Détection visage
face_bbox = _largest_face_bbox(frame)
if face_bbox is None:
continue # skip frame sans visage
results = model.predict(frame, conf=conf, verbose=False)
if len(results[0].boxes) > 0:
detections += 1
annotated = results[0].plot(labels=show_labels)
out.write(annotated)
cap.release()
out.release()
if detections == 0:
return None
return out_path
# ---------------- Interface Streamlit ----------------
st.title("🧠 Stroke-IA – Détection AVC par IA")
# Sidebar
st.sidebar.header("⚙️ Paramètres")
conf_threshold = st.sidebar.slider("Seuil de confiance", 0.1, 1.0, 0.85, 0.05)
show_labels = st.sidebar.checkbox("Afficher les labels", value=True)
st.sidebar.header("🔑 Mode Premium")
key_input = st.sidebar.text_input("Entrez votre clé premium")
if key_input == "VOTRE_CLE_PREMIUM":
premium_access = True
st.sidebar.success("✅ Mode premium activé !")
key_input = "" # effacer la saisie
# Section image upload
st.header("🖼️ Détection sur image")
image_file = st.file_uploader("Uploader une image", type=["jpg","jpeg","png"])
if image_file and st.button("Analyser l'image"):
image = Image.open(image_file)
result_path = predict_image(image, conf=conf_threshold, show_labels=show_labels)
if result_path is None:
st.success(f"✅ Aucune détection ou limite gratuite atteinte")
else:
st.image(result_path, caption="Image annotée", use_container_width=True)
# Section vidéo upload
st.header("🎥 Détection sur vidéo")
video_file = st.file_uploader("Uploader une vidéo (mp4, mov, etc.)", type=["mp4","mov"])
if video_file and st.button("Analyser la vidéo"):
temp_path = os.path.join(SAVE_DIR, "temp_video.mp4")
with open(temp_path,"wb") as f:
f.write(video_file.read())
result_path = predict_video(temp_path, conf=conf_threshold, show_labels=show_labels)
if result_path is None:
st.success(f"✅ Aucune détection ou limite gratuite atteinte")
else:
st.video(result_path)
# Disclaimer
st.markdown(f"""
---
👨‍💻 **Badsi Djilali** — Ingénieur Deep Learning
🚀 Créateur de **Stroke_IA_Detection**
🧠 (Détection d'asymétrie faciale & AVC par IA)
⚠️ **Disclaimer :** Stroke-IA est une démo technique, pas un avis médical.
© {datetime.now().year} — Badsi Djilali.
""")