Isoler des objets de segmentation

Après avoir exécuté la tâche de segmentation, il est parfois souhaitable d'extraire les objets isolés des résultats d'inférence. Ce guide fournit une méthode générique pour y parvenir en utilisant le Mode Predict d'Ultralytics.



Watch: How to Remove Background and Isolate Objects with Ultralytics YOLO Segmentation & OpenCV in Python 🚀

Procédure pas à pas

  1. Consulte la section Installation rapide d'Ultralytics pour obtenir un guide rapide sur l'installation des bibliothèques nécessaires.


  2. Charge un modèle et exécute la méthode predict() sur une source.

    from ultralytics import YOLO
    
    # Load a model
    model = YOLO("yolo26n-seg.pt")
    
    # Run inference
    results = model.predict()
Pas d'arguments de prédiction ?

Si aucune source n'est spécifiée, les images d'exemple de la bibliothèque seront utilisées :

'ultralytics/assets/bus.jpg'
'ultralytics/assets/zidane.jpg'

Ceci est utile pour effectuer des tests rapides avec la méthode predict().

Pour plus d'informations sur les modèles de segmentation, visite la page Tâche de segmentation. Pour en savoir plus sur la méthode predict(), consulte la section Mode Predict de la documentation.

***

Maintenant, itère sur les résultats et les contours. Pour les flux de travail qui nécessitent d'enregistrer une image dans un fichier, le base-name de l'image source et le class-label de la détection sont récupérés pour une utilisation ultérieure (optionnel).

```{ .py .annotate }
from pathlib import Path

import numpy as np

# (2) Iterate detection results (helpful for multiple images)
for r in results:
    img = np.copy(r.orig_img)
    img_name = Path(r.path).stem  # source image base-name

    # Iterate each object contour (multiple detections)
    for ci, c in enumerate(r):
        # (1) Get detection class name
        label = c.names[c.boxes.cls.tolist().pop()]
```

1. To learn more about working with detection results, see [Boxes Section for Predict Mode](../modes/predict.md#boxes).
2. To learn more about `predict()` results see [Working with Results for Predict Mode](../modes/predict.md#working-with-results)
Boucle For

Une seule image ne fera itérer la première boucle qu'une seule fois. Une seule image contenant une seule détection fera itérer chaque boucle uniquement une fois.


  1. Commence par générer un masque binaire à partir de l'image source, puis dessine un contour rempli sur le masque. Cela permettra d'isoler l'objet des autres parties de l'image. Un exemple à partir de bus.jpg pour l'un des objets détectés de la classe person est affiché sur la droite.

    Image de masque binaire{ width="240", align="right" }

    import cv2
    
    # Create binary mask
    b_mask = np.zeros(img.shape[:2], np.uint8)
    
    # (1) Extract contour result
    contour = c.masks.xy.pop()
    # (2) Changing the type
    contour = contour.astype(np.int32)
    # (3) Reshaping
    contour = contour.reshape(-1, 1, 2)
    
    # Draw contour onto mask
    _ = cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)
    1. Pour plus d'informations sur c.masks.xy, consulte la section Masques du Mode Predict.

    2. Ici, les valeurs sont converties en np.int32 pour une compatibilité avec la fonction drawContours() d'OpenCV.

    3. La fonction drawContours() d'OpenCV attend que les contours aient une forme de [N, 1, 2]. Développe la section ci-dessous pour plus de détails.

    Expand to understand what is happening when defining the contour variable.

    - `c.masks.xy` :: Provides the coordinates of the mask contour points in the format `(x, y)`. For more details, refer to the [Masks Section from Predict Mode](../modes/predict.md#masks). - `.pop()` :: As `masks.xy` is a list containing a single element, this element is extracted using the `pop()` method. - `.astype(np.int32)` :: Using `masks.xy` will return with a data type of `float32`, but this won't be compatible with the OpenCV `drawContours()` function, so this will change the data type to `int32` for compatibility. - `.reshape(-1, 1, 2)` :: Reformats the data into the required shape of `[N, 1, 2]` where `N` is the number of contour points, with each point represented by a single entry `1`, and the entry is composed of `2` values. The `-1` denotes that the number of values along this dimension is flexible.

    Expand for an explanation of the drawContours() configuration.

    - Encapsulating the `contour` variable within square brackets, `[contour]`, was found to effectively generate the desired contour mask during testing. - The value `-1` specified for the `drawContours()` parameter instructs the function to draw all contours present in the image. - The `tuple` `(255, 255, 255)` represents the color white, which is the desired color for drawing the contour in this binary mask. - The addition of `cv2.FILLED` will color all pixels enclosed by the contour boundary the same, in this case, all enclosed pixels will be white. - See [OpenCV Documentation on `drawContours()`](https://docs.opencv.org/4.8.0/d6/d6e/group__imgproc__draw.html#ga746c0625f1781f1ffc9056259103edbc) for more information.


  2. Ensuite, il existe 2 options pour savoir comment avancer avec l'image à partir de ce point, ainsi qu'une option ultérieure pour chacune d'elles.

    Options d'isolation d'objet

Exemple
# Create 3-channel mask
mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)

# Isolate object with binary mask
isolated = cv2.bitwise_and(mask3ch, img)
Comment cela fonctionne-t-il ?
  • Tout d'abord, le masque binaire est converti d'une image à canal unique vers une image à trois canaux. Cette conversion est nécessaire pour l'étape suivante où le masque et l'image originale sont combinés. Les deux images doivent avoir le même nombre de canaux pour être compatibles avec l'opération de fusion.

  • L'image originale et le masque binaire à trois canaux sont fusionnés à l'aide de la fonction OpenCV bitwise_and(). Cette opération conserve uniquement les valeurs de pixels supérieures à zéro (> 0) des deux images. Comme les pixels du masque sont supérieurs à zéro (> 0) uniquement dans la région du contour, les pixels conservés de l'image originale sont ceux qui se chevauchent avec le contour.

Isoler avec des pixels noirs : sous-options

Image pleine taille

Aucune étape supplémentaire n'est requise si tu conserves l'image en taille réelle.

![Example Full size Isolated Object Image Black Background](https://cdn.jsdelivr.net/gh/ultralytics/assets@main/docs/full-size-isolated-object-black-background.avif){ width=240 }
Example full-size output
Image d'objet rognée

Étapes supplémentaires requises pour rogner l'image afin d'inclure uniquement la région de l'objet.

Exemple d'objet rogné isolé avec fond noir{ align="right" }

# (1) Bounding box coordinates
x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
# Crop image to object region
iso_crop = isolated[y1:y2, x1:x2]
  1. Pour plus d'informations sur les résultats des bounding boxes, consulte la section Boîtes du Mode Predict
Que fait ce code ?
  • L'appel c.boxes.xyxy.cpu().numpy() récupère les boîtes englobantes sous forme de tableau NumPy au format xyxy, où xmin, ymin, xmax et ymax représentent les coordonnées du rectangle de la boîte englobante. Consulte la section Boîtes du Mode Predict pour plus de détails.

  • L'opération squeeze() supprime toutes les dimensions inutiles du tableau NumPy, garantissant qu'il a la forme attendue.

  • La conversion des valeurs de coordonnées à l'aide de .astype(np.int32) change le type de données des coordonnées de la boîte de float32 à int32, les rendant compatibles pour le rognage d'image à l'aide de tranches d'index.

  • Enfin, la région de la boîte englobante est rognée à partir de l'image en utilisant le découpage par index. Les limites sont définies par les coordonnées [ymin:ymax, xmin:xmax] de la boîte englobante de détection.

Que faire si je veux l'objet rogné **y compris** l'arrière-plan ?

Ceci est une fonctionnalité intégrée de la bibliothèque Ultralytics. Consulte l'argument save_crop pour les Arguments d'inférence du Mode Predict pour plus de détails.


  1. Ce que tu fais ensuite dépend entièrement de toi en tant que développeur. Un exemple de base d'une prochaine étape possible (enregistrer l'image dans un fichier pour une utilisation future) est présenté.
    • NOTE : cette étape est optionnelle et peut être ignorée si elle n'est pas nécessaire pour ton cas d'utilisation spécifique.
Exemple d'étape finale
# Save isolated object to file
_ = cv2.imwrite(f"{img_name}_{label}-{ci}.png", iso_crop)
  • Dans cet exemple, img_name est le nom de base du fichier image source, label est le nom de la classe détectée, et ci est l'index de la détection d'objet (dans le cas de multiples instances avec le même nom de classe).

Code d'exemple complet

Ici, toutes les étapes de la section précédente sont combinées en un seul bloc de code. Pour une utilisation répétée, il serait optimal de définir une fonction pour effectuer tout ou partie des commandes contenues dans les boucles for, mais c'est un exercice laissé au lecteur.

from pathlib import Path

import cv2
import numpy as np

from ultralytics import YOLO

m = YOLO("yolo26n-seg.pt")  # (4)!
res = m.predict(source="path/to/image.jpg")  # (3)!

# Iterate detection results (5)
for r in res:
    img = np.copy(r.orig_img)
    img_name = Path(r.path).stem

    # Iterate each object contour (6)
    for ci, c in enumerate(r):
        label = c.names[c.boxes.cls.tolist().pop()]

        b_mask = np.zeros(img.shape[:2], np.uint8)

        # Create contour mask (1)
        contour = c.masks.xy.pop().astype(np.int32).reshape(-1, 1, 2)
        _ = cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)

        # Choose one:

        # OPTION-1: Isolate object with black background
        mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
        isolated = cv2.bitwise_and(mask3ch, img)

        # OPTION-2: Isolate object with transparent background (when saved as PNG)
        isolated = np.dstack([img, b_mask])

        # OPTIONAL: detection crop (from either OPT1 or OPT2)
        x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
        iso_crop = isolated[y1:y2, x1:x2]

        # Add your custom post-processing here (2)
  1. La ligne remplissant contour est combinée en une seule ligne ici, alors qu'elle était divisée en plusieurs lignes ci-dessus.
  2. {==Ce que tu mets ici dépend de toi!==}
  3. Consulte le Mode Predict pour des informations supplémentaires.
  4. Consulte la Tâche de segmentation pour plus d'informations.
  5. En savoir plus sur Travailler avec les résultats
  6. En savoir plus sur les Résultats de masque de segmentation

FAQ

Comment isoler des objets en utilisant Ultralytics YOLO26 pour des tâches de segmentation ?

Pour isoler des objets en utilisant Ultralytics YOLO26, suis ces étapes :

  1. Charger le modèle et exécuter l'inférence :

    from ultralytics import YOLO
    
    model = YOLO("yolo26n-seg.pt")
    results = model.predict(source="path/to/your/image.jpg")
  2. Générer un masque binaire et dessiner des contours :

    import cv2
    import numpy as np
    
    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)
  3. Isoler l'objet à l'aide du masque binaire :

    mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
    isolated = cv2.bitwise_and(mask3ch, img)

Consulte le guide sur le Mode Predict et la Tâche de segmentation pour plus d'informations.

Quelles options sont disponibles pour enregistrer les objets isolés après la segmentation ?

Ultralytics YOLO26 offre deux options principales pour enregistrer des objets isolés :

  1. Avec un arrière-plan noir :

    mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
    isolated = cv2.bitwise_and(mask3ch, img)
  2. Avec un arrière-plan transparent :

    isolated = np.dstack([img, b_mask])

Pour plus de détails, visite la section Mode Predict.

Comment puis-je rogner des objets isolés sur leurs boîtes englobantes en utilisant Ultralytics YOLO26 ?

Pour rogner des objets isolés sur leurs boîtes englobantes :

  1. Récupérer les coordonnées de la boîte englobante :

    x1, y1, x2, y2 = results[0].boxes.xyxy[0].cpu().numpy().astype(np.int32)
  2. Rogner l'image isolée :

    iso_crop = isolated[y1:y2, x1:x2]

Apprends-en plus sur les résultats des boîtes englobantes dans la documentation du Mode Predict.

Pourquoi devrais-je utiliser Ultralytics YOLO26 pour l'isolation d'objets dans les tâches de segmentation ?

Ultralytics YOLO26 fournit :

  • Haute vitesse de détection et de segmentation d'objets en temps réel.
  • Génération précise de boîtes englobantes et de masques pour une isolation précise des objets.
  • Documentation complète et API facile à utiliser pour un développement efficace.

Explore les avantages de l'utilisation de YOLO dans la documentation de la tâche de segmentation.

Puis-je enregistrer des objets isolés en incluant l'arrière-plan en utilisant Ultralytics YOLO26 ?

Oui, il s'agit d'une fonctionnalité intégrée dans Ultralytics YOLO26. Utilise l'argument save_crop dans la méthode predict(). Par exemple :

results = model.predict(source="path/to/your/image.jpg", save_crop=True)

Lis-en plus sur l'argument save_crop dans la section Arguments d'inférence du Mode Predict.

Commentaires