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.
Recept doorloop
-
Begin met de noodzakelijke invoer
Ultralytics Installeer
Zie het gedeelte Ultralytics Snelstartinstallatie voor een korte handleiding voor het installeren van de benodigde bibliotheken.
-
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:
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.
-
Herhaal nu de resultaten en de contouren. Voor workflows die een afbeelding in een bestand willen opslaan, moet de bronafbeelding
base-name
en de detectieclass-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()]
- Voor meer informatie over het werken met detectieresultaten, zie Kaders voor de modus Voorspellen.
- 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.
-
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 gedetecteerdeperson
klasseobjecten wordt rechts getoond.# 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)
-
Voor meer informatie over
c.masks.xy
zie Sectie maskers van voorspelmodus. -
Hier worden de waarden in
np.int32
voor compatibiliteit metdrawContours()
functie van OpenCV. -
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()
:: Alsmasks.xy
een lijst is die één element bevat, wordt dit element geëxtraheerd met depop()
methode. -
.astype(np.int32)
:: gebruikenmasks.xy
zal retourneren met een gegevenstype vanfloat32
maar dit zal niet compatibel zijn met de OpenCVdrawContours()
functie, dus dit zal het gegevenstype veranderen inint32
voor compatibiliteit. -
.reshape(-1, 1, 2)
:: Formatteert de gegevens in de gewenste vorm van[N, 1, 2]
waarbijN
het aantal contourpunten, waarbij elk punt wordt weergegeven door een enkele invoer1
en de invoer bestaat uit2
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 dedrawContours()
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.
-
-
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.
Afbeelding bijgesneden object
Extra stappen nodig om de afbeelding zo bij te snijden dat alleen het objectgebied eronder valt.
# (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]
- 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 dexyxy
formaat, waarbijxmin
,ymin
,xmax
enymax
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 vanfloat32
naarint32
waardoor 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 eenPNG
bestand.
Isoleren met transparante pixels: Subopties
Afbeelding op ware grootte
Er zijn geen extra stappen nodig als je een afbeelding op ware grootte bewaart.
Afbeelding bijgesneden object
Extra stappen nodig om de afbeelding zo bij te snijden dat alleen het objectgebied eronder valt.
# (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]
- 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 dexyxy
box coördinaten formaat, die overeenkomen met de puntenxmin, 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 vanfloat32
naarint32
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.
-
-
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
- In dit voorbeeld is de
img_name
is de basisnaam van het bronafbeeldingsbestand,label
de gedetecteerde klassenaam is enci
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)
- De regel die
contour
is hier samengevoegd tot één regel, waar het hierboven was opgesplitst in meerdere regels. - Wat hier komt is aan jou!
- Zie Voorspelmodus voor meer informatie.
- Zie Segmenttaak voor meer informatie.
- Meer informatie over Werken met resultaten
- 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)