Możesz używać ML Kit do wykrywania i śledzenia obiektów w kolejnych klatkach wideo.
Gdy przekazujesz obraz do narzędzia ML Kit, wykrywa on maksymalnie 5 obiektów na obrazie wraz z jego położeniem. Podczas wykrywania obiektów w strumieniach wideo każdy obiekt ma unikalny identyfikator, którego można użyć do śledzenia obiektu między ramkami. Opcjonalnie możesz też włączyć przybliżoną klasyfikację obiektów, która oznacza obiekty etykietami z szerokimi opisami kategorii.
Wypróbuj
- Przetestuj przykładową aplikację, aby zobaczyć przykładowe użycie tego interfejsu API.
- Kompletną implementację tego interfejsu API znajdziesz w aplikacji Material Design.
Zanim zaczniesz
- Uwzględnij w podfile te pody ML Kit:
pod 'GoogleMLKit/ObjectDetection', '3.2.0'
- Gdy zainstalujesz lub zaktualizujesz pody projektu, otwórz projekt Xcode, używając jego
.xcworkspace
. ML Kit jest obsługiwany w Xcode w wersji 12.4 lub nowszej.
1. Konfigurowanie wzorca do wykrywania obiektów
Aby wykrywać i śledzić obiekty, najpierw utwórz instancję ObjectDetector
i opcjonalnie określ wszystkie ustawienia wzorca do wykrywania, które chcesz zmienić jako domyślne.
Skonfiguruj wzorzec do wykrywania obiektów w swoim przypadku użycia za pomocą obiektu
ObjectDetectorOptions
. Możesz zmienić te ustawienia:Ustawienia funkcji wykrywania obiektów Tryb wykrywania .stream
(domyślnie) |.singleImage
W trybie strumieniowania (domyślny) wzorzec do wykrywania obiektów działa z niewielkim opóźnieniem, ale w przypadku kilku pierwszych wywołań detektora może uzyskać niepełne wyniki (takie jak nieokreślone ramki ograniczające lub kategorie). W trybie strumieniowania wzorzec wykrywa identyfikatory obiektów na potrzeby śledzenia obiektów w ramkach. Użyj tego trybu, jeśli chcesz śledzić obiekty lub gdy ważne jest małe opóźnienie, na przykład podczas przetwarzania strumieni wideo w czasie rzeczywistym.
W trybie pojedynczego obrazu wzorzec do wykrywania obiektów zwraca wynik po określeniu ramki ograniczającej obiekt. Jeśli włączysz także klasyfikację, wyniki będą zwracane po udostępnieniu ramki ograniczającej i etykiety kategorii. W efekcie opóźnienie wykrywania może być większe. W trybie pojedynczego obrazu nie są też przypisywane identyfikatory śledzenia. Użyj tego trybu, jeśli opóźnienie nie jest krytyczne i nie chcesz uwzględniać częściowych wyników.
Wykrywaj i śledź wiele obiektów false
(domyślnie) |true
Określa, czy chcesz wykryć i śledzić maksymalnie 5 obiektów czy tylko najbardziej widoczny obiekt (domyślnie).
Klasyfikowanie obiektów false
(domyślnie) |true
Określa, czy wykryte obiekty mają zostać sklasyfikowane w ramach przybliżonych kategorii. Po włączeniu tej funkcji wykrywacz obiektów klasyfikuje obiekty w te kategorie: artykuły odzieżowe, jedzenie, artykuły gospodarstwa domowego, miejsca i rośliny.
Interfejs API wykrywania i śledzenia obiektów jest zoptymalizowany pod kątem tych 2 głównych przypadków użycia:
- Wykrywanie i śledzenie najsłynniejszego obiektu w wizjerze kamery.
- Wykrywanie wielu obiektów na obrazie statycznym.
Aby skonfigurować interfejs API pod kątem tych przypadków użycia:
Swift
// Live detection and tracking let options = ObjectDetectorOptions() options.shouldEnableClassification = true // Multiple object detection in static images let options = ObjectDetectorOptions() options.detectorMode = .singleImage options.shouldEnableMultipleObjects = true options.shouldEnableClassification = true
Objective-C
// Live detection and tracking MLKObjectDetectorOptions *options = [[MLKObjectDetectorOptions alloc] init]; options.shouldEnableClassification = YES; // Multiple object detection in static images MLKObjectDetectorOptions *options = [[MLKOptions alloc] init]; options.detectorMode = MLKObjectDetectorModeSingleImage; options.shouldEnableMultipleObjects = YES; options.shouldEnableClassification = YES;
- Pobierz instancję
ObjectDetector
:
Swift
let objectDetector = ObjectDetector.objectDetector() // Or, to change the default settings: let objectDetector = ObjectDetector.objectDetector(options: options)
Objective-C
MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetector]; // Or, to change the default settings: MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];
2. Przygotuj obraz wejściowy
Aby wykrywać i śledzić obiekty, wykonaj te czynności w przypadku każdego obrazu lub ramki filmu.
Jeśli masz włączony tryb strumieniowania, musisz utworzyć obiekty VisionImage
z CMSampleBuffer
s.
Utwórz obiekt VisionImage
za pomocą właściwości UIImage
lub CMSampleBuffer
.
Jeśli używasz UIImage
, wykonaj te czynności:
- Utwórz obiekt
VisionImage
z elementemUIImage
. Pamiętaj o prawidłowej wartości.orientation
.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Jeśli używasz CMSampleBuffer
, wykonaj te czynności:
-
Określ orientację danych obrazu zawartych w elemencie
CMSampleBuffer
.Aby uzyskać orientację obrazu:
Swift
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> UIImage.Orientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftMirrored : .right case .landscapeLeft: return cameraPosition == .front ? .downMirrored : .up case .portraitUpsideDown: return cameraPosition == .front ? .rightMirrored : .left case .landscapeRight: return cameraPosition == .front ? .upMirrored : .down case .faceDown, .faceUp, .unknown: return .up } }
Objective-C
- (UIImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored : UIImageOrientationRight; case UIDeviceOrientationLandscapeLeft: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored : UIImageOrientationUp; case UIDeviceOrientationPortraitUpsideDown: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored : UIImageOrientationLeft; case UIDeviceOrientationLandscapeRight: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored : UIImageOrientationDown; case UIDeviceOrientationUnknown: case UIDeviceOrientationFaceUp: case UIDeviceOrientationFaceDown: return UIImageOrientationUp; } }
- Utwórz obiekt
VisionImage
za pomocą obiektuCMSampleBuffer
i orientacji:Swift
let image = VisionImage(buffer: sampleBuffer) image.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition)
Objective-C
MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer]; image.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
3. Przetwórz obraz
PrzekażVisionImage
do jednej z metod przetwarzania obrazu wykrywacza obiektów. Możesz użyć metody asynchronicznego process(image:)
lub synchronicznej metody results()
.
Aby asynchronicznie wykrywać obiekty:
Swift
objectDetector.process(image) { objects, error in guard error == nil else { // Error. return } guard !objects.isEmpty else { // No objects detected. return } // Success. Get object info here. // ... }
Objective-C
[objectDetector processImage:image completion:^(NSArray* _Nullable objects, NSError * _Nullable error) { if (error == nil) { return; } if (objects.count == 0) { // No objects detected. return; } // Success. Get object info here. }];
Aby wykrywać obiekty synchronicznie:
Swift
var objects: [Object] do { objects = try objectDetector.results(in: image) } catch let error { print("Failed to detect object with error: \(error.localizedDescription).") return } guard !objects.isEmpty else { print("Object detector returned no results.") return } // Success. Get object info here.
Objective-C
NSError *error; NSArray*objects = [objectDetector resultsInImage:image error:&error]; if (error == nil) { return; } if (objects.count == 0) { // No objects detected. return; } // Success. Get object info here.
4. Uzyskaj informacje o wykrytych obiektach
Jeśli wywołanie procesora graficznego zakończy się powodzeniem, przesyła listęObject
do modułu obsługi ukończenia lub zwraca listę w zależności od tego, czy została wywołana metoda asynchroniczny czy synchroniczny.
Każdy element Object
zawiera te właściwości:
frame |
CGRect wskazujący położenie obiektu na obrazie. |
trackingID |
Liczba całkowita określająca obiekt na obrazach lub „nil” w trybie pojedynczego obrazu. |
labels |
Tablica etykiet opisujących obiekt, który został zwrócony przez wzorzec.
Właściwość jest pusta, jeśli opcja wzorca do wykrywania treści shouldEnableClassification jest ustawiona na false .
|
Swift
// objects contains one item if multiple object detection wasn't enabled. for object in objects { let frame = object.frame let trackingID = object.trackingID // If classification was enabled: let description = object.labels.enumerated().map { (index, label) in "Label \(index): \(label.text), \(label.confidence)" }.joined(separator:"\n") }
Objective-C
// The list of detected objects contains one item if multiple // object detection wasn't enabled. for (MLKObject *object in objects) { CGRect frame = object.frame; NSNumber *trackingID = object.trackingID; for (MLKObjectLabel *label in object.labels) { NSString *labelString = [NSString stringWithFormat: @"%@, %f, %lu", label.text, label.confidence, (unsigned long)label.index]; ... } }
Poprawa użyteczności i wydajności
Aby zadbać o wygodę użytkowników, zastosuj się do tych wskazówek:
- Pomyślne wykrywanie obiektu zależy od jego złożoności wizualnej. Aby obiekt został wykryty, obiekty o małej liczbie elementów wizualnych mogą zająć większą część obrazu. Należy przekazać użytkownikom wskazówki dotyczące przechwytywania danych wejściowych, które dobrze współgrają z obiektami, które mają być wykrywane.
- Jeśli używasz klasyfikacji, aby wykrywać obiekty, które nie należą do obsługiwanych kategorii, zaimplementuj specjalną obsługę elementów nieznanych.
Zajrzyj też do kolekcji Wzorce funkcji wykorzystujących systemy uczące się w stylu Material Design.
Jeśli używasz trybu strumieniowego przesyłania danych w aplikacji w czasie rzeczywistym, postępuj zgodnie z tymi wskazówkami, aby uzyskać największą liczbę klatek na sekundę:
- Nie używaj w trybie strumieniowego wykrywania wielu obiektów, ponieważ większość urządzeń nie będzie w stanie generować odpowiedniej liczby klatek.
- Wyłącz klasyfikację, której nie potrzebujesz.
- Aby przetworzyć ramki wideo, użyj synchronicznego interfejsu API detektora
results(in:)
. Wywołaj tę metodę za pomocą funkcjicaptureOutput(_, didOutput:from:)
AVCaptureVideoDataOutputSampleBufferDelegate
, aby synchronicznie uzyskać wyniki z danej klatki filmu. Aby ograniczyć liczbę wywołań wykrywania, zachowajalwaysDiscardsLateVideoFrames
AVCaptureVideoDataOutput
. Jeśli nowa reguła wideo stanie się dostępna podczas działania wzorca do wykrywania treści, zostanie usunięta. - Jeśli używasz danych wyjściowych wzorca do nakładania grafiki na obrazie wejściowym, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładkę w jednym kroku. Dzięki temu renderowanie każdej klatki będzie renderowane tylko raz dla każdej przetworzonej klatki wejściowej. Przykład znajdziesz w przykładzie updatepreviewOverlayViewWithLastFrame w przykładzie ML Kit.