Za pomocą ML Kit możesz wykrywać i śledzić obiekty w kolejnych klatkach wideo.
Gdy przekazujesz obraz do ML Kit, wykrywa on do 5 obiektów na obrazie wraz z pozycją każdego z nich. Przy wykrywaniu obiektów w strumieniach wideo każdy obiekt ma unikalny identyfikator, za pomocą którego można go śledzić od klatki do klatki. Możesz też włączyć przybliżoną klasyfikację obiektów, która oznacza obiekty szerokimi opisami kategorii.
Wypróbuj
- Przyjrzyj się przykładowej aplikacji, aby zobaczyć przykładowe użycie tego interfejsu API.
- Pełną implementację tego interfejsu API znajdziesz w aplikacji Material Design z funkcją prezentacji.
Zanim zaczniesz
- W pliku Podfile uwzględnij te pody ML Kit:
pod 'GoogleMLKit/ObjectDetection', '3.2.0'
- Po zainstalowaniu lub zaktualizowaniu podów w projekcie otwórz projekt Xcode, korzystając z jego polecenia
.xcworkspace
. ML Kit obsługuje Xcode w wersji 12.4 lub nowszej.
1. Skonfiguruj detektor obiektów
Aby wykrywać i śledzić obiekty, najpierw utwórz instancję ObjectDetector
i opcjonalnie określ ustawienia wykrywania, które chcesz zmienić z domyślnych.
Skonfiguruj detektor obiektów na potrzeby danego 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 strumienia (domyślnym) wzorzec do wykrywania obiektów działa z bardzo krótkim czasem oczekiwania, ale podczas jego kilku pierwszych wywołań może generować niekompletne wyniki (takie jak nieokreślone ramki ograniczające lub kategorie). Dodatkowo w trybie strumieniowania detektor przypisuje do obiektów identyfikatory śledzenia, których możesz używać do śledzenia obiektów w ramkach. Użyj tego trybu, jeśli chcesz śledzić obiekty lub gdy ważne jest krótkie opóźnienie, np. gdy przetwarzasz strumienie wideo w czasie rzeczywistym.
W trybie z pojedynczym obrazem detektor obiektów zwraca wynik po określeniu ramki ograniczającej obiektu. Jeśli włączysz również klasyfikację, zostanie zwrócony wynik, gdy ramka ograniczająca i etykieta kategorii są dostępne. W rezultacie czas oczekiwania na wykrywanie jest potencjalnie dłuższy. W trybie z jednym obrazem identyfikatory śledzenia nie są przypisywane. Użyj tego trybu, jeśli opóźnienie nie jest krytyczne i nie chcesz zajmować się częściowymi wynikami.
Wykrywaj i śledź wiele obiektów false
(domyślnie) |true
Określa, czy wykrywać 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ą być klasyfikowane w przybliżonych kategoriach. Gdy ta opcja jest włączona, detektor obiektów klasyfikuje obiekty w tych kategoriach: odzież, jedzenie, wyposażenie domu, miejsca i rośliny.
Interfejs API wykrywania i śledzenia jest zoptymalizowany pod kątem tych 2 głównych przypadków użycia:
- Wykrywanie na żywo i śledzenie najbardziej widocznego 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, w przypadku każdego obrazu lub klatki filmu wykonaj te czynności.
Jeśli masz włączony tryb strumieniowego przesyłania danych, musisz utworzyć obiekty VisionImage
z CMSampleBuffer
.
Utwórz obiekt VisionImage
za pomocą UIImage
lub CMSampleBuffer
.
Jeśli używasz urządzenia UIImage
, wykonaj te czynności:
- Utwórz obiekt
VisionImage
za pomocąUIImage
. Pamiętaj, aby podać prawidłową wartość.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 urządzenia CMSampleBuffer
, wykonaj te czynności:
-
Określ orientację danych obrazu w elemencie
CMSampleBuffer
.Aby pobrać orientację:
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
, używając obiektu i orientacjiCMSampleBuffer
: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. Przetwarzanie obrazu
Przekaż właściwośćVisionImage
do jednej z metod przetwarzania obrazu przez detektor obiektów. Możesz używać asynchronicznej metody 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 synchronicznie wykrywać obiekty:
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. Pobieranie informacji o wykrytych obiektach
Jeśli wywołanie procesora obrazów się powiedzie, przekaże listęObject
do modułu obsługi ukończenia lub zwróci listę w zależności od tego, czy wywołano metodę asynchroniczną czy synchroniczną.
Każdy element Object
zawiera te właściwości:
frame |
CGRect wskazująca pozycję obiektu na obrazie. |
trackingID |
Liczba całkowita identyfikująca obiekt na zdjęciach lub „nil” w trybie pojedynczego obrazu. |
labels |
Tablica etykiet opisujących obiekt zwrócony przez detektor.
Właściwość jest pusta, jeśli opcja wzorca 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]; ... } }
Większa użyteczność i wydajność
Aby zadbać o wygodę użytkowników, przestrzegaj tych wytycznych:
- Pomyślne wykrywanie obiektów zależy od złożoności wizualnej obiektu. Aby można było wykryć obiekty o niewielkiej liczbie funkcji wizualnych, może być konieczne zajmowanie większej części obrazu. Musisz udostępnić użytkownikom wskazówki dotyczące przechwytywania danych wejściowych, które sprawdzają się w przypadku danego rodzaju obiektów, które chcesz wykrywać.
- Jeśli używasz klasyfikacji i chcesz wykrywać obiekty, które nie należą do poszczególnych kategorii, musisz wdrożyć specjalną obsługę nieznanych obiektów.
Zerknij na kolekcję wzorców dla funkcji opartych na systemach uczących się w interfejsie Material Design.
Jeśli używasz trybu strumieniowego przesyłania danych w aplikacji wyświetlającej dane w czasie rzeczywistym, postępuj zgodnie z tymi wskazówkami, aby uzyskać najlepszą liczbę klatek na sekundę:
- Nie używaj wykrywania wielu obiektów w trybie strumieniowego przesyłania danych, ponieważ większość urządzeń nie będzie w stanie uzyskać wystarczającej liczby klatek.
- Wyłącz klasyfikację, jeśli jej nie potrzebujesz.
- Do przetwarzania klatek wideo użyj synchronicznego interfejsu API
results(in:)
wzorca. Wywołaj tę metodę z funkcjicaptureOutput(_, didOutput:from:)
obiektuAVCaptureVideoDataOutputSampleBufferDelegate
, aby synchronicznie pobierać wyniki z danej klatki wideo. PozostawalwaysDiscardsLateVideoFrames
obiektuAVCaptureVideoDataOutput
jakotrue
, aby ograniczać wywołania do wzorca. Jeśli podczas działania wzorca pojawi się nowa ramka wideo, zostanie ona usunięta. - Jeśli używasz danych wyjściowych wzorca do nakładania grafiki na obraz wejściowy, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładkę w jednym kroku. Dzięki temu na każdą przetworzoną klatkę wejściową renderujesz się tylko raz. Przykład znajdziesz w sekcji updatePreviewOverlayViewWithLastFrame w przykładowym krótkim wprowadzeniu do ML Kit.