Zum Inhalt springen

Isolierung von Segmentierungsobjekten

Nach der Durchf├╝hrung der Segmentaufgabe ist es manchmal w├╝nschenswert, die isolierten Objekte aus den Schlussfolgerungsergebnissen zu extrahieren. In diesem Leitfaden findest du ein allgemeines Rezept, wie du dies mit dem Ultralytics Predict Mode erreichen kannst.

Beispiel f├╝r die Segmentierung isolierter Objekte

Rezeptdurchlauf

  1. See the Ultralytics Quickstart Installation section for a quick walkthrough on installing the required libraries.


  2. Ein Modell laden und ausf├╝hren predict() Methode auf eine Quelle.

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

    Keine Vorhersage-Argumente?

    Wenn du keine Quelle angibst, werden die Beispielbilder aus der Bibliothek verwendet:

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

    Dies ist hilfreich f├╝r schnelle Tests mit dem predict() Methode.

    Weitere Informationen ├╝ber Segmentierungsmodelle findest du auf der Segment Aufgabe Seite. Um mehr zu erfahren ├╝ber predict() Methode, siehe Modus vorhersagen Abschnitt der Dokumentation.


  3. Iteriere nun ├╝ber die Ergebnisse und die Konturen. F├╝r Workflows, die ein Bild in einer Datei speichern wollen, muss das Quellbild base-name und die Erkennung class-label zur sp├Ąteren Verwendung abgerufen werden (optional).

    from pathlib import Path
    
    import numpy as np
    
    # (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. Mehr ├╝ber die Arbeit mit den Erkennungsergebnissen erf├Ąhrst du im Abschnitt Boxen f├╝r den Vorhersagemodus.
    2. Um mehr zu erfahren ├╝ber predict() Ergebnisse siehe Arbeiten mit Ergebnissen f├╝r den Vorhersagemodus
    For-Schleife

    Bei einem einzelnen Bild wird die erste Schleife nur einmal durchlaufen. Bei einem einzelnen Bild mit nur einer Erkennung wird jede Schleife nur einmal durchlaufen.


  4. Beginne mit der Erstellung einer bin├Ąren Maske aus dem Quellbild und zeichne dann eine gef├╝llte Kontur auf die Maske. So kann das Objekt von den anderen Teilen des Bildes isoliert werden. Ein Beispiel aus bus.jpg f├╝r eine der erkannten person Klassenobjekte ist rechts abgebildet.

    Bin├Ąres Maskenbild

    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. F├╝r weitere Informationen ├╝ber c.masks.xy siehe Masken Abschnitt aus dem Vorhersagemodus.

    2. Hier werden die Werte in np.int32 f├╝r die Kompatibilit├Ąt mit drawContours() Funktion von OpenCV.

    3. Die OpenCV drawContours() Funktion erwartet, dass die Konturen eine Form von [N, 1, 2] Abschnitt unten f├╝r weitere Details erweitern.

    Erweitern Sie, um zu verstehen, was passiert, wenn Sie die contour variabel.

    • c.masks.xy :: Liefert die Koordinaten der Maskenkonturpunkte im Format (x, y). Weitere Einzelheiten findest du in der Masken Abschnitt aus dem Vorhersagemodus.

    • .pop() :: As masks.xy eine Liste ist, die ein einzelnes Element enth├Ąlt, wird dieses Element mit der Methode pop() Methode.

    • .astype(np.int32) :: Verwendung von masks.xy wird mit einem Datentyp von float32aber das ist nicht kompatibel mit der OpenCV drawContours() Funktion, also wird der Datentyp in int32 f├╝r Kompatibilit├Ąt.

    • .reshape(-1, 1, 2) :: Formatiert die Daten in die gew├╝nschte Form von [N, 1, 2] wo N ist die Anzahl der Konturpunkte, wobei jeder Punkt durch einen einzelnen Eintrag repr├Ąsentiert wird 1und der Eintrag besteht aus 2 Werte. Die -1 bedeutet, dass die Anzahl der Werte entlang dieser Dimension flexibel ist.

    Erweitern Sie f├╝r eine Erkl├Ąrung der drawContours() Konfiguration.

    • Die Verkapselung der contour Variable in eckigen Klammern, [contour]wurde bei den Tests festgestellt, dass sie die gew├╝nschte Konturenmaske effektiv erzeugt.

    • Der Wert -1 angegeben f├╝r die drawContours() Parameter weist die Funktion an, alle im Bild vorhandenen Konturen zu zeichnen.

    • Die tuple (255, 255, 255) steht f├╝r die Farbe Wei├č, die die gew├╝nschte Farbe zum Zeichnen der Kontur in dieser bin├Ąren Maske ist.

    • Der Zusatz von cv2.FILLED f├Ąrbt alle von der Konturbegrenzung eingeschlossenen Pixel gleich, in diesem Fall sind alle eingeschlossenen Pixel wei├č.

    • Siehe OpenCV Dokumentation auf drawContours() f├╝r weitere Informationen.


  5. Als N├Ąchstes gibt es 2 Optionen, wie du mit dem Bild von diesem Punkt aus weitermachen kannst, und eine weitere Option f├╝r jede.

    Optionen zur Objektisolierung

    # Create 3-channel mask
    mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
    
    # Isolate object with binary mask
    isolated = cv2.bitwise_and(mask3ch, img)
    
    Wie funktioniert das?
    • Zun├Ąchst wird die bin├Ąre Maske von einem einkanaligen Bild in ein dreikanaliges Bild umgewandelt. Diese Umwandlung ist f├╝r den nachfolgenden Schritt notwendig, bei dem die Maske und das Originalbild kombiniert werden. Beide Bilder m├╝ssen die gleiche Anzahl von Kan├Ąlen haben, damit sie mit dem ├ťberblendvorgang kompatibel sind.

    • Das Originalbild und die Dreikanal-Bin├Ąrmaske werden mit der OpenCV-Funktion zusammengef├╝hrt bitwise_and(). Bei diesem Vorgang bleiben die nur Pixelwerte, die gr├Â├čer als Null sind (> 0) aus beiden Bildern. Da die Pixel der Maske gr├Â├čer als Null sind (> 0) nur Innerhalb der Konturregion bleiben die Pixel des Originalbildes ├╝brig, die sich mit der Kontur ├╝berschneiden.

    Mit schwarzen Pixeln isolieren: Unteroptionen

    Bild in voller Gr├Â├če

    Es sind keine weiteren Schritte erforderlich, wenn du das Bild in voller Gr├Â├če beh├Ąltst.

    Beispiel in voller Gr├Â├če Isoliertes Objektbild Schwarzer Hintergrund
    Beispiel f├╝r die Ausgabe in voller Gr├Â├če

    Ausgeschnittenes Objekt Bild

    Zus├Ątzliche Schritte sind erforderlich, um das Bild so zuzuschneiden, dass es nur die Objektregion enth├Ąlt.

    Beispiel Bild mit isoliertem Objekt beschneiden Schwarzer Hintergrund

    # (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. Weitere Informationen zu Bounding-Box-Ergebnissen findest du unter Boxen-Abschnitt im Vorhersagemodus
    Was bewirkt dieser Code?
    • Die c.boxes.xyxy.cpu().numpy() Aufruf ruft die Bounding Boxes als NumPy-Array in der xyxy Format, wobei xmin, ymin, xmax, und ymax stehen f├╝r die Koordinaten des Begrenzungsrahmen-Rechtecks. Siehe K├Ąstchen Abschnitt aus dem Vorhersagemodus f├╝r weitere Details.

    • Die squeeze() Operation entfernt alle unn├Âtigen Dimensionen aus dem NumPy-Array und stellt sicher, dass es die erwartete Form hat.

    • Umrechnung der Koordinatenwerte mit .astype(np.int32) ├Ąndert den Datentyp der Feldkoordinaten von float32 zu int32Dadurch sind sie f├╝r das Zuschneiden von Bildern mit Indexscheiben geeignet.

    • Schlie├člich wird die Bounding-Box-Region mithilfe von Index-Slicing aus dem Bild ausgeschnitten. Die Begrenzungen werden durch den [ymin:ymax, xmin:xmax] Koordinaten des Begrenzungsrahmens der Erkennung.

    # Isolate object with transparent background (when saved as PNG)
    isolated = np.dstack([img, b_mask])
    
    Wie funktioniert das?
    • Die Verwendung der NumPy dstack() (Array-Stapelung entlang der Tiefenachse) in Verbindung mit der erzeugten bin├Ąren Maske ein Bild mit vier Kan├Ąlen. Dadurch werden alle Pixel au├čerhalb der Objektkontur transparent, wenn das Bild als PNG Datei.

    Mit transparenten Pixeln isolieren: Unteroptionen

    Bild in voller Gr├Â├če

    Es sind keine weiteren Schritte erforderlich, wenn du das Bild in voller Gr├Â├če beh├Ąltst.

    Beispiel in voller Gr├Â├če Isoliertes Objektbild ohne Hintergrund
    Beispiel Ausgabe in voller Gr├Â├če + transparenter Hintergrund

    Ausgeschnittenes Objekt Bild

    Zus├Ątzliche Schritte sind erforderlich, um das Bild so zuzuschneiden, dass es nur die Objektregion enth├Ąlt.

    Beispiel Zuschneiden eines isolierten Objekts Bild ohne Hintergrund

    # (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. Weitere Informationen zu Bounding-Box-Ergebnissen findest du unter Boxen-Abschnitt im Vorhersagemodus
    Was bewirkt dieser Code?
    • Bei der Verwendung von c.boxes.xyxy.cpu().numpy()werden die Bounding Boxes als NumPy-Array zur├╝ckgegeben, indem die xyxy Box-Koordinatenformat, die den Punkten entsprechen xmin, ymin, xmax, ymax f├╝r den Begrenzungsrahmen (Rechteck), siehe K├Ąstchen Abschnitt aus dem Vorhersagemodus f├╝r weitere Informationen.

    • Hinzuf├╝gen von squeeze() sorgt daf├╝r, dass alle ├╝berfl├╝ssigen Dimensionen aus dem NumPy-Array entfernt werden.

    • Umrechnung der Koordinatenwerte mit .astype(np.int32) ├Ąndert den Datentyp der Feldkoordinaten von float32 zu int32 die beim Zuschneiden des Bildes mit Hilfe von Index-Slices kompatibel sein werden.

    • Schlie├člich wird die Bildregion f├╝r die Bounding Box mithilfe von Index-Slicing zugeschnitten, wobei die Grenzen mit der Funktion [ymin:ymax, xmin:xmax] Koordinaten des Begrenzungsrahmens der Erkennung.

    Was ist, wenn ich das ausgeschnittene Objekt einschlie├člich des Hintergrunds haben m├Âchte?

    Dies ist eine eingebaute Funktion der Bibliothek Ultralytics . Siehe die save_crop Argument f├╝r Predict Mode Inference Argumente f├╝r Details.


  6. Was als N├Ąchstes zu tun ist, bleibt ganz dir als Entwickler ├╝berlassen. Ein einfaches Beispiel f├╝r einen m├Âglichen n├Ąchsten Schritt (Speichern des Bildes in einer Datei zur sp├Ąteren Verwendung) wird hier gezeigt.

    • HINWEIS: Dieser Schritt ist optional und kann ├╝bersprungen werden, wenn er f├╝r deinen speziellen Anwendungsfall nicht erforderlich ist.
    Beispiel Letzter Schritt
    # Save isolated object to file
    _ = cv2.imwrite(f"{img_name}_{label}-{ci}.png", iso_crop)
    
    • In diesem Beispiel wird die img_name ist der Basisname der Quellbilddatei, label ist der erkannte Klassenname, und ci ist der Index der Objekterkennung (im Falle mehrerer Instanzen mit demselben Klassennamen).

Vollst├Ąndiger Beispielcode

Hier werden alle Schritte aus dem vorherigen Abschnitt in einem einzigen Codeblock zusammengefasst. Bei wiederholter Verwendung w├Ąre es optimal, eine Funktion zu definieren, die einige oder alle Befehle aus dem for-Schleifen, aber das ist eine ├ťbung, die dem Leser ├╝berlassen bleibt.

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. Die Zeile, die contour wird hier in einer einzigen Zeile zusammengefasst, wo sie oben auf mehrere Zeilen aufgeteilt war.
  2. Was hier hingeh├Ârt, entscheidest du!
  3. Weitere Informationen findest du unter Vorhersagemodus.
  4. Siehe Segmentaufgabe f├╝r weitere Informationen.
  5. Erfahre mehr ├╝ber das Arbeiten mit Ergebnissen
  6. Erfahre mehr ├╝ber die Ergebnisse der Segmentierungsmaske


Created 2023-11-27, Updated 2024-06-18
Authors: glenn-jocher (11), IvorZhu331 (1), RizwanMunawar (1), Burhan-Q (1)

Kommentare