Files changed (1) hide show
  1. app.py +59 -235
app.py CHANGED
@@ -1,243 +1,67 @@
1
  import streamlit as st
 
 
 
 
2
  from PIL import Image
3
- from ultralytics import YOLO
4
- import cv2, os
5
- from datetime import datetime
6
  import numpy as np
7
- from dotenv import load_dotenv
8
- import irm_cancer_module
9
 
10
- # ---------------- Charger config ----------------
11
- load_dotenv()
12
- SAVE_LIMIT_FREE = int(os.getenv("SAVE_LIMIT_FREE", 5))
13
- PREMIUM_KEY = os.getenv("PREMIUM_KEY", "VOTRE_CLE_PREMIUM")
14
-
15
- # ---------------- Config gΓ©nΓ©rale ----------------
16
- MODEL_PATH = "best.pt"
17
- MODEL_IRM_PATH = "best_seg.pt"
18
- MODEL_STROKE_PATH = "stroke.pt"
19
- SAVE_DIR = os.path.join("/tmp", "results")
20
- os.makedirs(SAVE_DIR, exist_ok=True)
21
-
22
- # ---------------- Charger modèles YOLO ----------------
23
- model = YOLO(MODEL_PATH)
24
- model_irm = YOLO(MODEL_IRM_PATH)
25
- model_stroke = YOLO(MODEL_STROKE_PATH)
26
-
27
- # ---------------- Etat utilisateur ----------------
28
- for key in ["uploads_count", "uploads_count_irm", "uploads_count_stroke", "premium_access"]:
29
- if key not in st.session_state:
30
- st.session_state[key] = 0 if "count" in key else False
31
-
32
- # ---------------- Fonctions utilitaires ----------------
33
- def _largest_face_bbox(np_img):
34
- import mediapipe as mp
35
- mp_face_detection = mp.solutions.face_detection
36
- h, w = np_img.shape[:2]
37
- with mp_face_detection.FaceDetection(min_detection_confidence=0.6) as fd:
38
- results = fd.process(cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR))
39
- if not results.detections:
40
- return None
41
- boxes = []
42
- for det in results.detections:
43
- rel = det.location_data.relative_bounding_box
44
- x1 = int(max(0, rel.xmin) * w)
45
- y1 = int(max(0, rel.ymin) * h)
46
- x2 = int(min(1.0, rel.xmin + rel.width) * w)
47
- y2 = int(min(1.0, rel.ymin + rel.height) * h)
48
- boxes.append((x1, y1, x2, y2))
49
- boxes.sort(key=lambda b: (b[2]-b[0])*(b[3]-b[1]), reverse=True)
50
- return boxes[0] if boxes else None
51
-
52
- def check_limit(counter_name="uploads_count"):
53
- """VΓ©rifie la limite gratuite."""
54
- if not st.session_state.premium_access and st.session_state[counter_name] >= SAVE_LIMIT_FREE:
55
- st.warning(f"⚠️ Limite gratuite atteinte ({SAVE_LIMIT_FREE} uploads). Passez en mode premium pour continuer.")
56
- return False
57
- return True
58
-
59
- # ---------------- PrΓ©diction image classique ----------------
60
- def predict_image(image, conf=0.85, show_labels=True):
61
- if not check_limit("uploads_count"):
62
- return None
63
- np_img = np.array(image)
64
- face_bbox = _largest_face_bbox(np_img)
65
- if face_bbox is None:
66
- st.warning("⚠️ Aucun visage humain détecté. Veuillez centrer le visage.")
67
- return None
68
- if np_img.shape[2] == 4:
69
- np_img = cv2.cvtColor(np_img, cv2.COLOR_RGBA2BGR)
70
- else:
71
- np_img = cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
72
- results = model.predict(source=np_img, conf=conf, verbose=False)
73
- if len(results[0].boxes) == 0:
74
- return None
75
- annotated_image = results[0].plot(labels=show_labels)
76
- out_path = os.path.join(SAVE_DIR, f"image_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png")
77
- cv2.imwrite(out_path, annotated_image)
78
- st.session_state.uploads_count += 1
79
- return out_path
80
-
81
- # ---------------- PrΓ©diction vidΓ©o ----------------
82
- def predict_video(video_path, conf=0.85, show_labels=True):
83
- if not check_limit("uploads_count"):
84
- return None
85
- cap = cv2.VideoCapture(video_path)
86
- fourcc = cv2.VideoWriter_fourcc(*'mp4v')
87
- out_path = os.path.join(SAVE_DIR, f"video_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4")
88
- fps = cap.get(cv2.CAP_PROP_FPS) or 30
89
- width, height = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
90
- out = cv2.VideoWriter(out_path, fourcc, fps, (width, height))
91
- detections = 0
92
- while cap.isOpened():
93
- ret, frame = cap.read()
94
- if not ret:
95
- break
96
- results = model.predict(frame, conf=conf, verbose=False)
97
- if len(results[0].boxes) > 0:
98
- detections += 1
99
- annotated = results[0].plot(labels=show_labels)
100
- out.write(annotated)
101
- cap.release()
102
- out.release()
103
- if detections == 0:
104
- return None
105
- st.session_state.uploads_count += 1
106
- return out_path
107
-
108
- # ---------------- PrΓ©diction IRM ----------------
109
- def predict_image_irm(image, conf=0.8, show_labels=True):
110
- if not check_limit("uploads_count_irm"):
111
- return None
112
- np_img = np.array(image)
113
- if np_img.shape[2] == 4:
114
- np_img = cv2.cvtColor(np_img, cv2.COLOR_RGBA2BGR)
115
- else:
116
- np_img = cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
117
- results = model_irm.predict(source=np_img, conf=conf, verbose=False)
118
- if results[0].masks is None or len(results[0].masks.data) == 0:
119
- st.warning("⚠️ Aucun masque détecté par le modèle IRM.")
120
- return None
121
- annotated_image = results[0].plot(labels=show_labels)
122
- out_path = os.path.join(SAVE_DIR, f"irm_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png")
123
- cv2.imwrite(out_path, annotated_image)
124
- st.session_state.uploads_count_irm += 1
125
- return out_path
126
-
127
- # ---------------- PrΓ©diction Stroke IRM ----------------
128
- def predict_image_stroke(image, conf=0.8, show_labels=True):
129
- if not check_limit("uploads_count_stroke"):
130
- return None
131
- np_img = np.array(image)
132
- if np_img.shape[2] == 4:
133
- np_img = cv2.cvtColor(np_img, cv2.COLOR_RGBA2BGR)
134
- else:
135
- np_img = cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
136
- results = model_stroke.predict(source=np_img, conf=conf, verbose=False)
137
- if len(results[0].boxes) == 0:
138
- st.warning("⚠️ Aucun AVC détecté par le modèle Stroke.")
139
  return None
140
- annotated_image = results[0].plot(labels=show_labels)
141
- out_path = os.path.join(SAVE_DIR, f"stroke_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png")
142
- cv2.imwrite(out_path, annotated_image)
143
- st.session_state.uploads_count_stroke += 1
144
- return out_path
145
-
146
- # ---------------- Interface Streamlit ----------------
147
- st.title("🧠 Stroke-IA Détection AVC par IA")
148
-
149
- # ---------------- Sidebar ----------------
150
- st.sidebar.header("βš™οΈ ParamΓ¨tres utilisateur")
151
- conf_threshold = st.sidebar.slider("Seuil de confiance (images/vidΓ©os)", 0.1, 1.0, 0.85, 0.05, key="conf_slider")
152
- conf_threshold_irm = st.sidebar.slider("Seuil de confiance (IRM)", 0.1, 1.0, 0.8, 0.05, key="conf_slider_irm")
153
- conf_threshold_stroke = st.sidebar.slider("Seuil de confiance (Stroke IRM)", 0.1, 1.0, 0.8, 0.05, key="conf_slider_stroke")
154
- show_labels = st.sidebar.checkbox("Afficher les labels", value=True, key="labels_checkbox")
155
 
156
- st.sidebar.header("πŸ”‘ Premium / Essai")
157
- if not st.session_state.premium_access:
158
- user_key = st.sidebar.text_input("Entrez votre clΓ© premium :", type="password", key="premium_input")
159
- if user_key == PREMIUM_KEY:
160
- st.session_state.premium_access = True
161
- st.sidebar.success("βœ… Mode premium activΓ© ! La limitation est levΓ©e.")
162
- st.rerun()
163
-
164
- if not st.session_state.premium_access:
165
- st.sidebar.info(f"πŸ“Š Utilisation gratuite images/vidΓ©os : {st.session_state.uploads_count}/{SAVE_LIMIT_FREE}")
166
- st.sidebar.info(f"πŸ“Š Utilisation gratuite IRM : {st.session_state.uploads_count_irm}/{SAVE_LIMIT_FREE}")
167
- st.sidebar.info(f"πŸ“Š Utilisation gratuite Stroke IRM : {st.session_state.uploads_count_stroke}/{SAVE_LIMIT_FREE}")
168
-
169
- # ---------------- Upload vidΓ©o ----------------
170
- st.header("πŸŽ₯ DΓ©tection sur vidΓ©o")
171
- video_file = st.file_uploader("Uploader une vidΓ©o", type=["mp4", "mov"], key="video_uploader")
172
- if video_file and st.button("Analyser la vidΓ©o", key="video_button"):
173
- temp_path = os.path.join(SAVE_DIR, "temp_video.mp4")
174
- with open(temp_path, "wb") as f:
175
- f.write(video_file.read())
176
- result_path = predict_video(temp_path, conf=conf_threshold, show_labels=show_labels)
177
- if result_path is None:
178
- st.success("βœ… Aucun AVC dΓ©tectΓ© ou limite gratuite atteinte.")
179
  else:
180
- st.video(result_path)
181
-
182
- # ---------------- Upload image ----------------
183
- st.header("πŸ–ΌοΈ DΓ©tection sur image")
184
- image_file = st.file_uploader("Uploader une image", type=["jpg", "jpeg", "png"], key="image_uploader")
185
- if image_file and st.button("Analyser l'image", key="image_button"):
186
- image = Image.open(image_file)
187
- result_path = predict_image(image, conf=conf_threshold, show_labels=show_labels)
188
- if result_path is None:
189
- st.success("βœ… Aucun AVC dΓ©tectΓ© ou limite gratuite atteinte.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  else:
191
- st.image(result_path, caption="Image annotΓ©e", use_container_width=True)
192
-
193
- # ---------------- Upload IRM ----------------
194
- st.header("🧠 Détection CANCER par IRM")
195
- irm_file = st.file_uploader("Uploader une IRM", type=["jpg", "jpeg", "png"], key="irm_uploader")
196
- if irm_file and st.button("Analyser l'IRM", key="irm_button"):
197
- irm_image = Image.open(irm_file)
198
- result_path_irm = predict_image_irm(irm_image, conf=conf_threshold_irm, show_labels=show_labels)
199
- if result_path_irm is None:
200
- st.success("βœ… Aucun rΓ©sultat dΓ©tectΓ© ou limite gratuite atteinte.")
201
- else:
202
- st.image(result_path_irm, caption="IRM annotΓ©e", use_container_width=True)
203
-
204
- # ---------------- Upload IRM Stroke ----------------
205
- st.header("🧠 Détection AVC par IRM")
206
- stroke_file = st.file_uploader("Uploader une IRM pour Stroke", type=["jpg", "jpeg", "png"], key="stroke_uploader")
207
- if stroke_file and st.button("Analyser l'IRM Stroke", key="stroke_button"):
208
- stroke_image = Image.open(stroke_file)
209
- result_path_stroke = predict_image_stroke(stroke_image, conf=conf_threshold_stroke, show_labels=show_labels)
210
- if result_path_stroke is None:
211
- st.success("βœ… Aucun rΓ©sultat dΓ©tectΓ© ou limite gratuite atteinte.")
212
- else:
213
- st.image(result_path_stroke, caption="Stroke annotΓ©e", use_container_width=True)
214
-
215
-
216
- # Upload IRM 3D (cancer)
217
- st.header("🧠 Détection Tumeur (IRM 3D)")
218
- irm3d_files = st.file_uploader("Uploader 4 sΓ©quences (FLAIR, T1, T1CE, T2)", type=["nii", "nii.gz"], accept_multiple_files=True)
219
- if irm3d_files and st.button("Analyser IRM 3D"):
220
- if len(irm3d_files) != 4:
221
- st.error("⚠️ Merci d’uploader exactement 4 fichiers IRM (FLAIR, T1, T1CE, T2)")
222
- else:
223
- tmp_paths = []
224
- for f in irm3d_files:
225
- path = os.path.join(SAVE_DIR, f.name)
226
- with open(path, "wb") as out:
227
- out.write(f.read())
228
- tmp_paths.append(path)
229
- seg, report_text, (nii_path, report_path, mask_path) = irm_cancer_module.run(tmp_paths)
230
- st.subheader("πŸ“ Rapport automatique")
231
- st.text(report_text)
232
- if mask_path and os.path.exists(mask_path):
233
- st.image(mask_path, caption="Segmentation annotΓ©e", use_container_width=True)
234
-
235
- # Disclaimer
236
- st.markdown(f"""
237
- ---
238
- πŸ‘¨β€πŸ’» **Badsi Djilali** β€” IngΓ©nieur Deep Learning
239
- πŸš€ CrΓ©ateur de **Stroke_IA_Detection**
240
-
241
- ⚠️ Démo technique, pas un avis médical.
242
- Β© {datetime.now().year} β€” Badsi Djilali.
243
- """)
 
1
  import streamlit as st
2
+ import cv2
3
+ import torch
4
+ import pandas as pd
5
+ import os
6
  from PIL import Image
 
 
 
7
  import numpy as np
 
 
8
 
9
+ # --- CONFIGURATION ---
10
+ MODEL_PATH = "best.pt" # Jo aapki file list mein hai
11
+ LOG_FILE = "scan_history.csv"
12
+
13
+ # Model load karne ka function
14
+ @st.cache_resource
15
+ def load_my_model():
16
+ # Agar YOLOv8 hai toh ultralytics use karein, v5 hai toh torch.hub
17
+ try:
18
+ model = torch.hub.load('ultralytics/yolov5', 'custom', path=MODEL_PATH)
19
+ return model
20
+ except:
21
+ st.error("Model load nahi ho raha. Check karein ki best.pt sahi jagah hai.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
+ # Data auto-save karne ka function
25
+ def auto_log_data(result_count):
26
+ new_entry = pd.DataFrame([[pd.Timestamp.now(), result_count]], columns=["Date", "Detections"])
27
+ if not os.path.isfile(LOG_FILE):
28
+ new_entry.to_csv(LOG_FILE, index=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  else:
30
+ new_entry.to_csv(LOG_FILE, mode='a', header=False, index=False)
31
+
32
+ # --- UI SETUP ---
33
+ st.set_page_config(page_title="Stroke-IA Detector", layout="wide")
34
+ st.title("🧠 Stroke-IA Real-time Analysis")
35
+
36
+ tab1, tab2 = st.tabs(["πŸ” Detection", "πŸ“Š Analytics Dashboard"])
37
+
38
+ model = load_my_model()
39
+
40
+ with tab1:
41
+ st.subheader("Upload for AI Scanning")
42
+ uploaded_file = st.file_uploader("Image ya Video select karein", type=['jpg', 'jpeg', 'png', 'mp4'])
43
+
44
+ if uploaded_file is not None and model is not None:
45
+ # Image Analysis
46
+ if uploaded_file.type.startswith('image'):
47
+ img = Image.open(uploaded_file)
48
+ results = model(img) # Model prediction
49
+
50
+ # Show Result
51
+ st.image(np.squeeze(results.render()), caption="AI Prediction")
52
+
53
+ # Auto-Save
54
+ det_count = len(results.pandas().xyxy[0])
55
+ if st.button("Save Result to Dashboard"):
56
+ auto_log_data(det_count)
57
+ st.success(f"Data Saved! {det_count} signs detected.")
58
+
59
+ with tab2:
60
+ st.subheader("πŸ“ˆ Automatic Analysis History")
61
+ if os.path.exists(LOG_FILE):
62
+ df = pd.read_csv(LOG_FILE)
63
+ st.write("Aapko dobara CSV upload karne ki zaroorat nahi hai. Ye history hai:")
64
+ st.dataframe(df, use_container_width=True)
65
+ st.line_chart(df['Detections'])
66
  else:
67
+ st.info("Abhi tak koi scan save nahi kiya gaya hai.")