Analisi delle immagini

L'analisi delle immagini nel caso d'uso fornisca alla tua app un'immagine accessibile alla CPU su cui eseguire l'elaborazione di immagini, la visione artificiale o l'inferenza del machine learning. La un'applicazione implementa analyze() che viene eseguito su ogni frame.

Per scoprire come integrare ML Kit di Google con l'app CameraX, consulta Strumento di analisi ML Kit.

Modalità operative

Quando la pipeline di analisi dell'applicazione non riesce a stare al passo con il frame di CameraX di frequenza effettiva, CameraX può essere configurata in modo da rilasciare fotogrammi in uno dei seguenti modi:

  • non-coding (predefinito): in questa modalità, l'esecutore memorizza sempre nella cache l'ultima immagine nel buffer (simile a una coda con profondità di 1) mentre l'applicazione analizza l'immagine precedente. Se FotocameraX riceve una nuova immagine prima che l'applicazione termini l'elaborazione, la nuova immagine viene salvata nello stesso buffer, sovrascrivendo quella 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 di blocco chiamando setBackpressureStrategy() con STRATEGY_KEEP_ONLY_LATEST Per ulteriori informazioni sulle implicazioni per gli esecutori, consulta il riferimento documentazione di STRATEGY_KEEP_ONLY_LATEST

  • block: in questa modalità, l'esecutore interno può aggiungere più immagini alla coda delle immagini interna e inizia a eliminare i frame solo quando la coda pieno. Il blocco si verifica nell'intero ambito del dispositivo videocamera: se fotocamera ha più casi d'uso correlati, bloccato durante l'elaborazione di queste immagini da parte di CameraX. Per ad esempio, quando a un dispositivo Fotocamera sono associate sia l'analisi dell'anteprima che l'analisi delle immagini, allora l'anteprima verrà bloccata anche durante l'elaborazione delle immagini da parte di CameraX. Puoi abilitare la modalità di blocco passando STRATEGY_BLOCK_PRODUCER a setBackpressureStrategy(). 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 analizzare un'immagine è inferiore alla durata di un fotogramma di CameraX (16 ms per 60 fps, ad esempio), entrambe le modalità operative offrono una fluidità complessiva un'esperienza senza intervento manuale. La modalità di blocco può comunque essere utile in alcuni scenari, ad esempio quando si ha a che fare con tremolio del sistema molto brevi.

Con uno strumento ad alta latenza e prestazioni elevate, la modalità di blocco una coda più lunga per compensare la latenza. Tieni presente, tuttavia, che un'applicazione può comunque elaborare tutti i frame.

Con un analizzatore a latenza elevata e che richiede molto tempo (l'analizzatore non è in grado di elaborare frame), una modalità non di blocco potrebbe essere una scelta più appropriata, 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, segui questi passaggi:

Subito dopo il binding, CameraX invia le immagini all'analizzatore registrato. Dopo aver completato l'analisi, chiama ImageAnalysis.clearAnalyzer() oppure slegare il caso d'uso ImageAnalysis per interrompere l'analisi.

Caso d'uso di Build ImageAnalysis

ImageAnalysis si connette analizzatore (un consumatore di immagini) a CameraX, che produce immagini. Le applicazioni possono utilizzare ImageAnalysis.Builder per creare un oggetto ImageAnalysis. Con ImageAnalysis.Builder, può configurare quanto segue:

Le applicazioni possono impostare la risoluzione o il formato, ma non entrambi. La risoluzione esatta dell'output dipende dalle dimensioni richieste dall'applicazione (o proporzioni) e hardware e potrebbe differire dalle richieste dimensioni o proporzioni. Per informazioni sull'algoritmo di corrispondenza della risoluzione, consulta la documentazione setTargetResolution()

Un'applicazione può configurare i pixel dell'immagine di output in modo che siano in YUV (impostazione predefinita) con spazi colore RGBA. Quando imposti un formato di output RGBA, CameraX internamente converte le immagini dallo spazio colore YUV allo spazio colore 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 si esegue un'analisi complicata di immagini in cui il dispositivo non può memorizzare aumenta con la frequenza fotogrammi, puoi configurare CameraX in modo da rimuovere fotogrammi le strategie descritte nella sezione Modalità operative di questo argomento.

Crea il tuo analizzatore

Le applicazioni possono creare analizzatori implementando ImageAnalysis.Analyzer ed eseguire l'override analyze(ImageProxy image). In ogni analizzatore, le applicazioni ricevono ImageProxy, che è un wrapper per Media.Image. È possibile eseguire query sul formato dell'immagine ImageProxy.getFormat() Il formato è uno dei seguenti valori che l'applicazione fornisce i seguenti vantaggi: ImageAnalysis.Builder:

  • ImageFormat.RGBA_8888 se l'app ha richiesto OUTPUT_IMAGE_FORMAT_RGBA_8888.
  • ImageFormat.YUV_420_888 se l'app ha richiesto OUTPUT_IMAGE_FORMAT_YUV_420_888.

Consulta il caso d'uso di Build ImageAnalysis per le configurazioni dello spazio colore e dove è possibile recuperare i byte pixel.

All'interno di uno strumento di analisi, l'applicazione deve fare quanto segue:

  1. Analizza un determinato frame il più rapidamente possibile, preferibilmente all'interno un determinato limite di tempo di frequenza frame (ad esempio, inferiore a 32 ms per il caso a 30 f/s). Se l'applicazione non è in grado di analizzare un frame abbastanza velocemente, prendi in considerazione uno dei meccanismi di interruzione del frame supportati.
  2. Rilascia ImageProxy per CameraX chiamando ImageProxy.close() Tieni presente che non devi chiamare la funzione di chiusura di Media.Image sottoposta a wrapping (Media.Image.close())

Le applicazioni possono utilizzare l'oggetto Media.Image aggregato direttamente all'interno di ImageProxy. Non chiamare Media.Image.close() sull'immagine aggregata perché si romperebbe il meccanismo di condivisione delle immagini all'interno di CameraX; usa invece ImageProxy.close() per rilasciare Media.Image sottostante a CameraX.

Configura il tuo analizzatore per ImageAnalysis

Dopo aver creato uno strumento di analisi, utilizza ImageAnalysis.setAnalyzer() registrarlo per iniziare l'analisi. Al termine dell'analisi, utilizza ImageAnalysis.clearAnalyzer() per rimuovere lo strumento di analisi registrato.

È possibile configurare un solo analizzatore attivo per l'analisi delle immagini. Chiamata in corso ImageAnalysis.setAnalyzer() sostituisce lo strumento di analisi registrato, se è già esiste già. Le applicazioni possono impostare un nuovo analizzatore in qualsiasi momento, prima o dopo l'associazione caso d'uso.

Associa l'analisi delle immagini a un ciclo di vita

Ti consigliamo vivamente di associare ImageAnalysis a un account esistente Ciclo di vita di AndroidX con ProcessCameraProvider.bindToLifecycle() personalizzata. Tieni presente che la funzione bindToLifecycle() restituisce la selezione Camera, che può essere usato per regolare con precisione le impostazioni avanzate come l'esposizione e altre. Consulta questa guida per ulteriori informazioni sul controllo dell'output della videocamera.

L'esempio seguente combina tutti i passaggi precedenti, associando Casi d'uso di CameraX ImageAnalysis e Preview per 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 risorse aggiuntive che seguono.

Codelab

  • Iniziare a usare CameraX
  • Esempio di codice

  • Esempi di app CameraX