Overslaan naar inhoud

Segmentatieobjecten isoleren

Na het uitvoeren van de Segmenttaak is het soms wenselijk om de geïsoleerde objecten uit de inferentieresultaten te halen. Deze handleiding geeft een algemeen recept om dit te doen met behulp van demodus Ultralytics Predict.

Voorbeeld van segmentatie van geïsoleerde objecten

Recept doorloop

  1. Begin met de noodzakelijke invoer

    from pathlib import Path
    
    import cv2
    import numpy as np
    from ultralytics import YOLO
    
    Ultralytics Installeer

    Zie het gedeelte Ultralytics Snelstartinstallatie voor een korte handleiding voor het installeren van de benodigde bibliotheken.


  2. Een model laden en uitvoeren predict() methode op een bron.

    from ultralytics import YOLO
    
    # Load a model
    model = YOLO('yolov8n-seg.pt')
    
    # Run inference
    results = model.predict()
    

    Geen voorspelargumenten?

    Zonder een bron op te geven, worden de voorbeeldafbeeldingen uit de bibliotheek gebruikt:

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

    Dit is handig om snel te testen met de predict() methode.

    Ga voor meer informatie over segmentatiemodellen naar de Segment Taak pagina. Voor meer informatie over predict() methode, zie Modus voorspellen sectie van de Documentatie.


  3. Herhaal nu de resultaten en de contouren. Voor workflows die een afbeelding in een bestand willen opslaan, moet de bronafbeelding base-name en de detectie class-label worden opgehaald voor later gebruik (optioneel).

    # (2) Iterate detection results (helpful for multiple images)
    for r in res:
        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. Voor meer informatie over het werken met detectieresultaten, zie Kaders voor de modus Voorspellen.
    2. Voor meer informatie over predict() resultaten zie Werken met resultaten voor de modus Voorspellen
    For-lus

    Een enkele afbeelding zal de eerste lus slechts eenmaal doorlopen. Een enkele afbeelding met slechts één detectie zal elke lus slechts één keer doorlopen.


  4. Begin met het genereren van een binair masker van de bronafbeelding en teken dan een gevulde contour op het masker. Hierdoor wordt het object geïsoleerd van de andere delen van de afbeelding. Een voorbeeld van bus.jpg voor een van de gedetecteerde person klasseobjecten wordt rechts getoond.

    Binaire maskerafbeelding

    # 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. Voor meer informatie over c.masks.xy zie Sectie maskers van voorspelmodus.

    2. Hier worden de waarden in np.int32 voor compatibiliteit met drawContours() functie van OpenCV.

    3. De OpenCV drawContours() functie verwacht dat contouren een vorm hebben van [N, 1, 2] vergroot de sectie hieronder voor meer details.

    Uitbreiden om te begrijpen wat er gebeurt bij het definiëren van de contour variabel.

    • c.masks.xy :: Geeft de coördinaten van de maskercontourpunten in het formaat (x, y). Raadpleeg voor meer informatie de Sectie maskers van voorspelmodus.

    • .pop() :: Als masks.xy een lijst is die één element bevat, wordt dit element geëxtraheerd met de pop() methode.

    • .astype(np.int32) :: gebruiken masks.xy zal retourneren met een gegevenstype van float32maar dit zal niet compatibel zijn met de OpenCV drawContours() functie, dus dit zal het gegevenstype veranderen in int32 voor compatibiliteit.

    • .reshape(-1, 1, 2) :: Formatteert de gegevens in de gewenste vorm van [N, 1, 2] waarbij N het aantal contourpunten, waarbij elk punt wordt weergegeven door een enkele invoer 1en de invoer bestaat uit 2 waarden. De -1 geeft aan dat het aantal waarden langs deze dimensie flexibel is.

    Uitvouwen voor een uitleg van de drawContours() configuratie.

    • Het inkapselen van de contour variabele tussen vierkante haakjes, [contour]bleek tijdens het testen effectief het gewenste contourmasker te genereren.

    • De waarde -1 gespecificeerd voor de drawContours() De parameter instrueert de functie om alle contouren te tekenen die aanwezig zijn in de afbeelding.

    • De tuple (255, 255, 255) staat voor de kleur wit, wat de gewenste kleur is voor het tekenen van de contour in dit binaire masker.

    • De toevoeging van cv2.FILLED zal alle pixels omsloten door de contour hetzelfde kleuren, in dit geval zullen alle omsloten pixels wit zijn.

    • Zie OpenCV Documentatie op drawContours() voor meer informatie.


  5. Vervolgens zijn er 2 opties om vanaf dit punt verder te gaan met de afbeelding en een vervolgoptie voor elke optie.

    Opties voor objectisolatie

    # Create 3-channel mask
    mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
    
    # Isolate object with binary mask
    isolated = cv2.bitwise_and(mask3ch, img)
    
    Hoe werkt dit?
    • Eerst wordt het binaire masker geconverteerd van een eenkanaalsafbeelding naar een driekanaalsafbeelding. Deze conversie is nodig voor de volgende stap waarin het masker en de originele afbeelding worden gecombineerd. Beide afbeeldingen moeten hetzelfde aantal kanalen hebben om compatibel te zijn met de overvloeier.

    • De originele afbeelding en het binaire driekanaalsmasker worden samengevoegd met de OpenCV-functie bitwise_and(). Deze bewerking behoudt alleen pixelwaarden die groter zijn dan nul (> 0) van beide afbeeldingen. Omdat de maskerpixels groter zijn dan nul (> 0) alleen Binnen het contourgebied zijn de pixels die overblijven van de oorspronkelijke afbeelding de pixels die overlappen met de contour.

    Isoleren met zwarte pixels: Subopties

    Afbeelding op ware grootte

    Er zijn geen extra stappen nodig als je een afbeelding op ware grootte bewaart.

    Voorbeeld op ware grootte Geïsoleerde objectafbeelding Zwarte achtergrond
    Voorbeeld uitvoer op ware grootte

    Afbeelding bijgesneden object

    Extra stappen nodig om de afbeelding zo bij te snijden dat alleen het objectgebied eronder valt.

    Voorbeeld uitsnede geïsoleerd object zwarte achtergrond

    # (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. Voor meer informatie over de resultaten van bounding boxen, zie Sectie Boxen van de modus Voorspellen
    Wat doet deze code?
    • De c.boxes.xyxy.cpu().numpy() oproep haalt de begrenzingskaders op als een NumPy array in de xyxy formaat, waarbij xmin, ymin, xmaxen ymax staan voor de coördinaten van de rechthoek van het begrenzingskader. Zie Vakken uit de voorspelmodus voor meer informatie.

    • De squeeze() verwijdert onnodige dimensies uit de NumPy array en zorgt ervoor dat deze de verwachte vorm heeft.

    • De coördinaatwaarden converteren met .astype(np.int32) verandert het gegevenstype van de boxcoördinaten van float32 naar int32waardoor ze geschikt zijn voor het bijsnijden van afbeeldingen met behulp van index slices.

    • Tenslotte wordt het bounding box-gebied uit de afbeelding geknipt met behulp van index slicing. De grenzen worden gedefinieerd door de [ymin:ymax, xmin:xmax] coördinaten van het detectiebegrenzingskader.

    # Isolate object with transparent background (when saved as PNG)
    isolated = np.dstack([img, b_mask])
    
    Hoe werkt dit?
    • De NumPy dstack() functie (matrixstapeling langs de diepte-as) in combinatie met het gegenereerde binaire masker, wordt een afbeelding met vier kanalen gemaakt. Hierdoor zijn alle pixels buiten de objectcontour transparant bij het opslaan als een PNG bestand.

    Isoleren met transparante pixels: Subopties

    Afbeelding op ware grootte

    Er zijn geen extra stappen nodig als je een afbeelding op ware grootte bewaart.

    Voorbeeld op ware grootte Geïsoleerde objectafbeelding zonder achtergrond
    Voorbeeld uitvoer op ware grootte + transparante achtergrond

    Afbeelding bijgesneden object

    Extra stappen nodig om de afbeelding zo bij te snijden dat alleen het objectgebied eronder valt.

    Voorbeeldsnede Geïsoleerd object zonder achtergrond

    # (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. Voor meer informatie over de resultaten van bounding boxen, zie Sectie Boxen van de modus Voorspellen
    Wat doet deze code?
    • Bij gebruik van c.boxes.xyxy.cpu().numpy()worden de begrenzende vakken geretourneerd als een NumPy array, met behulp van de xyxy box coördinaten formaat, die overeenkomen met de punten xmin, ymin, xmax, ymax voor de begrenzende box (rechthoek), zie Vakken uit de voorspelmodus voor meer informatie.

    • toevoegen squeeze() zorgt ervoor dat alle vreemde dimensies uit de NumPy array worden verwijderd.

    • De coördinaatwaarden converteren met .astype(np.int32) verandert het gegevenstype van de boxcoördinaten van float32 naar int32 die compatibel zal zijn bij het bijsnijden van de afbeelding met behulp van index slices.

    • Tot slot wordt het afbeeldingsgebied voor de bounding box bijgesneden met behulp van index slicing, waarbij de grenzen worden ingesteld met behulp van de optie [ymin:ymax, xmin:xmax] coördinaten van het detectiebegrenzingskader.

    Wat als ik het bijgesneden object inclusief de achtergrond wil?

    Dit is een ingebouwde functie voor de Ultralytics bibliotheek. Zie de save_crop argument voor Voorspellen van modus Inferentie Argumenten voor meer informatie.


  6. Wat je daarna doet, kun je als ontwikkelaar helemaal zelf bepalen. Een basisvoorbeeld van een mogelijke volgende stap (de afbeelding opslaan in een bestand voor toekomstig gebruik) wordt getoond.

    • OPMERKING: deze stap is optioneel en kan worden overgeslagen als dit niet nodig is voor jouw specifieke toepassing.
    Voorbeeld Laatste stap
    # Save isolated object to file
    _ = cv2.imwrite(f'{img_name}_{label}-{ci}.png', iso_crop)
    
    • In dit voorbeeld is de img_name is de basisnaam van het bronafbeeldingsbestand, label de gedetecteerde klassenaam is en ci is de index van de objectdetectie (in het geval van meerdere instanties met dezelfde klassenaam).

Volledige voorbeeldcode

Hier worden alle stappen uit de vorige sectie gecombineerd in één blok code. Voor herhaald gebruik zou het optimaal zijn om een functie te definiëren om enkele of alle opdrachten uit te voeren die in de for-lussen, maar dat is een oefening voor de lezer.

from pathlib import Path

import cv2
import numpy as np
from ultralytics import YOLO

m = YOLO('yolov8n-seg.pt')#(4)!
res = m.predict()#(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]

        # TODO your actions go here (2)
  1. De regel die contour is hier samengevoegd tot één regel, waar het hierboven was opgesplitst in meerdere regels.
  2. Wat hier komt is aan jou!
  3. Zie Voorspelmodus voor meer informatie.
  4. Zie Segmenttaak voor meer informatie.
  5. Meer informatie over Werken met resultaten
  6. Meer informatie over de resultaten van het Segmentatiemasker


Aangemaakt 2023-11-27, Bijgewerkt 2024-04-27
Auteurs: glenn-jocher (6), RizwanMunawar (1), Burhan-Q (1)

Reacties