AColmenero commited on
Commit
e85e2ac
·
1 Parent(s): 9a42dab
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
- title: D2AS MasterIA
3
- emoji: 👁
4
- colorFrom: indigo
5
- colorTo: green
6
  sdk: gradio
7
  sdk_version: 3.40.1
8
  app_file: app.py
 
1
  ---
2
+ title: MasterIA Unir
3
+ emoji: 🦀
4
+ colorFrom: pink
5
+ colorTo: indigo
6
  sdk: gradio
7
  sdk_version: 3.40.1
8
  app_file: app.py
app.py ADDED
@@ -0,0 +1,362 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ |Función para preprocesar una imagen antes de la predicción------------------------------------------
3
+ | LIBRERIAS |
4
+ |___________________________________________________________________________________________________|
5
+ """
6
+
7
+ # Machine Learning
8
+ import tensorflow as tf # TensorFlow para el aprendizaje automático
9
+ from tensorflow.keras.models import load_model # load_model de Keras para cargar modelos guardados
10
+ from tensorflow.keras.preprocessing.image import img_to_array # img_to_array de Keras para convertir imágenes en arrays
11
+ from tensorflow.keras.applications.mobilenet_v2 import preprocess_input # preprocess_input de Keras para preprocesar imágenes
12
+
13
+ # Procesamiento (imágenes y operaciones)
14
+ import cv2 # OpenCV para el procesamiento de imágenes
15
+ import numpy as np # NumPy para manipulación de matrices y vectores
16
+ import os # Importa el módulo os para interactuar con el sistema operativo
17
+ from revelado.revelado import calculate_ela, calculate_difference_image, apply_auto_contrast, equalize_histogram_color # funciones personalizadas del módulo revelado
18
+
19
+ #Interfaz y aplicación web
20
+ import gradio as gr # Biblioteca Gradio para crear la interfaz
21
+ from gradio.outputs import Image # Clase Image de Gradio para mostrar imágenes en la interfaz
22
+ from flask import Flask, redirect # Flask y redirect de Flask para la aplicación web
23
+ import threading #Threading para ejecutar tareas en hilos separados
24
+ from gradio import Interface
25
+ import matplotlib.pyplot as plt
26
+ from gradio.components import Image as GrImage, Label, Dropdown, Image as GrImageOut
27
+ from tensorflow.keras.preprocessing.image import ImageDataGenerator
28
+ from tensorflow.keras.preprocessing.image import load_img, img_to_array
29
+ from tensorflow.keras.applications.mobilenet import preprocess_input
30
+ #Mapa de calor
31
+ from PIL import Image
32
+ import numpy as np
33
+ from tf_keras_vis.gradcam import GradcamPlusPlus
34
+ from tf_keras_vis.utils.model_modifiers import ReplaceToLinear
35
+ from tf_keras_vis.utils import normalize
36
+
37
+ #_______________________________________________
38
+ # Importar la clase Flask de Flask para la aplicación web
39
+ app = Flask(__name__)
40
+
41
+ # Título y descripción de la interfaz
42
+ title = "Master Inteligencia Artificial. EdenAIs."
43
+ description = "Una aplicación para realizar predicciones sobre imágenes"
44
+
45
+ # Cargar el modelo guardado
46
+ model_clase_unica = load_model("model.h5")
47
+ model_dos_clases = load_model("paper.h5")
48
+
49
+
50
+ """
51
+ |Función para preprocesar una imagen antes de la predicción------------------------------------------
52
+ | FUNCIONES |
53
+ |___________________________________________________________________________________________________|
54
+ """
55
+
56
+
57
+ # Función para preprocesar una imagen antes de la predicción
58
+ def preprocess_image(image):
59
+ """
60
+ Tipo de función: Preprocesamiento de imagen
61
+ Parámetros de entrada: image (objeto imagen)
62
+ Parámetros de salida: imagen_preprocesada (arreglo numpy)
63
+ Descripción: Convierte una imagen en un arreglo numpy, expande las dimensiones
64
+ y aplica preprocesamiento necesario para el modelo.
65
+ """
66
+ # Convertir la imagen en un arreglo numpy
67
+ image_array = img_to_array(image)
68
+
69
+ # Expandir las dimensiones del arreglo para que coincida con la entrada esperada por el modelo
70
+ image_array = np.expand_dims(image_array, axis=0)
71
+
72
+ # Preprocesar la imagen
73
+ imagen_preprocesada = preprocess_input(image_array)
74
+
75
+ return imagen_preprocesada
76
+
77
+
78
+ """
79
+ |Función para guardar la imagen original en la carpeta de entrada------------------------------------
80
+ | FUNCIONES |
81
+ |___________________________________________________________________________________________________|
82
+ """
83
+
84
+ def guardar_imagen_original(imagen, input_folder):
85
+ """
86
+ Tipo de función: Guardar imagen
87
+ Parámetros de entrada: imagen (objeto imagen), input_folder (ruta de la carpeta de entrada)
88
+ Parámetros de salida: Ninguno
89
+ Descripción: Guarda la imagen original en la carpeta de entrada con la máxima calidad.
90
+ """
91
+ # Obtener la extensión de archivo original de la imagen
92
+ filename = "original_image.jpg"
93
+
94
+ # Guardar la imagen en la carpeta de entrada con la máxima calidad
95
+ cv2.imwrite(os.path.join(input_folder, filename), imagen, [cv2.IMWRITE_JPEG_QUALITY, 100])
96
+
97
+
98
+ """
99
+ |Función para realizar predicciones sobre una imagenes-----------------------------------------------
100
+ | FUNCION |
101
+ |___________________________________________________________________________________________________|
102
+ """
103
+ #Función para crear el mapa de calor para una clase
104
+ def generate_heatmap(original_image, processed_image, model):
105
+ # Convert the original image to the required format
106
+ original_image_color = Image.fromarray(cv2.cvtColor(original_image, cv2.COLOR_BGR2RGBA)).resize((300, 300))
107
+ original_image_gray = original_image_color.convert("L").convert("RGBA")
108
+
109
+ # Prepare the processed image
110
+ processed_image_resized = cv2.resize(processed_image, (300, 300))
111
+ processed_image_preprocessed = preprocess_image(processed_image_resized)
112
+ # Define the scoring function for the detected class
113
+ def score_for_class(output):
114
+ return output[:, 0] # Score for the detected class
115
+ # Get the predicted probabilities
116
+ probabilities = model.predict(processed_image_preprocessed)[0]
117
+ percentage_class_1 = int(probabilities[0] * 100)
118
+ percentage_class_0 = 100 - percentage_class_1
119
+
120
+ # Create an instance of GradcamPlusPlus
121
+
122
+ gradcam = GradcamPlusPlus(model, model_modifier=ReplaceToLinear(), clone=True)
123
+
124
+
125
+ # Get the Grad-CAM heatmap for the detected class
126
+
127
+ cam_class = gradcam(score_for_class, processed_image_preprocessed) # Use preprocessed image
128
+ cam_class = normalize(cam_class)
129
+
130
+ # Reduce the heatmap dimensionality to 2D and scale to 8-bit valueçs
131
+ cam_class = np.uint8(255 * np.squeeze(cam_class))
132
+
133
+ # Save the heatmap and load as an RGBA image
134
+ plt.imsave('temporal.png', cam_class)
135
+ cam_image = Image.open('temporal.png').convert("RGBA")
136
+
137
+ # Superimpose the heatmap on the original grayscale image
138
+ superimposed_image_class = Image.blend(original_image_gray, cam_image, alpha=0.5)
139
+ # Tamaño final deseado
140
+ final_height, final_width = 300, 300
141
+ # Concatenate the original image, processed image, and heatmaps
142
+ # Redimensionar todas las imágenes a la misma altura
143
+ # Convertir la imagen PIL a una matriz NumPy
144
+ original_image_color_array = np.array(original_image_color)
145
+
146
+ if original_image_color_array.shape[2] == 4:
147
+ original_image_color_array = cv2.cvtColor(original_image_color_array, cv2.COLOR_RGBA2RGB)
148
+
149
+
150
+ processed_image_array = np.array(processed_image)
151
+
152
+ superimposed_image_class_array = np.array(superimposed_image_class)
153
+ if superimposed_image_class_array.shape[2] == 4:
154
+ superimposed_image_class_array = cv2.cvtColor(superimposed_image_class_array, cv2.COLOR_RGBA2RGB)
155
+
156
+ # Redimensionar todas las imágenes a las mismas dimensiones
157
+ original_image_color_resized = cv2.resize(original_image_color_array, (final_width, final_height))
158
+ processed_image_resized = cv2.resize(processed_image_array, (final_width, final_height))
159
+ superimposed_image_class_resized = cv2.resize(superimposed_image_class_array, (final_width, final_height))
160
+
161
+ # Concatenar las imágenes redimensionadas
162
+ final_image = np.hstack([original_image_color_resized, processed_image_resized, superimposed_image_class_resized])
163
+ # Verificar la imagen procesada
164
+ print("Processed Image Resized Shape:", processed_image_resized.shape)
165
+ # Verificar el modelo
166
+ print("Model Summary:", model.summary())
167
+
168
+ def score_for_class(output):
169
+ score = output[:, 0] # Score for the detected class
170
+ print("Score Shape:", score.shape)
171
+ return score
172
+
173
+ # Return the final concatenated image
174
+ return final_image
175
+
176
+ def cargar_y_preprocesar_imagen(imagen_path, target_size=(300, 300)):
177
+ # Crear una instancia de ImageDataGenerator con las mismas configuracion para el conjunto de entrenamiento
178
+ datagen = ImageDataGenerator(rescale=1.0/255.)
179
+
180
+ # Cargar la imagen
181
+ img = load_img(imagen_path, target_size=target_size)
182
+
183
+ # Convertir la imagen a un array y expandimos las dimensiones para que pueda ser procesada por el ImageDataGenerator
184
+ img = img_to_array(img)
185
+ img = np.expand_dims(img, axis=0)
186
+
187
+ # Usar el ImageDataGenerator para procesar la imagen
188
+ img = datagen.flow(img, batch_size=1)
189
+
190
+ # El ImageDataGenerator retorna un generador, así que usamos next() para obtener la imagen procesada
191
+ img = next(img)
192
+
193
+ # Devolver la imagen procesada
194
+ return img[0]
195
+ #Generamos el mapa de calor para dos clases
196
+ def generate_heatmap_2_classes(original_image, processed_image, model):
197
+ # Convertir la imagen original al formato requerido y redimensionar
198
+ # original_image_color = Image.fromarray(cv2.cvtColor(original_image, cv2.COLOR_BGR2RGBA)).resize((300, 300))
199
+ original = Image.open("img.png").resize((300, 300)).convert("RGBA")
200
+ original_image_color = Image.open("img.png").resize((300, 300)).convert("RGBA")
201
+
202
+ # Leer la imagen procesada desde el archivo "img.png"
203
+ processed_image = cargar_y_preprocesar_imagen("img.png")
204
+ image = np.expand_dims(processed_image, axis=0) # Añade una dimensión extra para el batch
205
+
206
+ # Obtén las probabilidades de pertenencia a cada clase
207
+ probabilities = model.predict(image)[0]
208
+
209
+ # Crear una instancia de GradcamPlusPlus
210
+ gradcam = GradcamPlusPlus(model, model_modifier=ReplaceToLinear(), clone=True)
211
+ # Obtén las probabilidades de pertenencia a cada clase
212
+ probabilities = model.predict(image)[0]
213
+ percentage_human = int(probabilities[0] * 100)
214
+ percentage_synthetic = int(probabilities[1] * 100)
215
+
216
+ # Definir funciones de puntuación para ambas clases
217
+ def score_for_human(output):
218
+ return output[:, 0] # Puntuación para la clase "humana"
219
+
220
+ def score_for_synthetic(output):
221
+ return output[:, 1] # Puntuación para la clase "sintética"
222
+
223
+ # Obtén los mapas de calor de Grad-CAM para cada clase
224
+ cam_human = gradcam(score_for_human, image)
225
+ cam_human = normalize(cam_human)
226
+ cam_synthetic = gradcam(score_for_synthetic, image)
227
+ cam_synthetic = normalize(cam_synthetic)
228
+
229
+ # Reduce la dimensionalidad de los mapas de calor a 2D y escálalos a valores de 8 bits
230
+ cam_human = np.uint8(255 * np.squeeze(cam_human))
231
+ cam_synthetic = np.uint8(255 * np.squeeze(cam_synthetic))
232
+
233
+ images_combined = [original_image_color]
234
+ for cam in [cam_human, cam_synthetic]:
235
+ # Guardar el mapa de calor
236
+ plt.imsave('temporal.png', cam)
237
+
238
+ # Cargar el mapa de calor y convertirlo a RGBA
239
+ cam_image = Image.open('temporal.png').convert("RGBA")
240
+
241
+ # Superponer el mapa de calor a la imagen original
242
+ superimposed_image = Image.blend(original, cam_image, alpha=0.5)
243
+
244
+ # Guardar la imagen en la lista de imágenes a combinarse
245
+ images_combined.append(superimposed_image)
246
+
247
+ # Concatenar las imágenes y guardar la imagen final
248
+ final_image = Image.fromarray(np.hstack([np.array(im) for im in images_combined]))
249
+
250
+ return final_image
251
+
252
+ def hacer_predicciones(modelo_seleccionado, imagen):
253
+ """
254
+ Tipo de función: Predicción
255
+ Parámetros de entrada: imagen (objeto imagen)
256
+ Parámetros de salida: diccionario de predicciones, imagen procesada (objeto imagen)
257
+ Descripción: Realiza predicciones sobre la imagen utilizando el modelo cargado.
258
+ Devuelve un diccionario con las probabilidades de cada clase y la imagen procesada.
259
+ """
260
+ if modelo_seleccionado == "Modelo 1 Clase":
261
+ model = model_clase_unica
262
+ else:
263
+ model = model_dos_clases
264
+
265
+ print(modelo_seleccionado)
266
+
267
+ original_image = cv2.cvtColor(imagen, cv2.COLOR_RGB2BGR)
268
+
269
+ num = 1
270
+ difference_image = calculate_difference_image(imagen, num)
271
+ difference_image2 = apply_auto_contrast(difference_image)
272
+ cv2.imwrite("img.png", difference_image2)
273
+ processed_image = cv2.imread("img.png")
274
+ imagen_resized = cv2.resize(processed_image, (300, 300))
275
+ imagen_preprocesada = preprocess_image(imagen_resized)
276
+
277
+ if modelo_seleccionado == "Modelo 1 Clase":
278
+ predicciones = model.predict(imagen_preprocesada).tolist()[0]
279
+ probabilidad_clase_1 = predicciones[0]
280
+ probabilidad_clase_0 = 1 - probabilidad_clase_1
281
+ final_image = generate_heatmap(original_image, processed_image, model)
282
+ else:
283
+ # Usar la función cargar_y_preprocesar_imagen para el preprocesamiento correcto
284
+ #processed_image_preprocessed = cargar_y_preprocesar_imagen("img.jpg")
285
+ gradcam = GradcamPlusPlus(model, model_modifier=ReplaceToLinear(), clone=True)
286
+ imagen_path = "img.png"
287
+ # Convertir la imagen PIL en una matriz NumPy
288
+ imagen = cargar_y_preprocesar_imagen(imagen_path)
289
+ image = np.expand_dims(imagen, axis=0) # Añade una dimensión extra para el batch
290
+
291
+ probabilities = model.predict(image)[0]
292
+ print (probabilities)
293
+ probabilidad_clase_0 = int(probabilities[0] * 100)
294
+ probabilidad_clase_1 = int(probabilities[1] * 100)
295
+ predicted_label = np.argmax(probabilities)
296
+ print(predicted_label)
297
+
298
+ def score_for_human(output):
299
+ return output[:, 0]
300
+
301
+ def score_for_synthetic(output):
302
+ return output[:, 1]
303
+
304
+ gradcam = GradcamPlusPlus(model, model_modifier=ReplaceToLinear(), clone=True)
305
+ cams = [gradcam(score_func, image) for score_func in [score_for_human, score_for_synthetic]]
306
+ cams = [normalize(cam) for cam in cams]
307
+ cams = [np.uint8(255 * np.squeeze(cam)) for cam in cams]
308
+ # Convertir la imagen PIL a una matriz NumPy
309
+
310
+
311
+ final_image = generate_heatmap_2_classes(original_image, image, model)
312
+
313
+ return {"Arte Manual": probabilidad_clase_0/100, "Arte Sintetico": probabilidad_clase_1/100}, final_image
314
+ """
315
+ |Función para generar gradio en un hilo separado----------------------------------------------------
316
+ | FUNCIONES |
317
+ |___________________________________________________________________________________________________|
318
+ """
319
+
320
+ def run_gradio():
321
+ """
322
+ Tipo de función: Ejecución Gradio
323
+ Parámetros de entrada: Ninguno
324
+ Parámetros de salida: Ninguno
325
+ Descripción: Ejecuta la interfaz Gradio en un hilo separado.
326
+ """
327
+ output = iface.process([imagen]) # Ejecutar el procesamiento de la imagen
328
+ predicciones = output[0]
329
+ final_image = output[1]
330
+
331
+ # Guardar la imagen en una ubicación accesible
332
+ cv2.imwrite("output_img.jpg", final_image)
333
+ #___________________________________________________________________________________________________
334
+
335
+ # Crear una entrada de imagen en Gradio
336
+ im = GrImage(shape=(None, None), image_mode='RGB', invert_colors=False, source="upload")
337
+ model_selector = Dropdown(choices=["Modelo 1 Clase", "Modelo 2 Clases"], label="Selecciona un modelo")
338
+
339
+ # Crear una interfaz de Gradio con una entrada de imagen
340
+ iface = Interface(
341
+ fn=hacer_predicciones,
342
+ inputs=[model_selector, im],
343
+ outputs=[Label(), GrImageOut(type="numpy")],
344
+ title=title,
345
+ description=description,
346
+ allow_flagging="never"
347
+ )
348
+
349
+ # Lanzar la aplicación Gradio en un hilo separado
350
+ threading.Thread(target=run_gradio).start()
351
+
352
+ # Lanzar la interfaz Gradio
353
+ iface.launch(share=False)
354
+
355
+ # Definir la función de ruta en Flask
356
+ @app.route('/')
357
+ def index():
358
+ return redirect(iface.launch(share=True))
359
+
360
+ # Ejecutar la aplicación Flask
361
+ if __name__ == '__main__':
362
+ app.run()
model.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b46ef335d599ad864fa38d1dc11bab6d46eff7b7ee9c15da9e550e0cf93d8fe8
3
+ size 25106800
paper.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6a5ac1775bca55bfda417b01475b931648d1feceb17c9da0087a27ecc9803e50
3
+ size 49603640
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ Flask==2.2.5
2
+ huggingface-hub==0.15.1
3
+ keras==2.11.0
4
+ opencv-python==4.8.0.74
5
+ Pillow==9.3.0
6
+ tensorflow==2.11.0
7
+ transformers==4.30.2
8
+ matplotlib
9
+ numpy
10
+ tf-keras-vis=0.8.5
revelado/__pycache__/revelado.cpython-310.pyc ADDED
Binary file (2.48 kB). View file
 
revelado/__pycache__/revelado.cpython-37.pyc ADDED
Binary file (2.46 kB). View file
 
revelado/__pycache__/revelado.cpython-39.pyc ADDED
Binary file (2.48 kB). View file
 
revelado/revelado.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import cv2 as cv2
3
+ import numpy as np
4
+ from PIL import Image
5
+ from io import BytesIO
6
+ from pylab import *
7
+ import re
8
+ from PIL import Image, ImageChops, ImageEnhance
9
+
10
+ def convert_to_ela_image(filename, quality=90):
11
+ im = Image.open(filename).convert('RGB')
12
+ resaved_im = im
13
+ ela_im = ImageChops.difference(im, resaved_im)
14
+ extrema = ela_im.getextrema()
15
+ max_diff = max([ex[1] for ex in extrema])
16
+ if max_diff == 0:
17
+ max_diff = 1
18
+ scale = 255.0 / max_diff
19
+
20
+ ela_im = ImageEnhance.Brightness(ela_im).enhance(scale)
21
+ return ela_im
22
+ def calculate_ela(original_image, quality=90):
23
+
24
+ # Comprimir y descomprimir la imagen
25
+ buffer = BytesIO()
26
+ Image.fromarray(original_image).save(buffer, format="JPEG", quality=quality)
27
+ compressed_image = np.array(Image.open(buffer))
28
+
29
+ # Calcular la diferencia absoluta
30
+ ela_image = cv2.absdiff(original_image, compressed_image)
31
+
32
+ # Escalar las diferencias para mejorar la visibilidad
33
+ ela_image = cv2.normalize(ela_image, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
34
+
35
+ return ela_image
36
+
37
+ def calculate_difference_image(original_image, n):
38
+
39
+ ela_image = calculate_ela(original_image)
40
+ auto_contrast_image = apply_auto_contrast(original_image)
41
+ difference_image = cv2.absdiff(original_image, auto_contrast_image)
42
+ difference_image = cv2.absdiff(difference_image, ela_image)
43
+ return difference_image
44
+
45
+ def apply_auto_contrast(image, clip_limit=2.0, tile_grid_size=(8, 8)):
46
+ channels = cv2.split(image)
47
+ clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=tile_grid_size)
48
+ contrast_enhanced_channels = [clahe.apply(channel) for channel in channels]
49
+ contrast_enhanced_image = cv2.merge(contrast_enhanced_channels)
50
+ return contrast_enhanced_image
51
+
52
+ def equalize_histogram_color(image):
53
+ channels = cv2.split(image)
54
+ equalized_channels = [cv2.equalizeHist(channel) for channel in channels]
55
+ equalized_image = cv2.merge(equalized_channels)
56
+ return equalized_image