# ----------------------------- # 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