File size: 2,876 Bytes
034b360
 
a448502
8c70b79
034b360
 
67b7135
034b360
67b7135
8c70b79
a448502
 
 
 
 
8c70b79
a448502
 
 
034b360
8c70b79
a448502
 
8c70b79
a448502
 
 
 
 
 
 
 
 
 
 
 
034b360
a448502
 
 
 
 
 
 
034b360
 
a448502
 
 
034b360
a448502
 
 
 
034b360
 
 
a448502
034b360
 
 
 
 
 
 
 
 
 
 
 
 
 
a448502
034b360
 
 
 
 
 
a448502
 
 
034b360
 
 
 
 
 
d54dd15
 
a448502
 
 
034b360
 
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
# app.py
import os
import zipfile
import numpy as np
from PIL import Image, ImageDraw
import gradio as gr
from huggingface_hub import hf_hub_download
from tensorflow.keras.models import load_model
import keras

# -----------------------------
# Configuración del modelo
# -----------------------------
REPO_ID = "nicolasrl/matriculas"       # tu repo en HF
ZIP_FILE = "matriculas_resnetv2.zip"   # archivo zip subido con todo el SavedModel

# -----------------------------
# Función para descargar y cargar modelo
# -----------------------------
def get_model():
    """
    Descarga el modelo en zip desde Hugging Face, lo descomprime
    y lo carga como SavedModel de TensorFlow/Keras.
    """
    tmp_dir = "/tmp/matriculas_resnetv2"
    os.makedirs(tmp_dir, exist_ok=True)

    # Descargar el zip desde HF
    zip_path = hf_hub_download(repo_id=REPO_ID, filename=ZIP_FILE)

    # Descomprimir en carpeta temporal
    with zipfile.ZipFile(zip_path, 'r') as zip_ref:
        zip_ref.extractall(tmp_dir)

    # Habilitar deserialización insegura (si hay Lambda layers)
    keras.config.enable_unsafe_deserialization()

    # Cargar el modelo desde la carpeta descomprimida
    model = load_model(tmp_dir, safe_mode=False)
    return model

# -----------------------------
# Cargar modelo al iniciar app
# -----------------------------
model = get_model()

# -----------------------------
# Función de predicción
# -----------------------------
def predict(img: Image.Image):
    """
    Recibe imagen PIL, realiza inferencia y devuelve imagen
    anotada con la caja y texto con coordenadas.
    """
    pil = img.convert("RGB")
    w, h = pil.size

    # Preprocesamiento igual al usado en entrenamiento
    img_resized = pil.resize((224, 224))
    x = np.array(img_resized).astype("float32") / 255.0
    x = np.expand_dims(x, 0)

    # Inferencia
    pred = model.predict(x)[0]  # [nxmin, nxmax, nymin, nymax]
    nxmin, nxmax, nymin, nymax = pred

    # Convertir coordenadas normalizadas a píxeles
    xmin = int(max(0, nxmin * w))
    xmax = int(min(w, nxmax * w))
    ymin = int(max(0, nymin * h))
    ymax = int(min(h, nymax * h))

    # Dibujar caja
    annotated = pil.copy()
    draw = ImageDraw.Draw(annotated)
    draw.rectangle([xmin, ymin, xmax, ymax], outline="cyan", width=3)

    return annotated, f"{xmin},{ymin},{xmax},{ymax}"

# -----------------------------
# Interfaz Gradio
# -----------------------------
demo = gr.Interface(
    fn=predict,
    inputs=gr.Image(type="pil"),
    outputs=[gr.Image(type="pil"), gr.Textbox()],
    title="Detección de matrículas",
    description="Sube una imagen. El modelo devuelve la caja delimitadora (xmin,ymin,xmax,ymax)."
)

# -----------------------------
# Lanzar app
# -----------------------------
if __name__ == "__main__":
    demo.launch(server_name="0.0.0.0", server_port=7860, enable_queue=True)