yassonee commited on
Commit
4ae300b
·
verified ·
1 Parent(s): d42aec0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -113
app.py CHANGED
@@ -1,10 +1,9 @@
1
- # app.py
2
  import streamlit as st
3
  from transformers import pipeline
4
  from PIL import Image, ImageDraw
5
  import torch
6
 
7
- # Configuration de la page
8
  st.set_page_config(
9
  page_title="Fraktur Detektion",
10
  layout="wide",
@@ -14,98 +13,98 @@ st.set_page_config(
14
  # CSS optimisé
15
  st.markdown("""
16
  <style>
17
- /* Réinitialisation complète */
18
  .stApp {
19
- background: transparent !important;
20
  padding: 0 !important;
 
 
21
  }
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  .block-container {
24
  padding: 0.5rem !important;
25
  max-width: 100% !important;
26
  }
27
 
28
- /* Suppression des éléments superflus */
29
- #MainMenu, footer, header, .viewerBadge_container__1QSob {
30
- display: none !important;
 
 
 
31
  }
32
 
33
- .stDeployButton {
34
- display: none !important;
 
 
 
35
  }
36
 
37
- /* Style compact */
38
- .uploadedFile {
39
- border: 1px dashed var(--border-color);
40
- border-radius: 0.5rem;
41
- padding: 0.5rem;
42
  }
43
 
44
- .st-emotion-cache-1kyxreq {
45
- margin-top: -2rem !important;
 
 
46
  }
47
 
48
- /* Conteneurs de résultats */
49
  .result-box {
50
- padding: 0.5rem;
51
  border-radius: 0.375rem;
52
  margin: 0.25rem 0;
 
53
  border: 1px solid var(--border-color);
54
- background: var(--background-color);
55
- }
56
-
57
- /* Tabs plus compacts */
58
- .stTabs [data-baseweb="tab-list"] {
59
- gap: 0.5rem;
60
  }
61
 
62
- .stTabs [data-baseweb="tab"] {
63
- padding: 0.25rem 0.5rem;
64
- font-size: 0.875rem;
65
  }
66
 
67
- /* Variables CSS pour le thème */
68
- :root[data-theme="light"] {
69
- --background-color: rgba(249, 250, 251, 0.8);
70
- --border-color: #e5e7eb;
71
- --text-color: #1f2937;
72
  }
73
 
74
- :root[data-theme="dark"] {
75
- --background-color: rgba(17, 24, 39, 0.8);
76
- --border-color: #374151;
77
- --text-color: #e5e7eb;
78
  }
79
 
80
- /* Ajustements responsifs */
81
- @media (max-width: 768px) {
82
- .block-container {
83
- padding: 0.25rem !important;
84
- }
85
  }
86
  </style>
87
- <script>
88
- function updateTheme(isDark) {
89
- document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
90
- }
91
-
92
- window.addEventListener('message', function(e) {
93
- if (e.data.type === 'theme-change') {
94
- updateTheme(e.data.theme === 'dark');
95
- }
96
- });
97
-
98
- // Thème initial basé sur les préférences système
99
- updateTheme(window.matchMedia('(prefers-color-scheme: dark)').matches);
100
- </script>
101
  """, unsafe_allow_html=True)
102
 
103
  @st.cache_resource
104
  def load_models():
105
  return {
106
- "D3STRON": pipeline("object-detection", model="D3STRON/bone-fracture-detr"),
107
- "Heem2": pipeline("image-classification", model="Heem2/bone-fracture-detection-using-xray"),
108
- "Nandodeomkar": pipeline("image-classification",
109
  model="nandodeomkar/autotrain-fracture-detection-using-google-vit-base-patch-16-54382127388")
110
  }
111
 
@@ -114,7 +113,7 @@ def translate_label(label):
114
  "fracture": "Knochenbruch",
115
  "no fracture": "Kein Bruch",
116
  "normal": "Normal",
117
- "abnormal": "Abnormal"
118
  }
119
  return translations.get(label.lower(), label)
120
 
@@ -134,76 +133,85 @@ def draw_boxes(image, predictions):
134
  text_bbox = draw.textbbox((box['xmin'], box['ymin']-15), label)
135
  draw.rectangle(text_bbox, fill=color)
136
  draw.text((box['xmin'], box['ymin']-15), label, fill="white")
137
-
138
  return image
139
 
140
  def main():
141
  models = load_models()
142
 
143
- # Contrôle de confiance simplifié
144
  conf_threshold = st.slider(
145
  "Konfidenzschwelle",
146
- min_value=0.0,
147
- max_value=1.0,
148
- value=0.60,
149
- step=0.05,
150
- help="Schwellenwert für die Erkennung (0-1)"
151
  )
152
 
153
  # Upload plus propre
154
- uploaded_file = st.file_uploader(
155
- "",
156
- type=['png', 'jpg', 'jpeg'],
157
- key="xray_upload"
158
- )
159
 
160
  if uploaded_file:
161
- col1, col2 = st.columns([1, 1])
162
-
163
- with col1:
164
- image = Image.open(uploaded_file)
165
- max_size = (300, 300)
166
- image.thumbnail(max_size, Image.Resampling.LANCZOS)
167
- st.image(image, use_container_width=True)
168
 
169
- with col2:
170
- tab1, tab2 = st.tabs(["📊 Klassifizierung", "🔍 Lokalisierung"])
 
 
 
171
 
172
- with tab1:
173
- for name in ["Heem2", "Nandodeomkar"]:
174
- with st.spinner("Analyse..."):
175
- predictions = models[name](image)
176
- for pred in predictions:
177
- if pred['score'] >= conf_threshold:
178
- score_color = "#22c55e" if pred['score'] > 0.7 else "#eab308"
179
- st.markdown(f"""
180
- <div class='result-box'>
181
- <span style='color: {score_color}; font-weight: 500;'>
182
- {pred['score']:.1%}
183
- </span> - {translate_label(pred['label'])}
184
- </div>
185
- """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
 
187
- with tab2:
188
- with st.spinner("Lokalisierung..."):
189
- predictions = models["D3STRON"](image)
190
- filtered_preds = [p for p in predictions if p['score'] >= conf_threshold]
191
-
192
- if filtered_preds:
193
- result_image = image.copy()
194
- result_image = draw_boxes(result_image, filtered_preds)
195
- st.image(result_image, use_container_width=True)
196
-
197
- for pred in filtered_preds:
198
- st.markdown(f"""
199
- <div class='result-box'>
200
- {translate_label(pred['label'])}: {pred['score']:.1%}
201
- </div>
202
- """, unsafe_allow_html=True)
203
- else:
204
- st.info("Keine Erkennungen über dem Schwellenwert")
205
  else:
206
- st.info("Röntgenbild hochladen (JPEG, PNG, max. 5MB)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
 
208
  if __name__ == "__main__":
209
  main()
 
 
1
  import streamlit as st
2
  from transformers import pipeline
3
  from PIL import Image, ImageDraw
4
  import torch
5
 
6
+ # Configuration page
7
  st.set_page_config(
8
  page_title="Fraktur Detektion",
9
  layout="wide",
 
13
  # CSS optimisé
14
  st.markdown("""
15
  <style>
16
+ /* Reset complet */
17
  .stApp {
18
+ background-color: var(--background-color) !important;
19
  padding: 0 !important;
20
+ max-height: 600px !important;
21
+ overflow: hidden !important;
22
  }
23
 
24
+ /* Variables de thème */
25
+ [data-theme="light"] {
26
+ --background-color: #ffffff;
27
+ --text-color: #1f2937;
28
+ --border-color: #e5e7eb;
29
+ --secondary-bg: #f3f4f6;
30
+ }
31
+
32
+ [data-theme="dark"] {
33
+ --background-color: #1f2937;
34
+ --text-color: #f3f4f6;
35
+ --border-color: #4b5563;
36
+ --secondary-bg: #374151;
37
+ }
38
+
39
+ /* Conteneur principal */
40
  .block-container {
41
  padding: 0.5rem !important;
42
  max-width: 100% !important;
43
  }
44
 
45
+ /* Upload et contrôles */
46
+ .uploadedFile {
47
+ border: 1px dashed var(--border-color);
48
+ border-radius: 0.375rem;
49
+ padding: 0.25rem;
50
+ background: var(--secondary-bg);
51
  }
52
 
53
+ /* Images plus petites */
54
+ .stImage > img {
55
+ max-width: 250px !important;
56
+ max-height: 250px !important;
57
+ margin: 0 auto !important;
58
  }
59
 
60
+ /* Tabs compacts */
61
+ .stTabs [data-baseweb="tab-list"] {
62
+ gap: 0.25rem;
63
+ background: transparent;
 
64
  }
65
 
66
+ .stTabs [data-baseweb="tab"] {
67
+ padding: 0.25rem 0.5rem;
68
+ background: var(--secondary-bg);
69
+ border-radius: 0.375rem;
70
  }
71
 
72
+ /* Résultats */
73
  .result-box {
74
+ padding: 0.375rem;
75
  border-radius: 0.375rem;
76
  margin: 0.25rem 0;
77
+ background: var(--secondary-bg);
78
  border: 1px solid var(--border-color);
79
+ color: var(--text-color);
 
 
 
 
 
80
  }
81
 
82
+ /* Cacher éléments inutiles */
83
+ #MainMenu, footer, header, .viewerBadge_container__1QSob, .stDeployButton {
84
+ display: none !important;
85
  }
86
 
87
+ div[data-testid="stVerticalBlock"] {
88
+ gap: 0.5rem !important;
 
 
 
89
  }
90
 
91
+ /* Ajustements espacement */
92
+ .st-emotion-cache-1kyxreq {
93
+ margin-top: -1rem !important;
 
94
  }
95
 
96
+ .st-emotion-cache-1wmy9hl {
97
+ padding: 0 !important;
 
 
 
98
  }
99
  </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  """, unsafe_allow_html=True)
101
 
102
  @st.cache_resource
103
  def load_models():
104
  return {
105
+ "KnochenAuge": pipeline("object-detection", model="D3STRON/bone-fracture-detr"), # L'œil des os
106
+ "KnochenWächter": pipeline("image-classification", model="Heem2/bone-fracture-detection-using-xray"), # Le gardien des os
107
+ "RöntgenMeister": pipeline("image-classification", # Le maître des rayons X
108
  model="nandodeomkar/autotrain-fracture-detection-using-google-vit-base-patch-16-54382127388")
109
  }
110
 
 
113
  "fracture": "Knochenbruch",
114
  "no fracture": "Kein Bruch",
115
  "normal": "Normal",
116
+ "abnormal": "Auffällig"
117
  }
118
  return translations.get(label.lower(), label)
119
 
 
133
  text_bbox = draw.textbbox((box['xmin'], box['ymin']-15), label)
134
  draw.rectangle(text_bbox, fill=color)
135
  draw.text((box['xmin'], box['ymin']-15), label, fill="white")
 
136
  return image
137
 
138
  def main():
139
  models = load_models()
140
 
141
+ # Contrôle de confiance compact
142
  conf_threshold = st.slider(
143
  "Konfidenzschwelle",
144
+ min_value=0.0, max_value=1.0,
145
+ value=0.60, step=0.05
 
 
 
146
  )
147
 
148
  # Upload plus propre
149
+ uploaded_file = st.file_uploader("", type=['png', 'jpg', 'jpeg'])
 
 
 
 
150
 
151
  if uploaded_file:
152
+ image = Image.open(uploaded_file)
153
+ max_size = (250, 250) # Taille réduite
154
+ image.thumbnail(max_size, Image.Resampling.LANCZOS)
 
 
 
 
155
 
156
+ tab1, tab2 = st.tabs(["📊 KI-Analyse", "🔍 Lokalisierung"])
157
+
158
+ with tab1:
159
+ # Afficher l'image originale seulement dans l'onglet Analyse
160
+ st.image(image, use_container_width=False)
161
 
162
+ model_names = {
163
+ "KnochenWächter": "🛡️ Der KnochenWächter",
164
+ "RöntgenMeister": "🎓 Der RöntgenMeister"
165
+ }
166
+
167
+ for model_key, display_name in model_names.items():
168
+ st.markdown(f"<div style='font-weight:500; margin-top:0.5rem;'>{display_name}</div>", unsafe_allow_html=True)
169
+ predictions = models[model_key](image)
170
+ for pred in predictions:
171
+ if pred['score'] >= conf_threshold:
172
+ score_color = "#22c55e" if pred['score'] > 0.7 else "#eab308"
173
+ st.markdown(f"""
174
+ <div class='result-box'>
175
+ <span style='color: {score_color}; font-weight: 500;'>
176
+ {pred['score']:.1%}
177
+ </span> - {translate_label(pred['label'])}
178
+ </div>
179
+ """, unsafe_allow_html=True)
180
+
181
+ with tab2:
182
+ # Dans l'onglet Lokalisierung, montrer directement l'image avec les boîtes
183
+ with st.spinner("Analyse läuft..."):
184
+ predictions = models["KnochenAuge"](image)
185
+ filtered_preds = [p for p in predictions if p['score'] >= conf_threshold]
186
+
187
+ if filtered_preds:
188
+ result_image = image.copy()
189
+ result_image = draw_boxes(result_image, filtered_preds)
190
+ st.markdown("### 👁️ Das KnochenAuge")
191
+ st.image(result_image, use_container_width=False)
192
+ else:
193
+ st.info("Keine Auffälligkeiten erkannt")
194
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  else:
196
+ st.info("Röntgenbild hochladen (JPEG, PNG)")
197
+
198
+ # Script pour la synchronisation du thème
199
+ st.markdown("""
200
+ <script>
201
+ function updateTheme(isDark) {
202
+ document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
203
+ }
204
+
205
+ window.addEventListener('message', function(e) {
206
+ if (e.data.type === 'theme-change') {
207
+ updateTheme(e.data.theme === 'dark');
208
+ }
209
+ });
210
+
211
+ // Thème initial
212
+ updateTheme(window.matchMedia('(prefers-color-scheme: dark)').matches);
213
+ </script>
214
+ """, unsafe_allow_html=True)
215
 
216
  if __name__ == "__main__":
217
  main()