Puoi utilizzare ML Kit per riconoscere le entità in un'immagine ed etichettarle. Questa API supporta un'ampia gamma di modelli di classificazione delle immagini personalizzati. Consulta Modelli personalizzati con ML Kit per indicazioni sui requisiti di compatibilità dei modelli, su dove trovare i modelli pre-addestrati, e su come addestrare i tuoi modelli.
Esistono due modi per integrare un modello personalizzato. Puoi raggruppare il modello inserendolo nella cartella degli asset dell'app oppure scaricarlo dinamicamente da Cloud Storage. La tabella seguente confronta le due opzioni.
| Modello raggruppato | Modello in hosting |
|---|---|
| Il modello fa parte dell'APK dell'app, il che ne aumenta le dimensioni. | Il modello non fa parte dell'APK. Viene ospitato caricandolo in Cloud Storage. Ti consigliamo di utilizzare Cloud Storage for Firebase. |
| Il modello è disponibile immediatamente, anche quando il dispositivo Android è offline | L'app deve includere il codice per scaricare il modello on demand |
| Non è necessario un progetto Firebase | Richiede un progetto Firebase (se utilizzi Cloud Storage for Firebase). |
| Per aggiornare il modello, devi ripubblicare l'app | Esegui il push degli aggiornamenti del modello senza ripubblicare l'app |
| Nessun test A/B integrato | Test A/B con Firebase Remote Config |
Prova
- Consulta l'app di avvio rapido di Vision per un esempio di utilizzo del modello raggruppato e l'app di avvio rapido di AutoML per un esempio di utilizzo del modello in hosting.
Prima di iniziare
Includi le librerie ML Kit nel tuo Podfile:
pod 'GoogleMLKit/ImageLabelingCustom', '8.0.0'Dopo aver installato o aggiornato i pod del progetto, apri il progetto Xcode utilizzando il file
.xcworkspace. ML Kit è supportato in Xcode versione 13.2.1 o successive.Se vuoi scaricare un modello utilizzando Cloud Storage for Firebase, assicurati di aggiungere Firebase al tuo progetto iOS, se non l'hai già fatto. Questa operazione non è necessaria quando raggruppi il modello.
1. Carica il modello
Configura un'origine modello locale
Per raggruppare il modello con l'app:
Copia il file del modello (in genere con estensione
.tfliteo.lite) nel progetto Xcode, assicurandoti di selezionareCopy bundle resources(Copia risorse bundle). Il file del modello verrà incluso nell'app bundle e sarà disponibile per ML Kit.Crea
LocalModeloggetto, specificando il percorso del file del modello:Swift
let localModel = LocalModel(path: localModelFilePath)
Objective-C
MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:localModelFilePath];
Configura un'origine modello in hosting remoto
Per utilizzare il modello in hosting remoto, devi scaricare il file del modello nello spazio di archiviazione locale del dispositivo utilizzando la logica dell'app, quindi caricarlo come modello locale. Ti consigliamo di utilizzare Cloud Storage for Firebase per ospitare un modello. Per i dettagli di implementazione, consulta la guida alla migrazione da Firebase ML a Cloud Storage.
Configura l'etichettatore di immagini
Dopo aver configurato le origini dei modelli, crea un oggetto ImageLabeler da una di queste.
Sono disponibili le seguenti opzioni:
| Opzioni | |
|---|---|
confidenceThreshold
|
Punteggio di attendibilità minimo delle etichette rilevate. Se non viene impostato, verrà utilizzata qualsiasi soglia del classificatore specificata dai metadati del modello. Se il modello non contiene metadati o se i metadati non specificano una soglia del classificatore, verrà utilizzata una soglia predefinita di 0.0. |
maxResultCount
|
Numero massimo di etichette da restituire. Se non viene impostato, verrà utilizzato il valore predefinito di 10. |
Se hai solo un modello raggruppato localmente, crea un etichettatore dall'oggetto LocalModel:
Swift
let options = CustomImageLabelerOptions(localModel: localModel) options.confidenceThreshold = NSNumber(value: 0.0) let imageLabeler = ImageLabeler.imageLabeler(options: options)
Objective-C
MLKCustomImageLabelerOptions *options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel]; options.confidenceThreshold = @(0.0); MLKImageLabeler *imageLabeler = [MLKImageLabeler imageLabelerWithOptions:options];
Se hai un modello in hosting remoto, dovrai verificare che sia stato scaricato prima di eseguirlo.
Anche se devi confermare questa operazione solo prima di eseguire l'etichettatore, se hai sia un modello in hosting remoto sia un modello raggruppato localmente, potrebbe essere utile eseguire questo controllo quando crei un'istanza di ImageLabeler: crea un etichettatore dal modello remoto se è stato scaricato e dal modello locale in caso contrario.
Swift
// Path where your download logic saves the model let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let localModelURL = documentDirectory.appendingPathComponent("my_remote_model.tflite") let model: LocalModel if FileManager.default.fileExists(atPath: localModelURL.path) { // Use the downloaded model model = LocalModel(path: localModelURL.path) } else { // Fall back to bundled model guard let bundledModelPath = Bundle.main.path(forResource: "model", ofType: "tflite") else { return } model = LocalModel(path: bundledModelPath) } let options = CustomImageLabelerOptions(localModel: model) let imageLabeler = ImageLabeler.imageLabeler(options: options)
Objective-C
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSString *localModelPath = [documentsDirectory stringByAppendingPathComponent:@"my_remote_model.tflite"]; MLKLocalModel *model; if ([NSFileManager.defaultManager fileExistsAtPath:localModelPath]) { // Use the downloaded model model = [[MLKLocalModel alloc] initWithPath:localModelPath]; } else { // Fall back to bundled model NSString *bundledModelPath = [NSBundle.mainBundle pathForResource:@"model" ofType:@"tflite"]; model = [[MLKLocalModel alloc] initWithPath:bundledModelPath]; } MLKCustomImageLabelerOptions *options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:model]; MLKImageLabeler *imageLabeler = [MLKImageLabeler imageLabelerWithOptions:options];
Se hai solo un modello in hosting remoto, devi disattivare le funzionalità correlate al modello, ad esempio disattivare o nascondere una parte dell'interfaccia utente, finché non confermi che il modello è stato scaricato.
Swift
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let localModelURL = documentDirectory.appendingPathComponent("my_remote_model.tflite") if FileManager.default.fileExists(atPath: localModelURL.path) { // Model is already cached, initialize immediately self.initializeLabeler(with: localModelURL) } else { // Model is not yet available, show loading UI and start download self.showLoadingUI() let storage = Storage.storage() let modelRef = storage.reference(forURL: "gs://YOUR_BUCKET/path/to/model.tflite") modelRef.write(toFile: localModelURL) { url, error in self.hideLoadingUI() if let error = error { // Handle download error self.showErrorUI() } else if let modelURL = url { // Download success, initialize labeler self.initializeLabeler(with: modelURL) } } } func initializeLabeler(with modelURL: URL) { let localModel = LocalModel(path: modelURL.path) let options = CustomImageLabelerOptions(localModel: localModel) self.imageLabeler = ImageLabeler.imageLabeler(options: options) // Enable ML-related UI features here self.enableMLFeatures() }
Objective-C
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSString *localModelPath = [documentsDirectory stringByAppendingPathComponent:@"my_remote_model.tflite"]; NSURL *localModelURL = [NSURL fileURLWithPath:localModelPath]; if ([NSFileManager.defaultManager fileExistsAtPath:localModelPath]) { // Model is already cached, initialize immediately [self initializeLabelerWithURL:localModelURL]; } else { // Model is not yet available, show loading UI and start download [self showLoadingUI]; FIRStorage *storage = [FIRStorage storage]; FIRStorageReference *modelRef = [storage referenceForURL:@"gs://YOUR_BUCKET/path/to/model.tflite"]; [modelRef writeToFile:localModelURL completion:^(NSURL * _Nullable URL, NSError * _Nullable error) { [self hideLoadingUI]; if (error != nil) { // Handle download error [self showErrorUI]; } else { // Download success, initialize labeler [self initializeLabelerWithURL:URL]; } }]; } - (void)initializeLabelerWithURL:(NSURL *)modelURL { MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:modelURL.path]; MLKCustomImageLabelerOptions *options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel]; self.imageLabeler = [MLKImageLabeler imageLabelerWithOptions:options]; // Enable ML-related UI features here [self enableMLFeatures]; }
2. Prepara l'immagine di input
Crea un oggetto VisionImage utilizzando un UIImage o un
CMSampleBuffer.
Se utilizzi un UIImage, segui questi passaggi:
- Crea un oggetto
VisionImageconUIImage. Assicurati di specificare l'.orientationcorretto.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Se utilizzi un CMSampleBuffer, segui questi passaggi:
-
Specifica l'orientamento dei dati dell'immagine contenuti in the
CMSampleBuffer.Per ottenere l'orientamento dell'immagine:
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; } }
- Crea un oggetto
VisionImageutilizzando l'CMSampleBufferoggetto e l'orientamento: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. Esegui l'etichettatore di immagini
Per etichettare gli oggetti in un'immagine, passa l'oggetto image al metodo process() di ImageLabeler.
In modo asincrono:
Swift
imageLabeler.process(image) { labels, error in guard error == nil, let labels = labels, !labels.isEmpty else { // Handle the error. return } // Show results. }
Objective-C
[imageLabeler processImage:image completion:^(NSArray*_Nullable labels, NSError *_Nullable error) { if (label.count == 0) { // Handle the error. return; } // Show results. }];
In modo sincrono:
Swift
var labels: [ImageLabel] do { labels = try imageLabeler.results(in: image) } catch let error { // Handle the error. return } // Show results.
Objective-C
NSError *error; NSArray*labels = [imageLabeler resultsInImage:image error:&error]; // Show results or handle the error.
4. Ottieni informazioni sulle entità etichettate
Se l'operazione di etichettatura delle immagini ha esito positivo, viene restituito un array diImageLabel. Ogni ImageLabel rappresenta un elemento etichettato nell'immagine. Puoi ottenere la descrizione testuale di ogni etichetta (se disponibile nei metadati del file del modello LiteRT), il punteggio di attendibilità e l'indice. Ad esempio:
Swift
for label in labels { let labelText = label.text let confidence = label.confidence let index = label.index }
Objective-C
for (MLKImageLabel *label in labels) { NSString *labelText = label.text; float confidence = label.confidence; NSInteger index = label.index; }
Suggerimenti per migliorare le prestazioni in tempo reale
Se vuoi etichettare le immagini in un'applicazione in tempo reale, segui queste linee guida per ottenere le migliori frequenze fotogrammi:
- Per l'elaborazione dei frame video, utilizza l'API sincrona
results(in:)del rilevatore. Chiama questo metodo dallaAVCaptureVideoDataOutputSampleBufferDelegatecaptureOutput(_, didOutput:from:)funzione per ottenere in modo sincrono i risultati dal frame video specificato. MantieniAVCaptureVideoDataOutputdialwaysDiscardsLateVideoFramescometrueper limitare le chiamate al rilevatore. Se diventa disponibile un nuovo frame video mentre il rilevatore è in esecuzione, verrà eliminato. - Se utilizzi l'output del rilevatore per sovrapporre elementi grafici all' immagine di input, ottieni prima il risultato da ML Kit, quindi esegui il rendering dell'immagine e della sovrapposizione in un unico passaggio. In questo modo, esegui il rendering sulla superficie di visualizzazione una sola volta per ogni frame di input elaborato. Per un esempio, consulta updatePreviewOverlayViewWithLastFrame nell'esempio di avvio rapido di ML Kit.