File size: 5,260 Bytes
1ed9ed3
 
 
ed212f9
1189eac
1ed9ed3
1189eac
1ed9ed3
 
 
 
 
 
 
c1eacec
 
1ed9ed3
c1eacec
 
1189eac
1ed9ed3
1189eac
c1eacec
 
 
1189eac
1ed9ed3
1189eac
c1eacec
d80b7b4
1ed9ed3
 
 
d80b7b4
1ed9ed3
d80b7b4
1ed9ed3
1189eac
c1eacec
1ed9ed3
1189eac
c1eacec
 
1ed9ed3
 
ed212f9
 
 
c1eacec
d80b7b4
 
 
 
1ed9ed3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d80b7b4
1ed9ed3
d80b7b4
 
1ed9ed3
65cd5c5
1ed9ed3
 
c1eacec
1189eac
1ed9ed3
1189eac
ed212f9
d80b7b4
1ed9ed3
 
 
d80b7b4
c1eacec
d80b7b4
1ed9ed3
 
 
d80b7b4
1ed9ed3
d80b7b4
1ed9ed3
 
 
 
c1eacec
1ed9ed3
c1eacec
1189eac
1ed9ed3
1189eac
ed212f9
 
 
1189eac
1ed9ed3
1189eac
1ed9ed3
 
 
 
 
 
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
# -----------------------------
# app.py - Detección de objetos con DETR y Gradio (imagen + datos)
# -----------------------------

# -----------------------------
# Librerías utilizadas y justificación
# -----------------------------
# transformers: permite usar modelos preentrenados como DETR para detección de objetos.
# DetrImageProcessor: preprocesa imágenes para que DETR las interprete correctamente.
# DetrForObjectDetection: modelo DETR preentrenado para detectar objetos en imágenes.
# torch: cálculos con tensores para inferencia con PyTorch.
# PIL.Image y ImageDraw: manipulación de imágenes y dibujo de cajas y etiquetas.
# gradio: crear interfaces web interactivas de manera sencilla.

from transformers import DetrImageProcessor, DetrForObjectDetection
import torch
from PIL import Image, ImageDraw, ImageFont
import gradio as gr

# -----------------------------
# Cargar modelo preentrenado
# -----------------------------
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")

# -----------------------------
# Función de detección
# -----------------------------
def detect_objects(image):
    """
    Detecta objetos en la imagen y retorna:
    - Imagen con cajas y etiquetas
    - Texto con los objetos detectados y coordenadas
    """
    width, height = image.size

    # Preprocesamiento
    inputs = processor(images=image, return_tensors="pt", padding=True)

    # Inferencia
    with torch.no_grad():
        outputs = model(**inputs)

    # Postprocesamiento
    target_sizes = torch.tensor([[height, width]])
    results = processor.post_process_object_detection(
        outputs, target_sizes=target_sizes, threshold=0.9
    )[0]

    labels = results["labels"]
    scores = results["scores"]
    boxes = results["boxes"]

    # -----------------------------
    # Preparar la imagen con detecciones
    # -----------------------------
    image_drawn = image.copy()
    draw = ImageDraw.Draw(image_drawn)
    try:
        font = ImageFont.truetype("arial.ttf", 16)
    except:
        font = ImageFont.load_default()

    for score, label, box in zip(scores, labels, boxes):
        box = [float(b) for b in box]

        # Ajustar coordenadas dentro de la imagen
        box[0] = max(0, min(box[0], width))
        box[1] = max(0, min(box[1], height))
        box[2] = max(0, min(box[2], width))
        box[3] = max(0, min(box[3], height))

        # Dibujar caja roja
        draw.rectangle(box, outline="red", width=3)

        # Preparar etiqueta con margen y fondo blanco
        label_text = f"{label} {score:.2f}"
        text_width, text_height = draw.textsize(label_text, font=font)
        text_padding = 4  # margen en pixeles

        # Determinar posición de la etiqueta
        text_x0 = box[0]
        text_y0 = max(0, box[1] - text_height - 2*text_padding)
        text_x1 = text_x0 + text_width + 2*text_padding
        text_y1 = text_y0 + text_height + 2*text_padding

        # Fondo blanco para la etiqueta
        draw.rectangle([text_x0, text_y0, text_x1, text_y1], fill="white")
        # Texto en negro encima del fondo blanco
        draw.text((text_x0 + text_padding, text_y0 + text_padding), label_text, fill="black", font=font)

    # -----------------------------
    # Preparar texto de resultados
    # -----------------------------
    detected_objects_text = []
    for score, label, box in zip(scores, labels, boxes):
        detected_objects_text.append(
            f"Objeto: {label}, Score: {score:.2f}, Box: {box.tolist()}"
        )
    detected_objects_text = "\n".join(detected_objects_text)

    # Retornar: (imagen procesada, resultados en texto)
    return image_drawn, detected_objects_text

# -----------------------------
# Crear interfaz con Gradio
# -----------------------------
def create_interface():
    """
    Interfaz con dos cuadros:
    - Imagen con detección visual
    - Texto con coordenadas y scores
    """
    interface = gr.Interface(
        fn=detect_objects,
        inputs=gr.Image(type="pil"),
        outputs=[gr.Image(type="pil", label="Imagen con Detección"),
                 gr.Textbox(label="Resultados (datos)")],
        live=True,
        title="Detección de Objetos con DETR",
        description=(
            "Sube una imagen y obtén la detección de objetos. "
            "El primer cuadro muestra la imagen con cajas rojas y etiquetas (ahora con fondo blanco). "
            "El segundo cuadro muestra los datos: objetos detectados, scores y coordenadas."
        )
    )
    interface.launch()

# -----------------------------
# Ejecutar la aplicación
# -----------------------------
if __name__ == "__main__":
    create_interface()

# -----------------------------
# Justificaciones y decisiones
# -----------------------------
# 1. Separar imagen y datos mejora la visualización y comprensión.
# 2. Fondo blanco en etiquetas evita que el texto quede recortado o sobre fondo rojo/imagen.
# 3. text_padding asegura un margen entre el borde del recuadro y el texto.
# 4. threshold=0.9 evita falsos positivos y mantiene solo predicciones confiables.
# 5. PIL.ImageDraw se usa para dibujar cajas y etiquetas sin modificar la imag