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