marrtinagg commited on
Commit
4f8e957
1 Parent(s): 6317a79

Edit app.py

Browse files
Files changed (1) hide show
  1. app.py +114 -38
app.py CHANGED
@@ -35,15 +35,11 @@ def make_gradcam_heatmap(img_array, model, last_conv_layer_name="conv4", pred_in
35
  )
36
  with tf.GradientTape() as tape:
37
  conv_outputs, predictions = grad_model(img_array)
38
-
39
- # 馃憞 Aseguramos que predictions sea tensor
40
  if isinstance(predictions, list):
41
  predictions = predictions[0]
42
-
43
  if pred_index is None:
44
  pred_index = tf.argmax(predictions[0])
45
  class_channel = predictions[:, pred_index]
46
-
47
  grads = tape.gradient(class_channel, conv_outputs)
48
  pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))
49
  conv_outputs = conv_outputs[0]
@@ -52,48 +48,40 @@ def make_gradcam_heatmap(img_array, model, last_conv_layer_name="conv4", pred_in
52
  heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap)
53
  return heatmap.numpy()
54
 
55
- # === Funci贸n de predicci贸n principal ===
56
  def preprocess_and_predict(img_input):
57
- # Convertir PIL a OpenCV (BGR)
58
  img = np.array(img_input)[:, :, ::-1]
59
-
60
- # 1. Zoom
61
  zoomed = apply_zoom(img, zoom_factor=0.9)
62
-
63
- # 2. Quitar pelos
64
  rgb_clean = cv2.cvtColor(zoomed, cv2.COLOR_BGR2RGB)
65
  clean = quitar_pelos(rgb_clean)
66
 
67
- # 3. Segmentar
68
  mask, lesion_rgb = segmentar_lesion(clean, size=(ROWS, COLS))
69
 
70
- # 4. Preparar para SimpleNet
71
  lesion_resized = cv2.resize(lesion_rgb, (ROWS, COLS))
72
  img_array = image.img_to_array(lesion_resized) / 255.0
73
  img_array = np.expand_dims(img_array, axis=0)
74
 
75
- # 5. Predicci贸n con SimpleNet
76
  probs = model.predict(img_array)[0]
77
  classes = ["Benign", "Malignant"]
78
  pred_idx = np.argmax(probs)
79
  pred_label = classes[pred_idx]
80
  result_text = f"Predicci贸n: {pred_label} ({probs[pred_idx]*100:.2f}%)"
81
 
82
- # 6. M茅tricas geom茅tricas
83
  area = calcular_area(mask)
84
  perim = calcular_perimetro(mask)
85
  circ = calcular_circularidad(mask)
86
  sim_v, sim_h = calcular_simetria(mask)
87
 
88
- metrics_text = (
89
- f"脕rea: {area}\n"
90
- f"Per铆metro: {perim}\n"
91
- f"Circularidad: {circ}\n"
92
- f"Simetr铆a Vertical: {sim_v}\n"
93
- f"Simetr铆a Horizontal: {sim_h}"
94
- )
95
 
96
- # 7. Grad-CAM con ZoomNet (imagen en bruto)
97
  raw_resized = cv2.resize(np.array(img_input), (ROWS, COLS))
98
  raw_array = image.img_to_array(raw_resized) / 255.0
99
  raw_array = np.expand_dims(raw_array, axis=0)
@@ -104,22 +92,110 @@ def preprocess_and_predict(img_input):
104
  heatmap_color = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
105
  overlay = cv2.addWeighted(raw_resized.astype("uint8"), 0.6, heatmap_color, 0.4, 0)
106
 
107
- return mask, lesion_rgb, result_text, metrics_text, overlay
108
-
109
- # === Interfaz Gradio ===
110
- demo = gr.Interface(
111
- fn=preprocess_and_predict,
112
- inputs=gr.Image(type="pil", label="Sube una imagen de lesi贸n"),
113
- outputs=[
114
- gr.Image(type="numpy", label="M谩scara Binaria"),
115
- gr.Image(type="numpy", label="Lesi贸n Segmentada"),
116
- gr.Textbox(label="Resultado del Modelo"),
117
- gr.Textbox(label="M茅tricas de la Lesi贸n"),
118
- gr.Image(type="numpy", label="Grad-CAM (ZoomNet)")
119
- ],
120
- title="DermaScan - Clasificaci贸n de Lesiones",
121
- description="Sube una imagen de piel. El sistema segmenta la lesi贸n, muestra la m谩scara, la predicci贸n, m茅tricas geom茅tricas y Grad-CAM."
122
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
 
124
  if __name__ == "__main__":
125
  demo.launch()
 
35
  )
36
  with tf.GradientTape() as tape:
37
  conv_outputs, predictions = grad_model(img_array)
 
 
38
  if isinstance(predictions, list):
39
  predictions = predictions[0]
 
40
  if pred_index is None:
41
  pred_index = tf.argmax(predictions[0])
42
  class_channel = predictions[:, pred_index]
 
43
  grads = tape.gradient(class_channel, conv_outputs)
44
  pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))
45
  conv_outputs = conv_outputs[0]
 
48
  heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap)
49
  return heatmap.numpy()
50
 
51
+ # === Funci贸n principal ===
52
  def preprocess_and_predict(img_input):
 
53
  img = np.array(img_input)[:, :, ::-1]
 
 
54
  zoomed = apply_zoom(img, zoom_factor=0.9)
 
 
55
  rgb_clean = cv2.cvtColor(zoomed, cv2.COLOR_BGR2RGB)
56
  clean = quitar_pelos(rgb_clean)
57
 
 
58
  mask, lesion_rgb = segmentar_lesion(clean, size=(ROWS, COLS))
59
 
 
60
  lesion_resized = cv2.resize(lesion_rgb, (ROWS, COLS))
61
  img_array = image.img_to_array(lesion_resized) / 255.0
62
  img_array = np.expand_dims(img_array, axis=0)
63
 
 
64
  probs = model.predict(img_array)[0]
65
  classes = ["Benign", "Malignant"]
66
  pred_idx = np.argmax(probs)
67
  pred_label = classes[pred_idx]
68
  result_text = f"Predicci贸n: {pred_label} ({probs[pred_idx]*100:.2f}%)"
69
 
70
+ # === M茅tricas geom茅tricas en formato tabla ===
71
  area = calcular_area(mask)
72
  perim = calcular_perimetro(mask)
73
  circ = calcular_circularidad(mask)
74
  sim_v, sim_h = calcular_simetria(mask)
75
 
76
+ metrics_data = [
77
+ ["脕rea (px虏)", area],
78
+ ["Per铆metro (px)", perim],
79
+ ["Circularidad", round(circ, 3)],
80
+ ["Simetr铆a Vertical", round(sim_v, 3)],
81
+ ["Simetr铆a Horizontal", round(sim_h, 3)]
82
+ ]
83
 
84
+ # === Grad-CAM ===
85
  raw_resized = cv2.resize(np.array(img_input), (ROWS, COLS))
86
  raw_array = image.img_to_array(raw_resized) / 255.0
87
  raw_array = np.expand_dims(raw_array, axis=0)
 
92
  heatmap_color = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
93
  overlay = cv2.addWeighted(raw_resized.astype("uint8"), 0.6, heatmap_color, 0.4, 0)
94
 
95
+ return mask, lesion_rgb, result_text, metrics_data, overlay
96
+
97
+
98
+ # === Interfaz con estilo ===
99
+ with gr.Blocks(css="""
100
+ body, .gradio-container {
101
+ font-family: 'Inter', sans-serif;
102
+ background: #ffffff !important;
103
+ }
104
+ h1, h2 { font-weight: 600; color: #111827; margin-bottom: 0.5rem; }
105
+ .section { background: white; border-radius: 0.75rem; padding: 1.5rem; margin: 1rem auto;
106
+ box-shadow: 0 1px 4px rgba(0,0,0,0.05); max-width: 800px; }
107
+ .gradio-container { max-width: 900px; margin: auto; }
108
+ img { border-radius: 0.5rem; }
109
+ #analyze-btn {
110
+ display: block;
111
+ margin: 1rem auto;
112
+ width: 150px;
113
+ background-color: #374151;
114
+ color: white;
115
+ font-weight: bold;
116
+ }
117
+ #metrics-table {
118
+ max-width: 320px;
119
+ margin: 1rem auto;
120
+ }
121
+ .expl-text {
122
+ color: #4B5563;
123
+ font-size: 0.95rem;
124
+ margin-bottom: 1rem;
125
+ }
126
+ """) as demo:
127
+
128
+ # === T铆tulo e introducci贸n ===
129
+ gr.HTML("""
130
+ <section style="text-align:center; padding: 2rem;">
131
+ <h1>DermaScan - Clasificaci贸n de Lesiones</h1>
132
+ <p style="color:#374151; font-size:1.05rem; max-width: 700px; margin:auto;">
133
+ El melanoma es uno de los c谩nceres de piel m谩s agresivos.
134
+ Este sistema utiliza <b>Inteligencia Artificial</b> para apoyar el diagn贸stico,
135
+ mostrando resultados de clasificaci贸n, zonas relevantes (Grad-CAM)
136
+ y m茅tricas geom茅tricas basadas en el criterio ABCDE.
137
+ </p>
138
+ </section>
139
+ """)
140
+
141
+ # === Subir imagen ===
142
+ with gr.Column(elem_classes="section"):
143
+ gr.HTML("<h2>Subir imagen</h2>")
144
+ gr.HTML('<p class="expl-text">Sube una imagen dermatosc贸pica de la lesi贸n para analizarla.</p>')
145
+ img_input = gr.Image(type="pil", label="Imagen de la lesi贸n", elem_id="upload-img")
146
+ run_btn = gr.Button("Analizar", elem_id="analyze-btn")
147
+
148
+ # === Segmentaci贸n ===
149
+ with gr.Column(elem_classes="section"):
150
+ gr.HTML("<h2>Preprocesamiento y Segmentaci贸n</h2>")
151
+ gr.HTML("""
152
+ <p class="expl-text">
153
+ En este paso se realizan varias operaciones:
154
+ <br>- Conversi贸n de canales de color.<br>
155
+ - Eliminaci贸n de pelos.<br>
156
+ - Segmentaci贸n de la lesi贸n.<br>
157
+ </p>
158
+ """)
159
+ img_mask = gr.Image(type="numpy", label="M谩scara Binaria", elem_id="mask-img")
160
+ img_segmented = gr.Image(type="numpy", label="Lesi贸n Segmentada", elem_id="seg-img")
161
+
162
+ # === Grad-CAM ===
163
+ with gr.Column(elem_classes="section"):
164
+ gr.HTML("<h2>Grad-CAM (ZoomNet)</h2>")
165
+ gr.HTML("""
166
+ <p class="expl-text">
167
+ El mapa de calor muestra las zonas con mayor relevancia para el modelo
168
+ al determinar si la lesi贸n es benigna o maligna.
169
+ </p>
170
+ """)
171
+ gradcam_img = gr.Image(type="numpy", label="Mapa de activaci贸n", elem_id="gradcam-img")
172
+
173
+ # === Resultados ===
174
+ with gr.Column(elem_classes="section"):
175
+ gr.HTML("<h2>Resultados del modelo</h2>")
176
+ result_text = gr.Textbox(label="Clasificaci贸n", max_lines=1, interactive=False)
177
+
178
+ gr.HTML("""
179
+ <p class="expl-text">
180
+ M茅tricas geom茅tricas basadas en el criterio <b>ABCDE</b>:
181
+ 煤tiles para analizar lesiones en casos dudosos.
182
+ </p>
183
+ """)
184
+ metrics_table = gr.Dataframe(
185
+ headers=["M茅trica", "Valor"],
186
+ datatype=["str", "number"],
187
+ interactive=False,
188
+ label="M茅tricas calculadas",
189
+ elem_id="metrics-table"
190
+ )
191
+
192
+ # === Conexi贸n bot贸n -> funci贸n ===
193
+ run_btn.click(
194
+ fn=preprocess_and_predict,
195
+ inputs=[img_input],
196
+ outputs=[img_mask, img_segmented, result_text, metrics_table, gradcam_img]
197
+ )
198
 
199
+ # === Lanzar en tema claro ===
200
  if __name__ == "__main__":
201
  demo.launch()