Il caso d'uso dell'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 del machine learning. L'applicazione implementa un metodo analyze()
che viene eseguito su ogni frame.
Per scoprire come integrare ML Kit di Google con la tua app CameraX, consulta ML Kit Analyzer.
Modalità operative
Quando la pipeline di analisi dell'applicazione non è in grado di soddisfare i requisiti di frequenza fotogrammi di CameraX, CameraX può essere configurata per rilasciare i frame in uno dei seguenti modi:
non bloccante (impostazione predefinita): in questa modalità, l'esecutore memorizza sempre nella cache l'immagine più recente in un buffer immagine (simile a una coda con 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 che i contenuti del buffer vengono sempre sovrascritti. Puoi attivare questa modalità non di blocco chiamandosetBackpressureStrategy()
conSTRATEGY_KEEP_ONLY_LATEST
. Per saperne di più sulle implicazioni per gli esecutori, consulta la documentazione di riferimento perSTRATEGY_KEEP_ONLY_LATEST
.Blocco: 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 si verifica nell'intero ambito del dispositivo della fotocamera: se il dispositivo della videocamera ha più casi d'uso associati, questi casi d'uso verranno tutti bloccati durante l'elaborazione di queste immagini da parte di CameraX. Ad esempio, quando sia l'anteprima sia l'analisi delle immagini sono associate a un dispositivo Fotocamera, anche l'anteprima viene bloccata mentre CameraX elabora le immagini. Per attivare la modalità di blocco, passa
STRATEGY_BLOCK_PRODUCER
asetBackpressureStrategy()
. Puoi anche configurare la profondità della coda delle immagini utilizzando ImageAnalysis.Builder.setImageQueueDepth().
Grazie a un analizzatore a bassa latenza e ad alte prestazioni in cui il tempo totale per analizzare un'immagine è inferiore alla durata di un fotogramma di CameraX (ad esempio 16 ms per 60 f/s), entrambe le modalità operative offrono un'esperienza generale omogenea. La modalità di blocco può comunque essere utile in alcuni scenari, ad esempio in caso di tremolio di sistema molto brevi.
Con uno strumento di analisi ad alte prestazioni e ad alta latenza, è necessaria la modalità di blocco con una coda più lunga per compensare la latenza. Tuttavia, l'applicazione può ancora elaborare tutti i frame.
Con un analizzatore dispendioso in termini di tempo e latenza elevata (l'analizzatore non è in grado di elaborare tutti i frame), potrebbe essere più appropriata una modalità non di blocco, in quanto i frame devono essere eliminati per il percorso di analisi, ma altri casi d'uso associati in contemporanea possono comunque vedere tutti i frame.
Implementazione
Per utilizzare l'analisi delle immagini nella tua applicazione, procedi nel seguente modo:
- Crea un caso d'uso di
ImageAnalysis
. - Crea una
ImageAnalysis.Analyzer
. - Imposta l'analizzatore su
ImageAnalysis
. - Associa
al ciclo di vita il proprietario del ciclo di vita, il selettore della videocamera e il caso d'uso
ImageAnalysis
.
Subito dopo l'associazione, CameraX invia le immagini all'analizzatore registrato.
Dopo aver completato l'analisi, chiama ImageAnalysis.clearAnalyzer()
o svincola il caso d'uso ImageAnalysis
per interrompere l'analisi.
Crea caso d'uso ImageAnalysis
ImageAnalysis
connette l'analizzatore (un consumer di immagini) a CameraX, che produce immagini.
Le applicazioni possono usare 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_888
eRGBA_8888
tramitesetOutputImageFormat(int)
. Il formato predefinito èYUV_420_888
. - Risoluzione e Proporzioni: puoi impostare uno di questi parametri, ma non puoi impostare entrambi i valori contemporaneamente.
- Rotazione.
- Nome target: utilizza questo parametro per scopi di debug.
- Formato: CameraX supporta
- Controlli di flusso delle immagini:
Le applicazioni possono impostare la risoluzione o le proporzioni, ma non entrambe. La risoluzione esatta dell'output dipende dalle dimensioni (o proporzioni) richieste dell'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 per setTargetResolution()
Un'applicazione può configurare i pixel dell'immagine di output in modo che siano in spazi colore YUV (predefinito) o RGBA. Quando si imposta un formato di output RGBA, CameraX converte internamente
le immagini dallo spazio colore YUV a RGBA e comprime i bit di immagine 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 analisi di immagini complesse in cui il dispositivo non riesce a tenere il passo con la frequenza fotogrammi, puoi configurare CameraX in modo che rilasci i frame con le strategie descritte nella sezione Modalità operative di questo argomento.
Crea l'analizzatore
Le applicazioni possono creare analizzatori implementando l'interfaccia ImageAnalysis.Analyzer
e eseguendo l'override di analyze(ImageProxy image)
.
In ogni analizzatore, le applicazioni ricevono un ImageProxy
, che è un wrapper per Media.Image.
Per eseguire query sul formato dell'immagine, puoi utilizzare
ImageProxy.getFormat()
.
Il formato è uno dei seguenti valori forniti dall'applicazione con ImageAnalysis.Builder
:
ImageFormat.RGBA_8888
se l'app ha richiestoOUTPUT_IMAGE_FORMAT_RGBA_8888
.ImageFormat.YUV_420_888
se l'app ha richiestoOUTPUT_IMAGE_FORMAT_YUV_420_888
.
Consulta il caso d'uso Build ImageAnalysis per le configurazioni dello spazio colore e dove è possibile recuperare i byte in 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 frame specificato (ad esempio, meno di 32 ms per caso di 30 f/s). Se l'applicazione non è in grado di analizzare un frame abbastanza rapidamente, prendi in considerazione uno dei meccanismi di eliminazione dei frame supportati.
- Rilascia
ImageProxy
a CameraX chiamando il numeroImageProxy.close()
. Tieni presente che non devi chiamare la funzione di chiusura dell'immagine Media.Image con wrapping (Media.Image.close()
).
Le applicazioni possono utilizzare il Media.Image
con wrapping direttamente in ImageProxy.
Non chiamare Media.Image.close()
nell'immagine a capo perché questo comprometterebbe il meccanismo di condivisione delle immagini all'interno di CameraX; utilizza invece ImageProxy.close()
per rilasciare il valore Media.Image
sottostante a CameraX.
Configura l'analizzatore per ImageAnalysis
Una volta 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 a
ImageAnalysis.setAnalyzer()
sostituisce l'analizzatore registrato, se
esiste. Le applicazioni possono impostare un nuovo analizzatore in qualsiasi momento, prima o dopo l'associazione del caso d'uso.
Associare l'analisi delle immagini a un ciclo di vita
Ti consigliamo vivamente di associare 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 perfezionare le impostazioni avanzate, come l'esposizione e altre ancora. Consulta questa guida per ulteriori informazioni su come controllare l'output della videocamera.
L'esempio seguente combina tutto ciò dei passaggi precedenti, associando i casi d'uso di CameraX ImageAnalysis
e Preview
a un proprietario di lifeCycle
:
Kotlin
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)
Java
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder() // enable the following line if RGBA output is needed. //.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) .setTargetResolution(new Size(1280, 720)) .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build(); imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() { @Override public void analyze(@NonNull ImageProxy imageProxy) { int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees(); // insert your code here. ... // after done, release the ImageProxy object imageProxy.close(); } }); cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, imageAnalysis, preview);
Risorse aggiuntive
Per saperne di più su CameraX, consulta le seguenti risorse aggiuntive.
Codelab
Esempio di codice