Il caso d'uso di analisi delle immagini fornisce alla tua app un'immagine accessibile dalla CPU su cui puoi eseguire l'elaborazione delle immagini, la visione artificiale o l'inferenza di machine learning. L'applicazione implementa un metodo analyze() che viene eseguito su ogni frame.
Per scoprire come integrare il Kit ML di Google con la tua app CameraX, consulta ML Kit Analyzer.
Modalità operative
Quando la pipeline di analisi dell'applicazione non riesce a tenere il passo con i requisiti di frequenza fotogrammi di CameraX, quest'ultima può essere configurata per eliminare i frame in uno dei seguenti modi:
non-blocking (predefinita): in questa modalità, l'esecutore memorizza sempre nella cache l'immagine più recente in un buffer di immagini (simile a una coda con una profondità di uno) mentre l'applicazione analizza l'immagine precedente. Se CameraX riceve una nuova immagine prima che l'applicazione termini l'elaborazione, la nuova immagine viene salvata nello stesso buffer, sovrascrivendo l'immagine precedente. Tieni presente che
ImageAnalysis.Builder.setImageQueueDepth()non ha alcun effetto in questo scenario e i contenuti del buffer vengono sempre sovrascritti. Puoi attivare questa modalità non bloccante chiamandosetBackpressureStrategy()conSTRATEGY_KEEP_ONLY_LATEST. Per saperne di più sulle implicazioni dell'esecutore, consulta la documentazione di riferimento perSTRATEGY_KEEP_ONLY_LATEST.blocking: in questa modalità, l'esecutore interno può aggiungere più immagini alla coda di immagini interna e inizia a eliminare i frame solo quando la coda è piena. Il blocco avviene nell'intero ambito del dispositivo della fotocamera: se il dispositivo della fotocamera ha più casi d'uso associati, questi verranno tutti bloccati mentre CameraX elabora queste immagini. Ad esempio, quando sia l'anteprima che l'analisi delle immagini sono associate a un dispositivo con fotocamera, anche l'anteprima viene bloccata mentre CameraX elabora le immagini. Puoi attivare la modalità di blocco passando
STRATEGY_BLOCK_PRODUCERasetBackpressureStrategy(). Puoi anche configurare la profondità della coda di immagini utilizzando ImageAnalysis.Builder.setImageQueueDepth().
Con un analizzatore a bassa latenza e ad alte prestazioni in cui il tempo totale per analizzare un'immagine è inferiore alla durata di un frame CameraX (ad esempio 16 ms per 60 fps), entrambe le modalità operative offrono un'esperienza complessiva fluida. La modalità di blocco può comunque essere utile in alcuni scenari, ad esempio quando si verificano jitter di sistema molto brevi.
Con un analizzatore ad alta latenza e ad alte prestazioni, è necessaria la modalità di blocco con una coda più lunga per compensare la latenza. Tieni presente, tuttavia, che l'applicazione può comunque elaborare tutti i frame.
Con un analizzatore ad alta latenza e che richiede molto tempo (l'analizzatore non è in grado di elaborare tutti i frame), una modalità non di blocco potrebbe essere una scelta più appropriata, poiché i frame devono essere eliminati per il percorso di analisi, ma altri casi d'uso associati simultanei possono comunque vedere tutti i frame.
Implementazione
Per utilizzare l'analisi delle immagini nella tua applicazione, segui questi passaggi:
- Crea un caso d'uso
ImageAnalysis. - Crea un
ImageAnalysis.Analyzer. - Imposta l'analizzatore su
ImageAnalysis. - Associa
il proprietario del ciclo di vita, il selettore della fotocamera e il caso d'uso
ImageAnalysisal ciclo di vita.
Subito dopo l'associazione, CameraX invia le immagini all'analizzatore registrato.
Al termine dell'analisi, chiama
ImageAnalysis.clearAnalyzer()
o scollega il caso d'uso ImageAnalysis per interrompere l'analisi.
Crea il caso d'uso ImageAnalysis
ImageAnalysis connette
l'analizzatore (un consumer di immagini) a CameraX, che è un producer di immagini.
Le applicazioni possono utilizzare
ImageAnalysis.Builder
per creare un oggetto ImageAnalysis. Con ImageAnalysis.Builder, l'applicazione può configurare quanto segue:
- Parametri di output dell'immagine:
- Formato: CameraX supporta
YUV_420_888eRGBA_8888tramitesetOutputImageFormat(int). Il formato predefinito èYUV_420_888. - Resolution e AspectRatio: puoi impostare uno di questi parametri, ma tieni presente che non puoi impostare entrambi i valori contemporaneamente.
- Rotazione.
- Nome target: utilizza questo parametro per il debug.
- Formato: CameraX supporta
- Controlli del flusso di immagini:
Le applicazioni possono impostare la risoluzione o le proporzioni, ma non entrambe. La risoluzione di output esatta dipende dalle dimensioni (o dalle proporzioni) richieste dall'applicazione e dalle funzionalità hardware e potrebbe essere diversa dalle dimensioni o dalle proporzioni richieste. Per informazioni sull'algoritmo di corrispondenza della risoluzione, consulta la documentazione relativa a setTargetResolution()
Un'applicazione può configurare i pixel dell'immagine di output in modo che siano negli spazi dei colori YUV (predefinito) o RGBA. Quando imposti un formato di output RGBA, CameraX converte internamente le immagini dallo spazio dei colori YUV a RGBA e pacchettizza i bit delle immagini nel ByteBuffer del primo piano di ImageProxy (gli altri due piani non vengono utilizzati) con la seguente sequenza:
ImageProxy.getPlanes()[0].buffer[0]: alpha
ImageProxy.getPlanes()[0].buffer[1]: red
ImageProxy.getPlanes()[0].buffer[2]: green
ImageProxy.getPlanes()[0].buffer[3]: blue
...
Quando esegui un'analisi delle immagini complessa in cui il dispositivo non riesce a tenere il passo con la frequenza fotogrammi, puoi configurare CameraX in modo che ignori i fotogrammi con le strategie descritte nella sezione Modalità operative di questo argomento.
Crea l'analizzatore
Le applicazioni possono creare analizzatori implementando l'interfaccia ImageAnalysis.Analyzer ed eseguendo l'override di analyze(ImageProxy image).
In ogni analizzatore, le applicazioni ricevono un
ImageProxy, che è un wrapper
per Media.Image.
Il formato dell'immagine può essere richiesto con
ImageProxy.getFormat().
Il formato è uno dei seguenti valori forniti dall'applicazione con ImageAnalysis.Builder:
ImageFormat.RGBA_8888se l'app ha richiestoOUTPUT_IMAGE_FORMAT_RGBA_8888.ImageFormat.YUV_420_888se l'app ha richiestoOUTPUT_IMAGE_FORMAT_YUV_420_888.
Consulta il caso d'uso Crea ImageAnalysis per le configurazioni dello spazio dei colori e per sapere dove è possibile recuperare i byte dei pixel.
All'interno di un analizzatore, l'applicazione deve:
- Analizza un determinato frame il più rapidamente possibile, preferibilmente entro il limite di tempo della frequenza fotogrammi specificata (ad esempio, meno di 32 ms per un caso di 30 f/s). Se l'applicazione non riesce ad analizzare un frame abbastanza rapidamente, prendi in considerazione uno dei meccanismi di frame dropping supportati.
- Rilascia
ImageProxysu CameraX chiamandoImageProxy.close(). Tieni presente che non devi chiamare la funzione di chiusura di Media.Image con wrapping (Media.Image.close()).
Le applicazioni possono utilizzare direttamente l'oggetto Media.Image con wrapping all'interno di ImageProxy.
Non chiamare Media.Image.close() sull'immagine con wrapper, perché ciò interromperebbe il meccanismo di condivisione delle immagini all'interno di CameraX; utilizza invece ImageProxy.close() per rilasciare l'oggetto Media.Image sottostante a CameraX.
Configura l'analizzatore per ImageAnalysis
Dopo aver creato un analizzatore, utilizza
ImageAnalysis.setAnalyzer()
per registrarlo e iniziare l'analisi. Al termine dell'analisi, utilizza ImageAnalysis.clearAnalyzer() per rimuovere l'analizzatore registrato.
È possibile configurare un solo analizzatore attivo per l'analisi delle immagini. La chiamata di ImageAnalysis.setAnalyzer() sostituisce l'analizzatore registrato se esiste già. Le applicazioni possono impostare un nuovo analizzatore in qualsiasi momento, prima o dopo l'associazione
del caso d'uso.
Associa ImageAnalysis a un ciclo di vita
Ti consigliamo vivamente di associare il tuo ImageAnalysis a un ciclo di vita AndroidX esistente con la funzione ProcessCameraProvider.bindToLifecycle(). Tieni presente che la funzione bindToLifecycle() restituisce il dispositivo Camera selezionato, che può essere utilizzato per ottimizzare le impostazioni avanzate, come l'esposizione e altre. Per ulteriori informazioni sul controllo dell'output della videocamera, consulta questa guida.
L'esempio seguente combina tutti i passaggi precedenti, associando i casi d'uso di CameraX ImageAnalysis e Preview a un proprietario lifeCycle:
val imageAnalysis = ImageAnalysis.Builder() // enable the following line if RGBA output is needed. // .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) .setTargetResolution(Size(1280, 720)) .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build() imageAnalysis.setAnalyzer(executor, ImageAnalysis.Analyzer { imageProxy -> val rotationDegrees = imageProxy.imageInfo.rotationDegrees // insert your code here. ... // after done, release the ImageProxy object imageProxy.close() }) cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, imageAnalysis, preview)
Risorse aggiuntive
Per scoprire di più su CameraX, consulta le seguenti risorse aggiuntive.
Codelab
Esempio di codice