Cómo aislar objetos segmentados con Ultralytics YOLO#
La segmentación de instancias genera una máscara precisa a nivel de píxel para cada objeto detectado, lo que significa que puedes extraer cada objeto de una imagen por separado. Esta guía te muestra cómo convertir los resultados de segmentación de Ultralytics YOLO en objetos aislados mediante el modo de predicción y OpenCV, con un fondo negro uniforme o transparente para guardarlos como PNG.
Watch: How to Remove Background and Isolate Objects with Ultralytics YOLO Segmentation & OpenCV in Python 🚀
¿Por qué aislar objetos segmentados?#
Extraer objetos individuales de una imagen permite realizar diversos flujos de trabajo posteriores:
- Eliminación del fondo para fotografías de productos, catálogos o edición creativa.
- Recortes por objeto para crear conjuntos de datos de clasificación a partir de tus detecciones.
- Procesamiento centrado para que los pasos posteriores, como el OCR, el análisis de color o la medición, vean solo el objeto y no la escena circundante.
- Exportación a PNG transparente para combinar objetos con fondos nuevos.
La receta funciona con cualquier modelo de segmentación de Ultralytics YOLO y sigue cuatro fases: ejecutar la inferencia → extraer cada contorno → aislar el objeto → guardar el resultado.
Ejecutar la inferencia de segmentación#
Instala las bibliotecas necesarias, carga un modelo de segmentación (el sufijo -seg, necesario para generar máscaras) y ejecuta la predicción sobre tu imagen de origen:
from ultralytics import YOLO
# Load a segmentation model
model = YOLO("yolo26n-seg.pt")
# Run inference on a source
results = model.predict(source="path/to/image.jpg")Si llamas a model.predict() sin un source, Ultralytics recurre a las imágenes de ejemplo incluidas con el paquete (bus.jpg y zidane.jpg), lo que resulta práctico para probar rápidamente el flujo de trabajo.
Extraer los contornos de los objetos#
Cada elemento de results corresponde a una imagen, y al iterar sobre un resultado se obtiene una detección cada vez. Para cada detección, copia la imagen original, lee la etiqueta de clase y dibuja el contorno de la máscara del objeto sobre una máscara binaria vacía. La región blanca de esta máscara indica exactamente qué píxeles pertenecen al objeto.
Los fragmentos de código de esta sección y de la siguiente se ejecutan dentro del bucle de detección que aparece abajo; el script completo, listo para copiar y pegar, está en Ejemplo completo.
from pathlib import Path
import cv2
import numpy as np
for r in results:
img = np.copy(r.orig_img)
img_name = Path(r.path).stem # source image base-name
# Iterate each detected object in the image
for ci, c in enumerate(r):
label = c.names[c.boxes.cls.tolist().pop()] # class name
# Build a binary mask and draw the object contour onto it
b_mask = np.zeros(img.shape[:2], np.uint8)
contour = c.masks.xy[0].astype(np.int32).reshape(-1, 1, 2)
cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)c.masks.xy[0]devuelve el contorno de la máscara como coordenadas de puntos(x, y)del objeto en este resultado de detección única..astype(np.int32)convierte los puntos defloat32, quedrawContours()de OpenCV no acepta..reshape(-1, 1, 2)cambia la forma de los puntos al formato[N, 1, 2]que esperadrawContours(), dondeNes el número de puntos del contorno.
Pasar [contour] con el índice -1 dibuja todos los puntos del contorno proporcionado, y cv2.FILLED rellena de blanco cada píxel encerrado.
Aislar el objeto#
Con la máscara binaria preparada, combínala con la imagen original. Hay dos estilos habituales, según cómo quieras que sea el fondo:
Convierte la máscara a tres canales y conserva solo los píxeles que se solapan con el objeto. Todo lo que queda fuera del contorno se vuelve negro:
# Isolate object with a black background
mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
isolated = cv2.bitwise_and(mask3ch, img)
Para conservar solo la región del objeto en lugar de la imagen a tamaño completo, recórtala al cuadro delimitador de la detección:
# Bounding box coordinates
x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
# Crop the isolated image to the object region
iso_crop = isolated[y1:y2, x1:x2]
Esta función está integrada. Pasa save_crop=True a predict() y Ultralytics guardará automáticamente los recortes del cuadro delimitador, sin necesidad de aplicar máscaras.
Guardar el resultado (opcional)#
Tú decides qué hacer con cada objeto aislado. Un paso posterior habitual es escribirlo en el disco para utilizarlo más adelante:
# Save the isolated object to file
cv2.imwrite(f"{img_name}_{label}-{ci}.png", isolated)Aquí, img_name es el nombre base de la imagen de origen, label es el nombre de la clase y ci es el índice de la detección, por lo que las distintas instancias de una misma clase obtienen nombres de archivo únicos. Sustituye isolated por iso_crop si has aplicado el recorte opcional anterior.
Ejemplo completo#
El siguiente script combina todos los pasos en un único bloque ejecutable. Utiliza un fondo negro de forma predeterminada; cambia la única línea marcada a np.dstack([img, b_mask]) para obtener un PNG transparente:
from pathlib import Path
import cv2
import numpy as np
from ultralytics import YOLO
model = YOLO("yolo26n-seg.pt")
results = model.predict(source="path/to/image.jpg")
for r in results:
img = np.copy(r.orig_img)
img_name = Path(r.path).stem
for ci, c in enumerate(r):
label = c.names[c.boxes.cls.tolist().pop()]
# Build a binary mask from the object contour
b_mask = np.zeros(img.shape[:2], np.uint8)
contour = c.masks.xy[0].astype(np.int32).reshape(-1, 1, 2)
cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)
# Isolate the object (black background)
mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
isolated = cv2.bitwise_and(mask3ch, img) # transparent PNG: isolated = np.dstack([img, b_mask])
# Save or add your custom post-processing here
cv2.imwrite(f"{img_name}_{label}-{ci}.png", isolated)
# Optional: crop to the bounding box before saving
# x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
# cv2.imwrite(f"{img_name}_{label}-{ci}.png", isolated[y1:y2, x1:x2])Si vas a utilizarlo repetidamente, encapsula el cuerpo del bucle en una función para poder llamarla con muchas imágenes.
Conclusión#
Ya tienes una receta completa para aislar objetos segmentados con Ultralytics YOLO: ejecuta la inferencia, crea una máscara binaria a partir de cada contorno, extrae el objeto sobre un fondo negro o transparente y, de forma opcional, recórtalo a su cuadro delimitador. Consulta la documentación completa de Tarea de segmentación y del modo de predicción para adaptar el flujo de trabajo a tus propias clases.
Preguntas frecuentes#
Carga un modelo de segmentación, ejecuta la inferencia, crea una máscara binaria a partir del contorno de cada detección y combínala con la imagen original:
import cv2 import numpy as np from ultralytics import YOLO model = YOLO("yolo26n-seg.pt") results = model.predict(source="path/to/your/image.jpg") img = np.copy(results[0].orig_img) b_mask = np.zeros(img.shape[:2], np.uint8) contour = results[0].masks.xy[0].astype(np.int32).reshape(-1, 1, 2) cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED) mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR) isolated = cv2.bitwise_and(mask3ch, img)Consulta el Ejemplo completo para ver el bucle completo por detección.
Hay dos estilos principales. Para un fondo negro, convierte la máscara a tres canales y utiliza
cv2.bitwise_and(). Para un fondo transparente (al guardar como PNG), apila la máscara como un cuarto canal alfa connp.dstack([img, b_mask]). Ambos se muestran en Aislar el objeto.Lee las coordenadas del cuadro delimitador de la detección y recorta la imagen aislada:
x1, y1, x2, y2 = results[0].boxes.xyxy[0].cpu().numpy().astype(np.int32) iso_crop = isolated[y1:y2, x1:x2]Obtén más información sobre los resultados de los cuadros delimitadores en la documentación del modo de predicción.
Ultralytics YOLO proporciona una segmentación de instancias rápida y en tiempo real, con una generación precisa de máscaras y cuadros delimitadores, además de una API sencilla de Python que convierte los resultados de la inferencia en objetos aislados con unas pocas líneas de código de OpenCV.
Sí. Utiliza el argumento
save_cropenpredict()para guardar recortes del cuadro delimitador con su fondo original:results = model.predict(source="path/to/your/image.jpg", save_crop=True)Obtén más información en la sección Argumentos de inferencia del modo de predicción.