Za pomocą zestawu ML Kit można wykrywać i śledzić obiekty w klatkach wideo.
Kiedy przekazujesz obrazy ML Kit, ML Kit zwraca dla każdego obrazu listę maksymalnie pięciu wykrytych obiektów i ich położenie na obrazie. Podczas wykrywania obiektów w strumieniach wideo każdy obiekt ma identyfikator, którego można użyć do śledzenia obiektu na obrazach. Opcjonalnie możesz także włączyć zgrubną klasyfikację obiektów, która oznacza obiekty z szerokimi opisami kategorii.
Zanim zaczniesz
- Jeśli nie dodałeś jeszcze Firebase do swojej aplikacji, zrób to, wykonując czynności opisane w przewodniku wprowadzającym .
- Dołącz biblioteki ML Kit do swojego Podfile:
pod 'Firebase/MLVision', '6.25.0' pod 'Firebase/MLVisionObjectDetection', '6.25.0'
Po zainstalowaniu lub zaktualizowaniu Podów swojego projektu pamiętaj o otwarciu projektu Xcode przy użyciu jego.xcworkspace
. - W swojej aplikacji zaimportuj Firebase:
Szybki
import Firebase
Cel C
@import Firebase;
1. Skonfiguruj detektor obiektów
Aby rozpocząć wykrywanie i śledzenie obiektów, najpierw utwórz instancję VisionObjectDetector
, opcjonalnie określając ustawienia detektora, które chcesz zmienić z domyślnych.
Skonfiguruj detektor obiektów dla swojego przypadku użycia za pomocą obiektu
VisionObjectDetectorOptions
. Możesz zmienić następujące ustawienia:Ustawienia detektora obiektów Tryb wykrywania .stream
(domyślny) |.singleImage
W trybie strumieniowym (domyślnym) detektor obiektów działa z bardzo małym opóźnieniem, ale może generować niekompletne wyniki (takie jak nieokreślone ramki ograniczające lub kategoria) przy kilku pierwszych wywołaniach detektora. Ponadto w trybie strumieniowym detektor przypisuje obiektom identyfikatory śledzenia, których można używać do śledzenia obiektów w klatkach. 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 detektor obiektów czeka, aż obwiednia i kategoria wykrytego obiektu (jeśli włączono klasyfikację) będą dostępne, zanim zwróci wynik. W rezultacie opóźnienie wykrywania jest potencjalnie większe. Ponadto w trybie pojedynczego obrazu identyfikatory śledzenia nie są przypisywane. Użyj tego trybu, jeśli opóźnienie nie jest krytyczne i nie chcesz mieć do czynienia z częściowymi wynikami.
Wykrywaj i śledź wiele obiektów false
(domyślnie) |true
Określa, czy wykrywać i śledzić maksymalnie pięć obiektów, czy tylko najbardziej widoczny obiekt (domyślnie).
Klasyfikuj obiekty false
(domyślnie) |true
Określa, czy klasyfikować wykryte obiekty do ogólnych kategorii. Po włączeniu detektor obiektów klasyfikuje obiekty w następujące kategorie: towary modowe, żywność, artykuły gospodarstwa domowego, miejsca, rośliny i nieznane.
Interfejs API wykrywania i śledzenia obiektów jest zoptymalizowany pod kątem dwóch podstawowych przypadków użycia:
- Wykrywanie na żywo i śledzenie najbardziej widocznego obiektu w wizjerze aparatu
- Wykrywanie wielu obiektów na statycznym obrazie
Aby skonfigurować interfejs API dla tych przypadków użycia:
Szybki
// Live detection and tracking let options = VisionObjectDetectorOptions() options.detectorMode = .stream options.shouldEnableMultipleObjects = false options.shouldEnableClassification = true // Optional // Multiple object detection in static images let options = VisionObjectDetectorOptions() options.detectorMode = .singleImage options.shouldEnableMultipleObjects = true options.shouldEnableClassification = true // Optional
Cel C
// Live detection and tracking FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init]; options.detectorMode = FIRVisionObjectDetectorModeStream; options.shouldEnableMultipleObjects = NO; options.shouldEnableClassification = YES; // Optional // Multiple object detection in static images FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init]; options.detectorMode = FIRVisionObjectDetectorModeSingleImage; options.shouldEnableMultipleObjects = YES; options.shouldEnableClassification = YES; // Optional
Uzyskaj instancję
FirebaseVisionObjectDetector
:Szybki
let objectDetector = Vision.vision().objectDetector() // Or, to change the default settings: let objectDetector = Vision.vision().objectDetector(options: options)
Cel C
FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetector]; // Or, to change the default settings: FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetectorWithOptions:options];
2. Uruchom detektor obiektów
Aby wykryć i śledzić obiekty, wykonaj poniższe czynności dla każdego obrazu lub klatki wideo. Jeśli włączyłeś tryb strumieniowy, musisz utworzyć obiekty VisionImage
z CMSampleBufferRef
s.
Utwórz obiekt
VisionImage
przy użyciuUIImage
lubCMSampleBufferRef
.Aby użyć
UIImage
:- W razie potrzeby obróć obraz tak, aby jego właściwość
imageOrientation
miała.up
. - Utwórz obiekt
VisionImage
, używając poprawnie obróconegoUIImage
. Nie określaj żadnych metadanych rotacji — należy użyć wartości domyślnej.topLeft
.Szybki
let image = VisionImage(image: uiImage)
Cel C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Aby użyć
CMSampleBufferRef
:Utwórz obiekt
VisionImageMetadata
, który określa orientację danych obrazu zawartych w buforzeCMSampleBufferRef
.Aby uzyskać orientację obrazu:
Szybki
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> VisionDetectorImageOrientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftTop : .rightTop case .landscapeLeft: return cameraPosition == .front ? .bottomLeft : .topLeft case .portraitUpsideDown: return cameraPosition == .front ? .rightBottom : .leftBottom case .landscapeRight: return cameraPosition == .front ? .topRight : .bottomRight case .faceDown, .faceUp, .unknown: return .leftTop } }
Cel C
- (FIRVisionDetectorImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationLeftTop; } else { return FIRVisionDetectorImageOrientationRightTop; } case UIDeviceOrientationLandscapeLeft: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationBottomLeft; } else { return FIRVisionDetectorImageOrientationTopLeft; } case UIDeviceOrientationPortraitUpsideDown: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationRightBottom; } else { return FIRVisionDetectorImageOrientationLeftBottom; } case UIDeviceOrientationLandscapeRight: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationTopRight; } else { return FIRVisionDetectorImageOrientationBottomRight; } default: return FIRVisionDetectorImageOrientationTopLeft; } }
Następnie utwórz obiekt metadanych:
Szybki
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Cel C
FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init]; AVCaptureDevicePosition cameraPosition = AVCaptureDevicePositionBack; // Set to the capture device you used. metadata.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
- Utwórz obiekt
VisionImage
przy użyciu obiektuCMSampleBufferRef
i metadanych rotacji:Szybki
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Cel C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- W razie potrzeby obróć obraz tak, aby jego właściwość
Przekaż
VisionImage
do jednej z metod przetwarzania obrazu detektora obiektów. Można użyć metody asynchronicznejprocess(image:)
lub metody synchronicznejresults()
.Aby wykryć obiekty asynchronicznie:
Szybki
objectDetector.process(image) { detectedObjects, error in guard error == nil else { // Error. return } guard let detectedObjects = detectedObjects, !detectedObjects.isEmpty else { // No objects detected. return } // Success. Get object info here. // ... }
Cel C
[objectDetector processImage:image completion:^(NSArray<FIRVisionObject *> * _Nullable objects, NSError * _Nullable error) { if (error == nil) { return; } if (objects == nil | objects.count == 0) { // No objects detected. return; } // Success. Get object info here. // ... }];
Aby wykryć obiekty synchronicznie:
Szybki
var results: [VisionObject]? = nil do { results = try objectDetector.results(in: image) } catch let error { print("Failed to detect object with error: \(error.localizedDescription).") return } guard let detectedObjects = results, !detectedObjects.isEmpty else { print("Object detector returned no results.") return } // ...
Cel C
NSError *error; NSArray<FIRVisionObject *> *objects = [objectDetector resultsInImage:image error:&error]; if (error == nil) { return; } if (objects == nil | objects.count == 0) { // No objects detected. return; } // Success. Get object info here. // ...
Jeśli wywołanie procesora obrazu powiedzie się, przekazuje on listę obiektów
VisionObject
do procedury obsługi uzupełniania lub zwraca listę, w zależności od tego, czy wywołano metodę asynchroniczną, czy synchroniczną.Każdy
VisionObject
zawiera następujące właściwości:frame
CGRect
wskazujący położenie obiektu na obrazie.trackingID
Liczba całkowita identyfikująca obiekt na obrazach. Zero w trybie pojedynczego obrazu. classificationCategory
Gruba kategoria obiektu. Jeśli detektor obiektów nie ma włączonej klasyfikacji, jest to zawsze .unknown
.confidence
Wartość ufności klasyfikacji obiektu. Jeśli detektor obiektów nie ma włączonej klasyfikacji lub obiekt jest sklasyfikowany jako nieznany, wartość ta wynosi nil
.Szybki
// detectedObjects contains one item if multiple object detection wasn't enabled. for obj in detectedObjects { let bounds = obj.frame let id = obj.trackingID // If classification was enabled: let category = obj.classificationCategory let confidence = obj.confidence }
Cel C
// The list of detected objects contains one item if multiple // object detection wasn't enabled. for (FIRVisionObject *obj in objects) { CGRect bounds = obj.frame; if (obj.trackingID) { NSInteger id = obj.trackingID.integerValue; } // If classification was enabled: FIRVisionObjectCategory category = obj.classificationCategory; float confidence = obj.confidence.floatValue; }
Poprawa użyteczności i wydajności
Aby zapewnić najlepszą wygodę użytkowania, postępuj zgodnie z tymi wskazówkami w swojej aplikacji:
- Skuteczne wykrycie obiektu zależy od jego złożoności wizualnej. Aby obiekty o niewielkiej liczbie cech wizualnych mogły zostać wykryte, konieczne może być zajęcie większej części obrazu. Powinieneś zapewnić użytkownikom wskazówki dotyczące przechwytywania danych wejściowych, które sprawdzają się w przypadku obiektów, które chcesz wykryć.
- Jeśli podczas korzystania z klasyfikacji chcesz wykryć obiekty, które nie mieszczą się w obsługiwanych kategoriach, zaimplementuj specjalną obsługę nieznanych obiektów.
Zapoznaj się także z [aplikacją prezentacyjną ML Kit Material Design] [showcase-link]{: .external } i kolekcją Material Design Patterns na potrzeby funkcji opartych na uczeniu maszynowym .
Korzystając z trybu przesyłania strumieniowego w aplikacji czasu rzeczywistego, postępuj zgodnie z poniższymi wskazówkami, aby uzyskać najlepszą liczbę klatek na sekundę:
Nie używaj wykrywania wielu obiektów w trybie przesyłania strumieniowego, ponieważ większość urządzeń nie będzie w stanie wygenerować odpowiedniej liczby klatek na sekundę.
Wyłącz klasyfikację, jeśli jej nie potrzebujesz.
- Przepustnica wzywa do detektora. Jeśli w czasie działania detektora pojawi się nowa klatka wideo, usuń ją.
- Jeśli używasz wyjścia detektora do nakładania grafiki na obraz wejściowy, najpierw uzyskaj wynik z ML Kit, a następnie wyrenderuj obraz i nakładkę w jednym kroku. W ten sposób renderujesz na powierzchnię wyświetlacza tylko raz dla każdej klatki wejściowej. Zobacz przykładowe klasy PreviewOverlayView i FIRDetectionOverlayView w przykładowej aplikacji prezentacyjnej.