Noursine commited on
Commit
39164a6
·
verified ·
1 Parent(s): df8281c

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +330 -0
app.py ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import plotly.graph_objects as go
3
+ import plotly.express as px
4
+ from ultralytics import YOLO
5
+ import cv2
6
+ import numpy as np
7
+ from PIL import Image
8
+ import pandas as pd
9
+ from streamlit_lottie import st_lottie
10
+ import requests
11
+
12
+ # Set page configuration
13
+ st.set_page_config(page_title="Advanced Dental Disease Detection", page_icon="🦷", layout="wide")
14
+
15
+ # Enhanced CSS for better styling and image sizing
16
+ st.markdown("""
17
+ <style>
18
+ .main {
19
+ padding: 2rem;
20
+ }
21
+ .stAlert > div {
22
+ padding: 0.5rem;
23
+ border-radius: 0.5rem;
24
+ }
25
+ .upload-text {
26
+ font-size: 1.2rem;
27
+ font-weight: bold;
28
+ margin-bottom: 1rem;
29
+ }
30
+ .condition-section {
31
+ margin: 1rem 0;
32
+ padding: 1rem;
33
+ border-radius: 0.5rem;
34
+ background-color: #f0f2f6;
35
+ }
36
+ .st-emotion-cache-1v0mbdj > img {
37
+ border-radius: 10px;
38
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
39
+ max-height: 400px; /* Control maximum height of images */
40
+ object-fit: contain;
41
+ }
42
+ .cropped-image {
43
+ max-height: 250px; /* Smaller height for cropped images */
44
+ width: auto;
45
+ margin: auto;
46
+ }
47
+ .st-tabs {
48
+ background-color: #ffffff;
49
+ padding: 1rem;
50
+ border-radius: 0.5rem;
51
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
52
+ }
53
+ .detection-grid {
54
+ display: grid;
55
+ grid-template-columns: repeat(3, 1fr);
56
+ gap: 1rem;
57
+ margin: 1rem 0;
58
+ }
59
+ </style>
60
+ """, unsafe_allow_html=True)
61
+
62
+ def load_lottie_url(url: str):
63
+ """
64
+ Load Lottie animation from URL
65
+ Args:
66
+ url (str): URL of the Lottie animation
67
+ Returns:
68
+ dict: Lottie animation JSON data or None if failed to load
69
+ """
70
+ try:
71
+ r = requests.get(url)
72
+ if r.status_code != 200:
73
+ return None
74
+ return r.json()
75
+ except Exception as e:
76
+ st.error(f"Error loading Lottie animation: {str(e)}")
77
+ return None
78
+
79
+ @st.cache_resource
80
+ def load_model():
81
+ """Load the YOLO model"""
82
+ try:
83
+ model = YOLO('best.pt')
84
+ return model
85
+ except Exception as e:
86
+ st.error(f"Error loading model: {str(e)}")
87
+ return None
88
+
89
+ def process_image(image, model):
90
+ """Process the image and return predictions"""
91
+ try:
92
+ if isinstance(image, Image.Image):
93
+ image_array = np.array(image)
94
+ else:
95
+ image_array = image
96
+
97
+ results = model.predict(image_array)
98
+ return results[0]
99
+ except Exception as e:
100
+ st.error(f"Error processing image: {str(e)}")
101
+ return None
102
+
103
+ def draw_single_condition(image, box, class_name):
104
+ """Draw a single condition's bounding box on the image"""
105
+ try:
106
+ image_array = np.array(image).copy()
107
+ x1, y1, x2, y2 = map(int, box.xyxy[0])
108
+ cv2.rectangle(image_array, (x1, y1), (x2, y2), (0, 255, 0), 2)
109
+ cv2.putText(image_array, class_name, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
110
+ return Image.fromarray(image_array)
111
+ except Exception as e:
112
+ st.error(f"Error drawing single condition: {str(e)}")
113
+ return image
114
+
115
+ def crop_detection(image, box):
116
+ """Crop the region of the detected condition"""
117
+ try:
118
+ image_array = np.array(image)
119
+ x1, y1, x2, y2 = map(int, box.xyxy[0])
120
+ padding_x, padding_y = int((x2 - x1) * 0.1), int((y2 - y1) * 0.1)
121
+ height, width = image_array.shape[:2]
122
+ x1, y1 = max(0, x1 - padding_x), max(0, y1 - padding_y)
123
+ x2, y2 = min(width, x2 + padding_x), min(height, y2 + padding_y)
124
+ cropped = image_array[y1:y2, x1:x2]
125
+ return Image.fromarray(cropped)
126
+ except Exception as e:
127
+ st.error(f"Error cropping detection: {str(e)}")
128
+ return None
129
+
130
+ def draw_predictions(image, results):
131
+ """Draw all bounding boxes and labels on the image"""
132
+ try:
133
+ if isinstance(image, Image.Image):
134
+ image_array = np.array(image)
135
+ else:
136
+ image_array = image
137
+
138
+ plotted_image = results.plot()
139
+ return Image.fromarray(plotted_image)
140
+ except Exception as e:
141
+ st.error(f"Error drawing predictions: {str(e)}")
142
+ return image
143
+
144
+ def group_predictions_by_condition(results):
145
+ """Group predictions by condition type"""
146
+ condition_groups = {}
147
+ if len(results.boxes) > 0:
148
+ for box in results.boxes:
149
+ class_id = int(box.cls[0])
150
+ class_name = results.names[class_id]
151
+ confidence = float(box.conf[0])
152
+ if class_name not in condition_groups:
153
+ condition_groups[class_name] = []
154
+ condition_groups[class_name].append({'box': box, 'confidence': confidence})
155
+ return condition_groups
156
+
157
+ def create_confidence_chart(condition_groups):
158
+ data = []
159
+ for condition, detections in condition_groups.items():
160
+ for detection in detections:
161
+ data.append({
162
+ 'Condition': condition,
163
+ 'Confidence': detection['confidence']
164
+ })
165
+ df = pd.DataFrame(data)
166
+ fig = px.box(df, x='Condition', y='Confidence', points="all")
167
+ fig.update_layout(title_text='Confidence Distribution by Condition')
168
+ return fig
169
+
170
+ def create_condition_count_chart(condition_groups):
171
+ counts = {condition: len(detections) for condition, detections in condition_groups.items()}
172
+ fig = go.Figure(data=[go.Pie(labels=list(counts.keys()), values=list(counts.values()))])
173
+ fig.update_layout(title_text='Distribution of Detected Conditions')
174
+ return fig
175
+
176
+ def main():
177
+ # Header
178
+ st.title("🦷 Advanced Dental Disease Detection")
179
+
180
+ # Educational Disclaimer
181
+ st.warning("""
182
+ 🚨 Disclaimer: This is an Educational/Research Tool Only 🚨
183
+ - This AI-powered application is for EDUCATIONAL and RESEARCH purposes ONLY
184
+ - It is NOT a substitute for professional medical diagnosis or advice
185
+ - Always consult a qualified dental professional for accurate diagnosis and treatment
186
+ - The detection results are probabilistic and should not be considered definitive medical guidance
187
+ """)
188
+
189
+ # Sidebar
190
+ with st.sidebar:
191
+ st.title("About")
192
+ st.info(
193
+ """Welcome to DentalVision AI Wedyan - Advanced X-ray Analysis
194
+ Our application leverages YOLO11 technology to analyze dental X-rays and identify a comprehensive range of dental conditions and features:
195
+ 🦷 Common Dental Conditions
196
+ - Cavities (Caries) and Tooth Decay
197
+ - Fractured and Missing Teeth
198
+ - Primary and Permanent Teeth
199
+ - Tooth Attrition and Wear
200
+ 👨‍⚕️ Dental Treatments & Restorations
201
+ - Crowns and Fillings
202
+ - Dental Implants and Abutments
203
+ - Root Canal Treatments
204
+ - Post-cores and Gingival Formers
205
+ 🎯 Orthodontic Elements
206
+ - Malaligned Teeth
207
+ - Orthodontic Brackets and Wires
208
+ - Permanent Retainers
209
+ - TADs and Metal Bands
210
+ 🔍 Bone & Tissue Analysis
211
+ - Mandibular Canal Assessment
212
+ - Maxillary Sinus Evaluation
213
+ - Bone Loss and Defects
214
+ - Cyst Detection
215
+ ⚠️ Special Conditions
216
+ - Impacted Teeth
217
+ - Periapical Lesions
218
+ - Retained Roots and Root Pieces
219
+ - Root Resorption and Supra Eruption
220
+ This AI-powered tool assists dental professionals in comprehensive X-ray analysis for more accurate diagnoses and treatment planning."""
221
+ )
222
+
223
+ # Add Lottie animation
224
+ #lottie_dental = load_lottie_url("https://assets5.lottiefiles.com/packages/lf20_xnbikipz.json")
225
+ #if lottie_dental:
226
+ # st_lottie(lottie_dental, speed=1, height=200, key="dental")
227
+
228
+ # Model loading
229
+ with st.spinner("Loading model..."):
230
+ model = load_model()
231
+
232
+ if model is None:
233
+ st.error("Failed to load model. Please check the model path and try again.")
234
+ return
235
+
236
+ # File uploader
237
+ uploaded_file = st.file_uploader("Choose an X-ray image...", type=['png', 'jpg', 'jpeg'])
238
+
239
+ if uploaded_file is not None:
240
+ try:
241
+ # Read image
242
+ image = Image.open(uploaded_file)
243
+
244
+ # Make prediction
245
+ with st.spinner("Analyzing image..."):
246
+ results = process_image(image, model)
247
+
248
+ if results is not None:
249
+ # Display original and processed images side by side
250
+ st.header("Image Analysis")
251
+ col1, col2 = st.columns(2)
252
+
253
+ with col1:
254
+ st.subheader("Original Image")
255
+ st.image(image, use_container_width=True)
256
+
257
+ with col2:
258
+ st.subheader("Detected Conditions")
259
+ processed_image = draw_predictions(image, results)
260
+ st.image(processed_image, use_container_width=True)
261
+
262
+ # Group predictions by condition
263
+ condition_groups = group_predictions_by_condition(results)
264
+
265
+ if condition_groups:
266
+ st.header("Detailed Analysis by Condition")
267
+
268
+ # Create tabs for each condition type
269
+ tabs = st.tabs(list(condition_groups.keys()))
270
+
271
+ for tab, (condition_name, detections) in zip(tabs, condition_groups.items()):
272
+ with tab:
273
+ st.subheader(f"{condition_name} Detections")
274
+ st.write(f"Number of {condition_name} detected: {len(detections)}")
275
+
276
+ # Display each instance of this condition
277
+ for idx, detection in enumerate(detections, 1):
278
+ st.write(f"#### Instance {idx}")
279
+ st.write(f"Confidence: {detection['confidence']:.2%}")
280
+
281
+ # Create three columns with controlled image sizes
282
+ cols = st.columns(3)
283
+
284
+ with cols[0]:
285
+ st.write("Full Image with Detection")
286
+ single_detection = draw_single_condition(image, detection['box'], condition_name)
287
+ st.image(single_detection, use_container_width=True, clamp=True)
288
+
289
+ with cols[1]:
290
+ st.write("Cropped Region")
291
+ cropped_region = crop_detection(image, detection['box'])
292
+ if cropped_region is not None:
293
+ st.image(cropped_region, use_container_width=True, clamp=True)
294
+
295
+ st.divider()
296
+
297
+ # Add advanced visualizations
298
+ st.header("Advanced Visualizations")
299
+ viz_cols = st.columns(2)
300
+
301
+ with viz_cols[0]:
302
+ confidence_chart = create_confidence_chart(condition_groups)
303
+ st.plotly_chart(confidence_chart, use_container_width=True)
304
+
305
+ with viz_cols[1]:
306
+ count_chart = create_condition_count_chart(condition_groups)
307
+ st.plotly_chart(count_chart, use_container_width=True)
308
+
309
+ else:
310
+ st.info("No dental conditions detected in the image.")
311
+
312
+ except Exception as e:
313
+ st.error(f"Error processing image: {str(e)}")
314
+
315
+ # Additional information
316
+ with st.expander("ℹ️ How to use"):
317
+ st.markdown("""
318
+ 1. Upload a dental X-ray image using the file uploader above
319
+ 2. The model will automatically process the image
320
+ 3. Results will show detected conditions with confidence scores
321
+ 4. View detailed analysis for each condition type in separate tabs
322
+ 5. For each detection you'll see:
323
+ - Full image with the detection marked
324
+ - Cropped view of the detected region
325
+ - Cropped view with detection marking
326
+ 6. Explore advanced visualizations for a comprehensive overview
327
+ """)
328
+
329
+ if __name__ == "__main__":
330
+ main()