fecia commited on
Commit
152f86b
1 Parent(s): 625ab7c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +159 -0
app.py CHANGED
@@ -155,5 +155,164 @@ iface = gr.Interface(
155
  description="Sube una imagen para detectar estenosis."
156
  )
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  if __name__ == "__main__":
159
  iface.launch()
 
155
  description="Sube una imagen para detectar estenosis."
156
  )
157
 
158
+ if __name__ == "__main__":
159
+ iface.launch()
160
+ import cv2
161
+ import numpy as np
162
+ import matplotlib.pyplot as plt
163
+ from ultralytics import YOLO
164
+ import gradio as gr
165
+ from matplotlib.patches import Rectangle
166
+ from matplotlib.legend import Legend
167
+
168
+ # Cargar el modelo YOLO (asegúrate de que 'model.pt' esté en el mismo directorio)
169
+ model = YOLO("model.pt")
170
+
171
+ def process_image(image):
172
+ # Convertir la imagen de PIL a NumPy array y de RGB a BGR (PIL usa RGB, OpenCV usa BGR)
173
+ img_rgb = np.array(image)
174
+ img_bgr = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2BGR)
175
+
176
+ # Realizar inferencia en la imagen BGR
177
+ results = model.predict(source=img_bgr, save=False)
178
+
179
+ # Inicializar la lista para almacenar la información de las máscaras
180
+ mask_info_list = []
181
+
182
+ # Crear una imagen en blanco para las máscaras (en formato BGR)
183
+ mask_image = np.zeros_like(img_bgr, dtype=np.uint8)
184
+
185
+ # Inicializar la máscara acumulativa
186
+ cumulative_mask = np.zeros((img_bgr.shape[0], img_bgr.shape[1]), dtype=bool)
187
+
188
+ # Procesar resultados
189
+ for result in results:
190
+ # Verificar si se detectaron máscaras
191
+ if result.masks is not None and len(result.masks.data) > 0:
192
+ # Obtener las máscaras, las probabilidades y las clases
193
+ masks = result.masks.data.cpu().numpy() # Shape: (num_masks, height, width)
194
+ confidences = result.boxes.conf.cpu().numpy() # Probabilidades
195
+ classes = result.boxes.cls.cpu().numpy().astype(int)
196
+ names = model.names # Nombres de las clases
197
+
198
+ # Normalizar las probabilidades al rango [0, 1]
199
+ confidences_norm = (confidences - confidences.min()) / (confidences.max() - confidences.min() + 1e-6)
200
+
201
+ # Redimensionar las máscaras para que coincidan con el tamaño de la imagen
202
+ resized_masks = []
203
+ for mask in masks:
204
+ mask_resized = cv2.resize(mask, (img_bgr.shape[1], img_bgr.shape[0]), interpolation=cv2.INTER_LINEAR)
205
+ resized_masks.append(mask_resized)
206
+ resized_masks = np.array(resized_masks) # Shape: (num_masks, height, width)
207
+
208
+ # Aplicar suavizado a las máscaras
209
+ smoothed_masks = []
210
+ for mask in resized_masks:
211
+ # Convertir la máscara a escala de grises (valores entre 0 y 255)
212
+ mask_uint8 = (mask * 255).astype(np.uint8)
213
+ # Aplicar desenfoque gaussiano
214
+ blurred_mask = cv2.GaussianBlur(mask_uint8, (7, 7), 0)
215
+ # Normalizar y convertir de nuevo a rango [0, 1]
216
+ mask_smoothed = blurred_mask.astype(np.float32) / 255.0
217
+ smoothed_masks.append(mask_smoothed)
218
+ smoothed_masks = np.array(smoothed_masks)
219
+
220
+ # Ordenar las máscaras por probabilidad descendente
221
+ sorted_indices = np.argsort(-confidences)
222
+ sorted_masks = smoothed_masks[sorted_indices]
223
+ sorted_confidences = confidences[sorted_indices]
224
+ sorted_confidences_norm = confidences_norm[sorted_indices]
225
+ sorted_classes = classes[sorted_indices]
226
+
227
+ # Definir el mapa de colores (puedes cambiar a 'plasma', 'inferno', etc.)
228
+ colormap = plt.cm.get_cmap('viridis') # Cambia 'viridis' por 'plasma' o 'inferno' si lo deseas
229
+
230
+ # Procesar cada máscara y asignar máscaras de mayor confianza primero
231
+ for idx_in_order, (idx, mask, conf_norm, conf, cls) in enumerate(
232
+ zip(sorted_indices, sorted_masks, sorted_confidences_norm, sorted_confidences, sorted_classes)):
233
+ # Umbralizar la máscara para obtener valores binarios
234
+ mask_bool = mask > 0.5
235
+
236
+ # Restar la máscara acumulativa de la máscara actual para obtener la parte única
237
+ unique_mask = np.logical_and(mask_bool, np.logical_not(cumulative_mask))
238
+
239
+ # Actualizar la máscara acumulativa
240
+ cumulative_mask = np.logical_or(cumulative_mask, unique_mask)
241
+
242
+ # Si no hay píxeles únicos, continuar
243
+ if not np.any(unique_mask):
244
+ continue
245
+
246
+ # Obtener el color del mapa de colores basado en la probabilidad normalizada
247
+ color_rgb = colormap(conf_norm)[:3] # Color en formato RGB [0, 1]
248
+ color_rgb_255 = [int(c * 255) for c in color_rgb] # Escalar a [0, 255]
249
+ color_bgr_255 = color_rgb_255[::-1] # Convertir de RGB a BGR
250
+
251
+ # Almacenar la información de la máscara
252
+ mask_info = {
253
+ 'mask_index': idx,
254
+ 'class': names[cls],
255
+ 'confidence': conf,
256
+ 'color_rgb': color_rgb_255,
257
+ 'color_bgr': color_bgr_255
258
+ }
259
+ mask_info_list.append(mask_info)
260
+
261
+ # Asignar colores a los píxeles correspondientes en la imagen de máscaras
262
+ for i in range(3):
263
+ mask_image[:, :, i][unique_mask] = color_bgr_255[i]
264
+
265
+ # Superponer la imagen de máscaras sobre la imagen original
266
+ alpha = 0.2 # Transparencia ajustada
267
+ img_with_masks = cv2.addWeighted(img_bgr.astype(np.float32), 1, mask_image.astype(np.float32), alpha, 0).astype(np.uint8)
268
+
269
+ else:
270
+ # Si no hay máscaras, usar la imagen original
271
+ img_with_masks = img_bgr.copy()
272
+ print("No se detectaron máscaras en esta imagen.")
273
+
274
+ # Convertir la imagen de BGR a RGB para matplotlib
275
+ img_with_masks_rgb = cv2.cvtColor(img_with_masks, cv2.COLOR_BGR2RGB)
276
+
277
+ # Crear una figura para mostrar la imagen y la leyenda
278
+ fig, ax = plt.subplots(figsize=(8, 8))
279
+ ax.imshow(img_with_masks_rgb)
280
+ ax.axis('off')
281
+
282
+ # Crear la leyenda si hay máscaras detectadas
283
+ if mask_info_list:
284
+ handles = []
285
+ labels = []
286
+ for mask_info in mask_info_list:
287
+ color_rgb_normalized = np.array(mask_info['color_rgb']) / 255 # Normalizar al rango [0, 1]
288
+ patch = Rectangle((0, 0), 1, 1, facecolor=color_rgb_normalized)
289
+ label = f"{mask_info['class']} - Confianza: {mask_info['confidence']:.2f}"
290
+ handles.append(patch)
291
+ labels.append(label)
292
+
293
+ # Añadir la leyenda al gráfico
294
+ legend = Legend(ax, handles, labels, loc='upper right')
295
+ ax.add_artist(legend)
296
+
297
+ plt.tight_layout()
298
+
299
+ # Convertir la figura a una imagen NumPy
300
+ fig.canvas.draw()
301
+ img_figure = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8)
302
+ img_figure = img_figure.reshape(fig.canvas.get_width_height()[::-1] + (3,))
303
+
304
+ plt.close(fig) # Cerrar la figura para liberar memoria
305
+
306
+ return img_figure
307
+
308
+ # Crear la interfaz de Gradio
309
+ iface = gr.Interface(
310
+ fn=process_image,
311
+ inputs=gr.Image(type="pil"),
312
+ outputs=gr.Image(type="numpy"),
313
+ title="Detección de Estenosis",
314
+ description="Sube una imagen para detectar estenosis."
315
+ )
316
+
317
  if __name__ == "__main__":
318
  iface.launch()