Abrir en Colab

Detección de objetos zero-shot con imágenes de ciencia participativa#

La detección de objetos es una herramienta poderosa para encontrar patrones en imágenes. Muchos proyectos de ciencia participativa, como NASA GLOBE e iNaturalist, incluyen fotografías. Podemos utilizar modelos abiertos de detección de objetos para identificar elementos, como animales y plantas, en estas imágenes.

# Instalar las bibliotecas necesarias
!pip install -q transformers pillow matplotlib torch

import requests
from PIL import Image, ImageDraw, ImageFont
import matplotlib.pyplot as plt
import torch
from transformers import pipeline

print("Bibliotecas importadas")
# Cargar el modelo de detección de objetos zero-shot
# OWL-ViT es un transformador de visión entrenado para la detección con vocabulario abierto
print("Cargando el modelo OWL-ViT... Esto puede tardar un momento.")
checkpoint = "google/owlvit-base-patch32"
detector = pipeline(model=checkpoint, task="zero-shot-object-detection")

def load_image(source):
    """Carga una imagen desde una URL o desde un archivo local."""
    try:
        if source.startswith(("http://", "https://")):
            response = requests.get(source, stream=True, timeout=30)
            response.raise_for_status()
            image = Image.open(response.raw)
        else:
            image = Image.open(source)

        return image.convert("RGB")
    except Exception as e:
        print(f"Error al cargar la imagen: {e}")
        return None

def draw_detections(image, predictions, threshold=0.1):
    """
    Dibuja recuadros delimitadores alrededor de los objetos detectados.

    Argumentos:
        image: imagen de PIL
        predictions: lista de diccionarios con las detecciones
        threshold: puntuación mínima de confianza que se mostrará (0-1)
    """
    # Crear una copia de la imagen para dibujar sobre ella
    draw_image = image.copy()
    draw = ImageDraw.Draw(draw_image)

    # Intentar cargar una fuente; usar la predeterminada si no está disponible
    try:
        font = ImageFont.truetype(
            "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
            16
        )
    except Exception:
        font = ImageFont.load_default()

    # Filtrar las predicciones según el umbral de confianza
    filtered_predictions = [
        prediction
        for prediction in predictions
        if prediction["score"] >= threshold
    ]

    # Dibujar cada detección
    for prediction in filtered_predictions:
        box = prediction["box"]
        score = prediction["score"]
        label = prediction["label"]

        # Extraer las coordenadas
        xmin = box["xmin"]
        ymin = box["ymin"]
        xmax = box["xmax"]
        ymax = box["ymax"]

        # Dibujar el recuadro delimitador
        draw.rectangle([xmin, ymin, xmax, ymax], outline="red", width=3)

        # Crear la etiqueta con la puntuación de confianza
        text = f"{label}: {score:.2f}"

        # Dibujar el fondo y el texto de la etiqueta
        text_bbox = draw.textbbox((xmin, ymin), text, font=font)
        draw.rectangle(text_bbox, fill="red")
        draw.text((xmin, ymin), text, fill="white", font=font)

    return draw_image, len(filtered_predictions)

def run_detection(candidates, image_urls, threshold=0.2):
    for idx, source in enumerate(image_urls, 1):
        print(f"\nProcesando imagen {idx}/{len(image_urls)}")
        print(f"Fuente: {source}")

        # Cargar la imagen
        image = load_image(source)
        if image is None:
            continue

        print(f"Tamaño de la imagen: {image.size}")

        # Ejecutar la detección
        print("Detectando objetos...")
        predictions = detector(image, candidate_labels=candidates)

        # Dibujar las detecciones sobre la imagen
        result_image, num_detections = draw_detections(
            image,
            predictions,
            threshold
        )

        # Mostrar los resultados
        print(
            f"- Se encontraron {num_detections} objetos "
            f"(confianza ≥ {threshold})"
        )

        # Mostrar la imagen original y la imagen con detecciones
        fig, axes = plt.subplots(1, 2, figsize=(16, 8))

        axes[0].imshow(image)
        axes[0].set_title(
            "Imagen original",
            fontsize=14,
            fontweight="bold"
        )
        axes[0].axis("off")

        axes[1].imshow(result_image)
        axes[1].set_title(
            f"Detecciones (umbral={threshold})",
            fontsize=14,
            fontweight="bold"
        )
        axes[1].axis("off")

        plt.tight_layout()
        plt.show()

        print("-" * 50)

print("Modelo cargado")

Probemos el modelo con algunas fotografías. Primero, cargaremos una imagen de una abeja de iNaturalist, una plataforma donde cualquier persona puede registrar fotografías y observaciones de la naturaleza. Puedes explorar más fotografías de iNaturalist aquí.

Para obtener la URL, haz clic con el botón derecho sobre una imagen y selecciona Copiar dirección de imagen.

# Objetos candidatos a detectar
# Las etiquetas en inglés suelen producir mejores resultados con este modelo
candidates = [
    "bee"
]

# URL de la imagen que se analizará; puedes agregar varias
image_urls = [
    "https://inaturalist-open-data.s3.amazonaws.com/photos/639462446/large.jpg",
]

# Ajusta este valor para mostrar más o menos detecciones
threshold = 0.1

# Ejecutar la detección de objetos
run_detection(candidates, image_urls, threshold=threshold)

¡El modelo pudo detectar esta abeja con un 74 % de confianza! Ahora probemos una imagen con varios animales. En este caso, analizaremos imágenes de peces.

# Objetos candidatos a detectar
# Las etiquetas en inglés suelen producir mejores resultados con este modelo
candidates = [
    "fish"
]

# URL de las imágenes que se analizarán; puedes agregar varias
image_urls = [
    "https://img.freepik.com/free-photo/koi-fish-swimming-pond_23-2152023678.jpg?semt=ais_hybrid&w=740&q=80",
    "https://images.pexels.com/photos/33855858/pexels-photo-33855858/free-photo-of-vibrant-goldfish-swimming-in-aquarium.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
    "https://inaturalist-open-data.s3.amazonaws.com/photos/639441608/large.jpg"
]

# Ajusta este valor para mostrar más o menos detecciones
threshold = 0.2

# Ejecutar la detección de objetos
run_detection(candidates, image_urls, threshold=threshold)

Exploremos otro ejemplo. ¿Podemos encontrar palmeras y excluir otros tipos de árboles?

# Objetos candidatos a detectar
# Las etiquetas en inglés suelen producir mejores resultados con este modelo
candidates = [
    "palm tree"
]

# URL de las imágenes que se analizarán; puedes agregar varias
image_urls = [
    "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTGCFHamuK-Ojb5oQ-M4wj_zV0ZrI7ysQOF2A&s",
    "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS2B5bF_UoqzH6f3QnBMtNUoUk7WfelIiSIAQ&s",
    "https://img.freepik.com/free-photo/grove-summer_1398-333.jpg"
]

# Ajusta este valor para mostrar más o menos detecciones
threshold = 0.1
run_detection(candidates, image_urls, threshold=threshold)

Para probar tu propio ejemplo, utiliza el siguiente código:

# Objetos candidatos a detectar
# Escribe las etiquetas en inglés para obtener mejores resultados
candidates = [
    "object description in English"
]

# Puedes incluir URL de imágenes o nombres de archivos subidos
image_urls = [
    "URL_DE_LA_IMAGEN",
    "URL_DE_LA_IMAGEN",
    # También puedes subir una imagen haciendo clic en el ícono de carpeta
    # ubicado a la izquierda en Google Colab. Después, incluye aquí el
    # nombre exacto del archivo que subiste.
    "nombre_del_archivo_subido.png"
]

# Ajusta este valor para mostrar más o menos detecciones
# Un umbral más cercano a 1 muestra menos detecciones, pero con mayor confianza
threshold = 0.1

run_detection(candidates, image_urls, threshold=threshold)