Nozioni di base sulle app

Miglioramento delle esperienze con la fotocamera su tutti i dispositivi con CameraX e l'intelligence on-device

Altoparlanti

Informazioni

Informazioni sulla presentazione

Gli utenti si aspettano che le app di terze parti acquisiscano foto e video con la stessa alta fedeltà della fotocamera nativa del dispositivo, indipendentemente dalle condizioni di illuminazione o dal livello hardware. Offrire questa coerenza nell'ecosistema Android in espansione comporta importanti considerazioni sull'architettura. Questa sessione mostra come creare pipeline di acquisizione solide e professionali che massimizzano le funzionalità del dispositivo, pur rimanendo affidabili su tutti i fattori di forma.

Esploreremo gli ultimi progressi di CameraX, mostrandoti come integrare funzionalità all'avanguardia come le foto in movimento e i miglioramenti con l'AI on-device tramite Google Play Services, oltre alle esperienze spaziali utilizzando l'SDK Jetpack XR. Esamineremo anche la nostra competenza CameraX, che consente all'agente di programmazione che preferisci di implementare automaticamente i concetti di questo talk e altro ancora.

Riepilogo

  • Jetpack CameraX è la libreria della fotocamera consigliata per le app per Android, poiché Camera1 è deprecata. L'applicazione delle norme di Play inizierà a disattivare Camera1 il prossimo anno in Android 18.
  • CameraXViewfinder adatta le anteprime della fotocamera a diversi fattori di forma, come i pieghevoli. In CameraX 1.7, aggiunge i controlli tramite gesti e il supporto del flash dello schermo.
  • Gli occhiali con audio e display eseguono app su uno smartphone host, esponendo al contempo le fotocamere su entrambi i dispositivi. Il passaggio di ProjectedDeviceContext consente a CameraX di acquisire immagini direttamente dagli occhiali.
  • L'API Feature Group aiuta le app a selezionare combinazioni supportate di funzionalità della fotocamera. A partire da CameraX 1.6, è supportata la combinazione della registrazione in 4K con la stabilizzazione video.
  • Il machine learning on-device analizza le anteprime della fotocamera e i contenuti multimediali acquisiti tramite ML Kit e MediaPipe. Gli sviluppatori possono eseguire attività che vanno dal rilevamento dei gesti in tempo reale alle descrizioni di immagini create dall'AI.

Risorse

Gemini Notebook

Argomenti

  • camerax
  • android-camera
  • on-device-ml
  • gemini-nano
  • mediapipe
  • ml-kit
  • android-xr

Trascrizione

Scarica la trascrizione

Introduzione e panoramica di CameraX

  • Ciao,

  • Ti diamo il benvenuto alla nostra sessione.

  • Sono Aman e con me c'è Scott.

  • Oggi siamo davvero entusiasti di parlare di come puoi migliorare le tue esperienze con la fotocamera su tutti i dispositivi con CameraX e l'intelligence on-device.

  • Iniziamo.

  • Pensa a come utilizzi i tuoi smartphone.

  • Spesso utilizziamo la fotocamera dello smartphone per immortalare momenti e condividerli con i nostri cari.

  • La fotocamera è diventata un elemento centrale dell'esperienza d'uso degli smartphone.

  • In effetti, una buona fotocamera è spesso un fattore chiave per l'acquisto di uno smartphone.

  • Oggi parleremo di due temi generali per la creazione di esperienze con la fotocamera di alta qualità.

  • Innanzitutto, esploreremo alcune funzionalità di CameraX, poi scopriremo alcune tecniche di machine learning on-device.

  • Iniziamo con CameraX.

  • Jetpack CameraX supporta l'esperienza con la fotocamera su Android.

  • Oltre a CameraX, abbiamo anche Camera1 e Camera2, che fanno parte del framework della piattaforma Android.

  • Quindi, quale libreria dovresti utilizzare?

  • Camera1 era l'API della fotocamera originale su Android.

  • Ora è deprecata, quindi le nuove app dovrebbero utilizzare Camera2 o CameraX.

  • Camera2 è subentrata a Camera1.

  • Quindi, se hai bisogno di un controllo della fotocamera di basso livello per casi d'uso complessi, Camera2 è una buona opzione.

  • Tuttavia, richiede la gestione manuale delle configurazioni specifiche del dispositivo.

  • Infine, Jetpack CameraX si basa su Camera2.

  • Fornisce un'API coerente e gestisce automaticamente le configurazioni specifiche del dispositivo.

  • È la scelta consigliata per la maggior parte degli sviluppatori.

  • Abbiamo un'osservazione molto importante da fare.

  • Abbiamo in programma di disattivare Camera1 e questo inizierà con l'applicazione delle norme di Google Play il prossimo anno in Android 18.

  • Se utilizzi ancora l'API Camera1 precedente, dovrai eseguire la migrazione a CameraX o Camera2.

  • Perché dovresti utilizzare CameraX?

  • Innanzitutto, supporta Android 7 e versioni successive, il che lo rende compatibile con quasi il 99% dei dispositivi Android attivi.

  • In secondo luogo, è facile da usare e fornisce API semplici per casi d'uso comuni come l'anteprima, l'acquisizione e la registrazione con meno codice.

  • In terzo luogo, offre un'esperienza coerente su tutti i dispositivi riducendo i problemi specifici del dispositivo, come l'allungamento dell'anteprima, che è abbastanza comune su pieghevoli e tablet.

  • Infine, semplifica l'implementazione di funzionalità OEM avanzate come la modalità notturna e la modalità Ritratto.

  • Ora vorrei invitare Scott a parlare di alcune delle funzionalità di CameraX.

  • A te la parola, Scott.

  • Grazie, Aman.

  • Ciao,

  • Mi chiamo Scott.

  • Oggi parleremo di diverse funzionalità di CameraX che ti consentiranno di creare un'esperienza con la fotocamera di livello professionale.

Funzionalità del mirino adattivo

  • La prima è il mirino adattivo.

  • È progettato per semplificare completamente la gestione dell'anteprima su diversi fattori di forma e dimensioni dello schermo.

  • Gli utenti ora dispongono di una varietà di dispositivi, tra cui smartphone pieghevoli, smartphone, laptop e dispositivi XR.

  • Pertanto, è più importante che mai creare un'esperienza con la fotocamera adatta ai nuovi fattori di forma.

  • Inoltre, l'anteprima della fotocamera è notoriamente difficile da realizzare, soprattutto sul widescreen pieghevole.

  • Su questi dispositivi, quando sono aperti, la fotocamera interna è montata in orizzontale, mentre quella posteriore è montata in verticale.

  • Quindi, se si presume che tutti i sensori della fotocamera siano montati verticalmente, si verificherà un disallineamento spaziale che causerà la distorsione o l'inclinazione.

  • Inoltre, CameraXViewfinder è progettato per gestire completamente la complessità al posto tuo, garantendo così che l'anteprima della fotocamera funzioni senza problemi su tutti i fattori di forma.

  • Vediamo come utilizzare il componibile CameraXViewfinder.

    var surfaceRequest by remember {
        mutableStateOf<SurfaceRequest?>(null)
    }
    
    LaunchedEffect(...) {
        preview.setSurfaceProvider { surfaceRequest = it }
        cameraProvider.bindToLifecycle(..., preview)
    }
    
    surfaceRequest?.let { request ->
        CameraXViewfinder(
            surfaceRequest = request,
            contentScale = ContentScale.Fit
        )
    }
  • Innanzitutto, dichiari la variabile di contenuto surfaceRequest per contenere la richiesta di superficie.

  • Mi dispiace.

  • In secondo luogo, in LaunchedEffect, imposti il provider di superficie in modo che intercetti un oggetto di richiesta di superficie.

  • Poi, esegui il binding al ciclo di vita e avvii la fotocamera.

  • Infine, ogni volta che lo stato viene aggiornato con una richiesta di superficie valida e attiva la ricomposizione, imposti la richiesta direttamente su CameraXViewfinder.

  • Qui puoi impostare l'opzione contentScale su Adatta o Ritaglia, a seconda delle tue preferenze.

  • Ecco fatto, ora è tutto pronto.

  • In CameraX 1.7, abbiamo aggiunto diverse nuove funzionalità a CameraXViewfinder.

  • Sono inclusi nuovi gesti come il tocco per mettere a fuoco o il pizzico per aumentare lo zoom.

  • Supporta anche il flash dello schermo, che ti consente di utilizzare uno schermo per illuminare il tuo selfie.

  • Implementare questa funzionalità è semplice.

    CameraXViewfinder(
        surfaceRequest = viewModel.surfaceRequest,
        contentScale = ContentScale.Fit,
        isTapToFocusEnabled = true,
        isPinchToZoomEnabled = true,
        onScreenFlashReady =
            {
               imageCapture.screenFlash = it
               imageCapture.flashMode = FLASH_MODE_SCREEN
            }
    )
  • Basta impostare su true le opzioni Tocca per mettere a fuoco e Pizzica per eseguire lo zoom.

  • Per il flash dello schermo, ottieni l'istanza del flash dello schermo dal callback onScreenFlashReady, quindi la passi a ImageCapture e imposti una modalità flash su FLASH_MODE_SCREEN.

  • Questo è tutto.

Acquisizione con la fotocamera con Android XR

  • Abbiamo visto come CameraX consente l'anteprima della fotocamera che funziona perfettamente su tutti i fattori di forma.

  • Ora facciamo un ulteriore passo avanti con l'acquisizione della fotocamera su Android XR.

  • Esistono tre categorie di dispositivi XR: la prima è quella dei visori XR.

  • Si tratta di visori completamente chiusi e immersivi che utilizzano la fotocamera per acquisire il mondo fisico e visualizzarlo all'interno dei visori.

  • E, in secondo luogo, gli occhiali XR con cavo.

  • Oggi abbiamo annunciato XREAL Aura nel keynote di questa categoria.

  • Come puoi vedere nei keynote, si tratta di occhiali trasparenti collegati al puck di elaborazione che ti consentono di visualizzare i contenuti virtuali sovrapposti al mondo reale.

  • E la terza, occhiali audio e con display.

  • Questi sono gli occhiali leggeri.

  • Possono combinare audio, videocamera e display per esperienze con comandi vocali e di facile consultazione.

  • Le prime due categorie, visori XR e occhiali XR con cavo, supportano anche Camera2 e CameraX, proprio come un normale smartphone.

  • Oggi ci concentreremo solo sugli occhiali audio e con display.

  • Su questi occhiali, le app vengono eseguite sullo smartphone Android, lo smartphone Android host, anziché sugli occhiali, ma qui l'accesso è sia alla fotocamera dello smartphone sia a quella degli occhiali.

  • La domanda chiave è: come fai a sapere con quale videocamera stai parlando?

  • Quindi è semplice.

  • Con il contesto standard, CameraX accede alla fotocamera dello smartphone.

  • Inoltre, con ProjectedDeviceContext, CameraX accede alla fotocamera degli occhiali.

  • Pertanto, un contesto diverso porterà a una videocamera target diversa.

  • Ricorda che le autorizzazioni per la fotocamera e gli occhiali sono separate.

  • Le autorizzazioni per lo smartphone e per gli occhiali sono separate, quindi devi richiedere l'autorizzazione per gli occhiali separatamente.

  • L'altra opzione è utilizzare l'attività proiettata, che viene eseguita anche sui dispositivi Android host, ma la UI viene proiettata sugli occhiali.

  • In questo caso, la regola si inverte.

  • Se utilizzi Context standard, accederai alla fotocamera degli occhiali.

  • Se vuoi accedere alla fotocamera dello smartphone, devi utilizzare HostContext.

  • Diamo un'occhiata al codice per vedere come possiamo acquisire immagini utilizzando la fotocamera degli occhiali.

    // In a coroutine
    val imageCapture = ImageCapture.Builder().build()
    
    ProjectedContext.isProjectedDeviceConnected(activity, coroutineContext)
        .collectLatest { isConnected ->
            if (isConnected) {
                val projectedContext = ProjectedContext.createProjectedDeviceContext(activity)
                val cameraConfig = CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig())
                    .setRepeatingStreamForced(false)
                    .build()
                val cameraProvider = LifecycleCameraProvider.createInstance(projectedContext, cameraConfig)
                cameraProvider.bindToLifecycle(activity, DEFAULT_BACK_CAMERA, imageCapture)
            }
        }
    // Shutter button clicked
    imageCapture.takePicture(...)
  • Innanzitutto, richiama isProjectedDeviceConnected per verificare se gli occhiali sono connessi o meno.

  • Poi chiami createProjectedDeviceContext per ottenere un projectedContext.

  • In secondo luogo, qui utilizzi LifecycleCameraProvider per inizializzare CameraX, anziché ProcessCameraProvider.

  • ProcessCameraProvider è un singleton, quindi non puoi modificare il contesto dopo l'inizializzazione.

  • L'utilizzo di LifecycleCameraProvider ti consente di modificare il contesto in qualsiasi momento.

  • Poi, devi disattivare lo stream ripetuto aggiuntivo in CameraX.

  • Questo è necessario perché gli occhiali attuali supportano un solo stream.

  • Al momento l'API è interna, ma la renderemo pubblica a breve.

  • Questo è tutto.

  • Da qui, si tratta di CameraX standard: basta associare ImageCapture e ora stai acquisendo tramite gli occhiali.

Acquisisci funzionalità e API

  • Ok.

  • Ora vediamo come CameraX ti aiuta a trovare la combinazione di funzionalità che funzionano insieme e a ottenere il meglio dal dispositivo.

  • Le app fotocamera moderne sono caratterizzate da funzionalità potenti e gli utenti si aspettano che la fotocamera supporti funzionalità come HDR, 60 f/s e stabilizzazione dell'anteprima, tutte contemporaneamente.

  • Tuttavia, in qualità di sviluppatore, sappiamo che combinare queste funzionalità non è sempre semplice.

  • La verifica del supporto delle singole funzionalità non garantisce che funzionino insieme.

  • Questa incertezza ha costretto gli sviluppatori a essere prudenti e a limitare l'esperienza degli utenti sui dispositivi compatibili.

  • Per risolvere questo problema, abbiamo introdotto l'API Feature Group, basata sul framework di query per la combinazione di funzionalità di Camera2.

  • Esistono due modi per utilizzarlo: innanzitutto, utilizza requiredFeatureGroup per controllare e attivare la combinazione di funzionalità quando è supportata.

  • In secondo luogo, puoi fornire la priorità delle funzionalità tramite preferredFeatureGroup, dopodiché CameraX sceglie la migliore combinazione supportata per te.

  • Ecco un esempio.

  • A destra, a sinistra, scusa, con l'opzione "Nessuna" attiva, è solo un telefono normale, una registrazione normale.

  • A sinistra, attiviamo contemporaneamente HDR, 60 FPS e Stabilizzazione anteprima.

  • Come puoi vedere, la qualità è migliorata notevolmente con un video più luminoso, fluido e senza tremolii.

  • Diamo un'occhiata al codice.

    cameraProvider.bindToLifecycle(
        lifecycleOwner,
        cameraSelector,
        SessionConfig(
            useCases = listOf(preview, videoCapture),
            // HDR_HLG10 > FPS_60 > Preview Stabilization.
            preferredFeatureGroup =
               listOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION),
        )
    )
  • In questo caso, utilizziamo preferredFeatureGroup per fornire l'elenco delle priorità delle funzionalità, ovvero HDR, 60 f/s e stabilizzazione dell'anteprima.

  • CameraX controllerà la combinazione e selezionerà quelle migliori supportate dal dispositivo.

  • Con CameraX 1.6 e versioni successive, aggiungiamo la registrazione in 4K e la stabilizzazione video direttamente nell'API Feature Group.

    // CameraX 1.6+ supports:
    // 4K, video stabilization & Effect
    val sessionConfig = SessionConfig(
       useCases = listOf(preview, videoCapture),
       requiredFeatureGroup =
         setOf(UHD_RECORDING, VIDEO_STABILIZATION),
       effects = listOf(overlayEffect)
    )
  • La combinazione di 4K e stabilizzazione video è supportata da molti dispositivi premium.

  • Ora, con l'API Feature Group, puoi attivarle insieme in tutta sicurezza.

  • Inoltre, ora hai la flessibilità di applicare l'effetto in tempo reale con l'API Groups, cosa che prima non era possibile.

  • Ora parliamo di come acquisire immagini di alta qualità in CameraX.

  • CameraX ora supporta l'acquisizione RAW DNG.

  • Ti consente di accedere all'immagine RAW non elaborata e non compressa direttamente dal sensore della fotocamera per l'editing professionale.

  • Inoltre, abbiamo migliorato l'estensione della modalità notturna.

  • Questa estensione consente di scattare foto luminose e nitide in condizioni di scarsa illuminazione senza utilizzare il flash.

  • Abbiamo anche introdotto una nuova API Night Mode Indicator.

  • Monitorerà quando l'ambiente corrente è buio e adatto alla modalità notturna e potrai utilizzarlo per mostrare l'indicatore della modalità notturna.

  • Inoltre, Ultra HDR è ora supportato nelle estensioni CameraX.

  • In questo modo, la modalità notturna offre una gamma dinamica più ampia e colori vivaci. Al momento, la modalità notturna con Ultra HDR è supportata su molti dispositivi premium recenti.

  • Qui puoi vedere la differenza tra la modalità normale, notturna e la modalità notturna con Ultra HDR.

  • Vediamo come implementare questa soluzione.

    val cameraInfo = cameraProvider.getCameraInfo(cameraSelector,
            ExtensionSessionConfig(ExtensionMode.NIGHT, extensionsManager))
    
    val imageCapabilities = ImageCapture.getImageCaptureCapabilities(cameraInfo)
    
    val imageCapture = ImageCapture.Builder().apply {
           if (imageCapabilities.supportedOutputFormats
                    .contains(OUTPUT_FORMAT_JPEG_ULTRA_HDR)) {
               setOutputFormat(OUTPUT_FORMAT_JPEG_ULTRA_HDR)
           }
         }.build()
    
    val extensionSessionConfig = ExtensionSessionConfig(
        ExtensionMode.NIGHT, extensionsManager, preview, imageCapture
    )
    
    cameraProvider.bindToLifecycle(...,  extensionSessionConfig)
  • Innanzitutto, crea un ExtensionSessionConfig per la modalità notturna e utilizzalo per ottenere l'istanza CameraInfo.

  • Poi, utilizza CameraInfo per ottenere la funzionalità di acquisizione delle immagini e verifica se Ultra HDR è supportato.

  • Quindi, imposta il formato di output su Ultra HDR.

  • Infine, crei di nuovo ExtensionSessionConfig con i casi d'uso e lo associ al ciclo di vita.

  • Ora puoi scattare foto con la modalità notturna con Ultra HDR.

  • Inoltre, abbiamo aggiunto il supporto di Foto in movimento a CameraX.

  • Le foto in movimento acquisiscono l'audio e il movimento intorno alla foto, preservando il momento, non solo un'immagine fissa.

  • Standardizziamo questo processo su diversi smartphone e dispositivi Android e semplifichiamo il supporto delle foto in movimento.

  • Le foto in movimento saranno disponibili in CameraX nel primo trimestre del 2027.

  • Una volta disponibile, imposta la modalità Foto in movimento in ImageCapture.Builder e inizia a scattare foto in movimento.

    val imageCapture = ImageCapture.Builder()
            .setMotionPhotoMode(
                 ImageCapture.MOTION_PHOTO_MODE_ON,
                 customConfig
             )
            .build()
    
    cameraProvider.bindToLifecycle(.. imageCapture)
    imageCapture.takePicture(...)
  • Ora vediamo come CameraX consente la registrazione di video ad alta velocità.

  • La registrazione nitida di azioni in rapido movimento è una funzionalità essenziale delle moderne app per fotocamera.

  • È particolarmente utile per scenari dal ritmo frenetico come lo sport.

  • Questo risultato si ottiene tramite l'acquisizione ad alta velocità a 120 o 240 fps.

  • Puoi utilizzarla in due modi.

  • Innanzitutto, codifica alla stessa frequenza fotogrammi, poi crea un vero e proprio video con frequenza fotogrammi elevata.

  • L'altra opzione è codificarlo a 30 f/s per creare un video in slow motion pronto per la riproduzione.

  • Ad esempio, un secondo registrato a 120 f/s richiede quattro secondi per essere riprodotto a 30 f/s.

  • Quindi, questo intervallo di tempo crea un effetto slow motion.

  • Per implementare la registrazione ad alta velocità, crei un HighSpeedVideoSessionConfig con il tuo videoCapture.

    val recorder = Recorder.Builder().build()
    val videoCapture = VideoCapture.withOutput(recorder)
    
    val frameRateRange = cameraInfo.getSupportedFrameRateRanges(
           HighSpeedVideoSessionConfig(videoCapture, preview)).first()
    
    val sessionConfig = HighSpeedVideoSessionConfig(
        videoCapture,
        preview,
        frameRateRange = frameRateRange,
        isSlowMotionEnabled = true
    )
    
    cameraProvider.bindToLifecycle(
         lifecycleOwner, cameraSelector, sessionConfig)
    
    // Start recording slow motion videos.
    val recording = recorder.prepareRecording(context, outputOption)
          .start(executor, {})
  • Poi imposti isSlowMotionEnabled su true per codificarlo a 30 f/s e creare un video in slow motion oppure su false per creare un video con frequenza fotogrammi ad alta velocità.

  • Quando lo slow motion è attivo, Google Foto lo identifica automaticamente e aggiunge un badge slow motion alla miniatura.

  • Vediamo come funziona in Google Foto.

  • In questo caso, lo slow motion conferisce un effetto drammatico al gatto.

  • Il mio gatto non vuole mai che lo tocchi.

  • Mi dispiace.

  • Infine, vediamo alcuni miglioramenti nella nostra API per l'uso simultaneo, l'API Concurrent Camera.

  • L'API Concurrent consente alla tua app di trasmettere in streaming contemporaneamente dalla fotocamera anteriore e da quella posteriore.

  • Quest'anno abbiamo introdotto alcuni miglioramenti all'API Concurrent Camera.

  • Puoi aggiornare dinamicamente la composizione della fotocamera dopo averla associata al ciclo di vita e averla aperta.

  • Ciò include la modifica della posizione, delle dimensioni e dell'ordine di rendering.

  • Puoi anche aggiungere stili come un angolo arrotondato, lo spessore bordo e il colore bordo.

  • Ecco come fare: utilizza CompositionSettings per configurare lo stile, ad esempio l'arrotondamento degli angoli, lo spessore e il colore del bordo, e utilizza setZOrder per regolare l'ordine di rendering.

    val concurrentCamera =
            cameraProvider.bindToLifecycle(list(config1, config2))
    // CameraX 1.7 features: rounded corner, border width & color
    val pipSettings = CompositionSettings.Builder()
        .setOffset(0.2f, 0.2f)
        .setScale(0.35f, 0.35f)
        .setRoundedCornerRatio(0.15f)
        .setBorderWidthRatio(0.02f)
        .setBorderColor(Color.WHITE)
        .setZOrder(1)
        .build()
    // CameraX 1.7 features: dynamical composition update
    concurrentCamera.setCompositionSettings(
    listOf(mainSettings, pipSettings))
  • In seguito, basta richiamare setCompositionSettings sulla fotocamera simultanea attiva per aggiornare la composizione in modo dinamico.

  • Questo è tutto.

  • Puoi procedere con l'aggiornamento dinamico della composizione.

  • Ok.

  • Ora abbiamo esaminato tutte le funzionalità.

  • Abbiamo un avviso importante: ti consigliamo vivamente di eseguire l'upgrade a CameraX 1.6 e versioni successive.

  • In questo modo, puoi evitare arresti anomali sui dispositivi di prossima uscita che supportano il nuovo formato, Eclipsa Video, e assicurarti che l'estensione CameraX continui a funzionare con il futuro aggiornamento delle funzionalità di Pixel.

  • Con questo, concludiamo la nostra prima sessione.

  • Abbiamo parlato delle funzionalità di CameraX che ti aiutano a creare un'esperienza con la fotocamera di livello professionale. Ora vorrei invitare Aman a presentare la prossima sessione sull'AI on-device.

Machine learning sul dispositivo

  • Grazie, Scott, per averci illustrato le funzionalità di CameraX.

  • Ora vediamo come puoi sfruttare il machine learning on-device per creare esperienze con la fotocamera intelligenti.

  • Il machine learning on-device consente un'ampia gamma di casi d'uso della fotocamera in due aree principali.

  • La prima è la pre-acquisizione.

  • Qui puoi analizzare l'anteprima della fotocamera in tempo reale per eseguire operazioni come il rilevamento di oggetti o migliorare l'anteprima stessa.

  • La seconda è la fase di post-acquisizione.

  • Una volta acquisita l'immagine, puoi migliorarne la qualità o eseguire operazioni come la generazione di una descrizione per l'immagine.

  • Ora, esaminiamo alcune delle soluzioni di machine learning on-device che abbiamo per le tue app per fotocamera.

  • La prima libreria ML on-device di cui parleremo è ML Kit.

  • ML Kit è stato creato principalmente per risolvere problemi comuni nei domini della visione artificiale e del linguaggio naturale, come il riconoscimento del testo, il riconoscimento facciale e la traduzione linguistica.

  • L'anno scorso abbiamo introdotto ML Kit.

  • Ecco alcuni esempi di API ML Kit Vision, come il rilevamento di mesh facciali, la segmentazione dei soggetti e il rilevamento di oggetti in tempo reale.

  • Sì.

  • L'anno scorso abbiamo introdotto le API di AI generativa.

  • Queste API sfruttano la potenza di Gemini Nano per abilitare funzionalità come il riassunto del testo, la descrizione delle immagini e molto altro.

  • Ecco un esempio di descrizione di un'immagine utilizzando l'API Prompt.

  • Passiamo la bitmap dell'immagine con il prompt testuale al modello e la descrizione del risultato è un piccolo robot Android verde con un design simile a un cactus seduto su una superficie nera.

  • E tutto questo avviene sul dispositivo.

  • Interessante, vero?

  • Adobe Photoshop utilizza l'API Prompt per migliorare l'esperienza utente nella sua app.

  • Durante la modifica degli asset, gli utenti spesso devono gestire più livelli nell'app Photoshop.

  • Utilizzando l'API Prompt, l'app è ora in grado di rinominare automaticamente i livelli non organizzati.

  • L'app utilizza anche l'API Prompt per generare didascalie e hashtag per le immagini, il che è molto utile per la condivisione sui social media.

  • Diamo un'occhiata al codice per la descrizione dell'immagine utilizzando l'API Prompt.

    // 1. Initialize the on-device GenerativeModel client
    val generativeModel = Generation.getClient()
    
    // 2. Check whether Gemini Nano is available on the device
    val status = generativeModel.checkStatus()
    when (status) {
        FeatureStatus.UNAVAILABLE -> {}
        FeatureStatus.DOWNLOADABLE -> {}
        FeatureStatus.DOWNLOADING -> {}
        FeatureStatus.AVAILABLE -> {}
    }
  • Innanzitutto, hai bisogno di un oggetto client generativeModel, quindi controlla se Gemini Nano è disponibile o scaricabile sul tuo dispositivo.

  • Poi, genera una richiesta di contenuti combinando l'immagine e il prompt testuale e, infine, fornisce questa richiesta alla chiamata generateContent per eseguire l'inferenza su Gemini Nano e ottenere la descrizione dell'immagine.

    // 3. Build a multimodal request with the image and text prompt
    val request = generateContentRequest(
        ImagePart(bitmap),
        TextPart("Describe this image in detail.")
    ) {}
    
    // 4. Run inference on-device and get the description
    val response = generativeModel.generateContent(request)
    val description = response.candidates.first().text
  • Sì, la prossima libreria di ML on-device è MediaPipe.

  • MediaPipe offre un'ampia gamma di soluzioni di machine learning per le tue applicazioni.

  • Puoi visitare rapidamente il sito web di MediaPipe per provare diversi esempi, come il riconoscimento facciale, il rilevamento di oggetti, la segmentazione dell'immagine e molto altro.

  • Tutti questi casi d'uso sembrano molto simili a ML Kit, quindi quale libreria dovresti utilizzare?

  • Sebbene MediaPipe e ML Kit risolvano problemi simili, esistono alcune differenze fondamentali.

  • Il primo è il supporto della piattaforma.

  • MediaPipe funziona su Android, iOS, web e Python, mentre ML Kit si concentra solo su Android e iOS.

  • Inoltre, MediaPipe offre la personalizzazione dei modelli, mentre ML Kit fornisce API pronte all'uso.

  • Infine, mentre MediaPipe è open source, ML Kit è un SDK di Google.

  • Ecco un esempio di riconoscimento dei gesti che utilizza le API MediaPipe Vision.

  • Questa API rileva i gesti con la mano in tempo reale dai dati fotocamera.

  • Ad esempio, per avviare o interrompere la registrazione della fotocamera utilizzando semplici gesti con la mano mentre ti trovi a distanza dallo smartphone.

  • Diamo un'occhiata al codice.

  • Per prima cosa, devi creare l'oggetto GestureRecognizerOptions, fornendo il percorso del modello, la modalità di live streaming e un listener dei risultati.

    // 1. Build GestureRecognizerOptions
    val options = GestureRecognizerOptions.builder().setBaseOptions(
        BaseOptions.builder().setModelAssetPath(MP_RECOGNIZER_TASK).build())
        .setRunningMode(RunningMode.LIVE_STREAM)
        .setResultListener { result, image -> /* Handle detected gesture */ }
        .build()
    
    // 2. Create the GestureRecognizer
    val gestureRecognizer = GestureRecognizer.createFromOptions(context, options)
    
    // 3. Convert CameraX ImageProxy to MediaPipe MPImage
    val bitmap = rotateBitmap(imageProxy.toBitmap(),
    imageProxy.imageInfo.rotationDegrees)
    val mpImage = BitmapImageBuilder(bitmap).build()
    
    // 4. Run gesture recognition on the image
    gestureRecognizer.recognizeAsync(mpImage, frameTime)
  • Quindi, crea un oggetto di riconoscimento dei gesti dalle opzioni.

  • Successivamente, recupera l'oggetto ImageProxy di CameraX e convertilo in una bitmap, quindi utilizza la bitmap per generare un oggetto mpImage di MediaPipe.

  • Infine, devi fornire l'oggetto MediaPipe mpImage alla chiamata recognizeAsync per rilevare i gesti in tempo reale.

Miglioramento di immagini e video

  • Poi abbiamo On-Device Image and Video Enhance, disponibile tramite l'API Google Play Services.

  • Questo modello offre funzionalità come la mappatura dei toni, la rimozione della sfocatura e la Super risoluzione sulla maggior parte dei dispositivi premium.

  • Ecco un esempio di un'immagine con mappatura tonale e upscaling utilizzando questo modello.

  • Puoi vedere chiaramente i colori più ricchi del cielo e del mare e la nitidezza migliorata nell'immagine ottimizzata.

  • Diamo un'occhiata al codice per il miglioramento delle immagini.

    // Step 1: Verify device support & install module
    val enhancementClient = Enhancement.getClient(context)
    
    suspend fun prepare(): Boolean {
        if (!enhancementClient.isDeviceSupported().await()) return false
        if (!enhancementClient.isModuleInstalled().await()) {
            check(enhancementClient.installModule().await()) {
                "Enhancement module install failed"
            }
        }
        return true
    }
  • Innanzitutto, devi verificare se il dispositivo sottostante lo supporta o meno e, se necessario, devi installare il modulo di miglioramento sul dispositivo.

  • Successivamente, crea l'oggetto EnhancementOptions specificando la bitmap e i miglioramenti che vuoi attivare.

    // Step 2: Select Enhancement options & create session
    val options = EnhancementOptions(
        width = bitmap.width,
        height = bitmap.height,
        enhancementMode = EnhancementMode.BITMAP,
        isTonemappingEnabled = true,
        isDeblurAndDenoisePhotoEnabled = true,
        isDeblurAndDenoiseVideoEnabled = false,
        isUpscalePhotoEnabled = false,
        isUpscaleVideoEnabled = false
    )
    
    val enhancementSession = enhancementClient
        .createSessionAsync(options, enhancementExecutor)
  • Successivamente, crea una sessione client con l'API Google Play Services, poi definisci un callback per gestire la bitmap risultante e infine chiama la funzione di elaborazione con la bitmap e le opzioni per migliorare l'immagine.

    // Step 3: Process Enhancement
    val enhancedBitmap = suspendCancellableCoroutine { continuation ->
        val enhancementCallback = object : EnhancementCallback {
            override fun onBitmapProcessed(result: Bitmap) {
                if (continuation.isActive) continuation.resume(result)
            }
            override fun onError(statusCode: Int) {
                if (continuation.isActive) {
                    continuation.resumeWithException(
                        Exception("Bitmap processing failed: $statusCode")
                    )
                }
            }
            override fun onSurfaceProcessed(timestamp: Long) {}
        }
    
        enhancementSession.process(bitmap, options, enhancementCallback)
    }
  • Di recente abbiamo integrato le API di miglioramento video in Jetpack Media3.

  • Puoi consultare il nostro intervento sui contenuti multimediali per scoprire di più sulle API Image and Video Enhancement.

  • L'ultima funzionalità di ML on-device che tratteremo è la modalità Luce scarsa.

  • Scattare foto in condizioni di scarsa illuminazione è un problema comune per gli utenti di smartphone.

  • Pensa agli utenti che acquisiscono immagini o partecipano a videochiamate in ambienti scarsamente illuminati.

  • La funzionalità Luce scarsa risolve questo problema illuminando l'anteprima della fotocamera in tempo reale.

  • Esistono due varianti di Luce scarsa+: hardware e software.

  • La versione hardware utilizza l'hardware OEM per migliorare i fotogrammi scarsamente illuminati senza utilizzare il machine learning.

  • Al contrario, la versione software utilizza un modello di ML on-device per migliorare i frame.

  • Diamo una rapida occhiata a come possiamo integrare CameraX con Software Low Light Boost, noto anche come Google Low Light Boost.

  • Google Luce scarsa Boost richiede due superfici chiave: innanzitutto, è necessaria una superficie di input per i frame della fotocamera non elaborati e una superficie di destinazione di output per i frame di output migliorati.

  • Per l'integrazione con CameraX, basta inserire la pipeline di Google Low Light Boost all'interno di un CameraEffect.

  • CameraX gestisce automaticamente il ciclo di vita e il routing della superficie per te.

  • Infine, lanceremo l'effetto di ottimizzazione in condizioni di scarsa illuminazione in CameraX nel quarto trimestre del 2026.

    // Integrates SW Low Light Boost
    val lowLightBoostEffect =
        LowLightBoostEffect(
            CameraEffect.PREVIEW or
            CameraEffect.VIDEO_CAPTURE or
            CameraEffect.IMAGE_CAPTURE
        )
    
    val sessionConfig = SessionConfig(
        useCases = listOf(preview, imageCapture),
        effects = lowLightBoostEffect
    )
    
    cameraProvider.bindToLifecycle(.. sessionConfig)
  • In questo modo, potrai creare un oggetto Low Light Boost e aggiungerlo alla configurazione della sessione, quindi associare la configurazione della sessione al ciclo di vita della fotocamera e funzionerà sui dispositivi supportati.

Riepilogo e migrazione

  • Siamo arrivati alla fine di entrambe le sezioni.

  • Riassumiamo rapidamente tutto ciò che abbiamo trattato oggi.

  • Oggi abbiamo parlato di come puoi migliorare le esperienze con la fotocamera su tutti i dispositivi con CameraX e il machine learning on-device.

  • Innanzitutto, con CameraXViewfinder, puoi attivare le anteprime della fotocamera per adattarle a diversi fattori di forma.

  • Poi abbiamo visto che CameraX consente di acquisire anche su dispositivi XR.

  • L'API Feature Group ti aiuta a trovare la combinazione ottimale di funzionalità hardware.

  • Abbiamo anche esplorato gli upgrade dell'Acquisizione di immagini e abbiamo scoperto la registrazione di video ad alta velocità per i video in slow motion.

  • Infine, abbiamo imparato a migliorare l'anteprima della fotocamera simultanea in modo dinamico.

  • Poi, abbiamo esaminato alcune delle soluzioni di machine learning on-device, come ML Kit e MediaPipe, per creare esperienze di visione intelligenti.

  • Infine, abbiamo visto il miglioramento di immagini e video on-device, insieme alla funzionalità Luce scarsa per illuminare l'anteprima della fotocamera in tempo reale.

  • Come accennato in precedenza, abbiamo in programma di disattivare Camera1, pertanto ti consigliamo vivamente di eseguire la migrazione a CameraX.

  • Per supportare questa migrazione, di recente abbiamo lanciato la skill CameraX.

  • Abbiamo anche una guida alla migrazione e il repository di esempi di fotocamera per guidarti.

  • Puoi visitare questo link per accedere ad altre risorse sulle funzionalità che abbiamo trattato oggi.

  • Include link alla documentazione, al blog e alle risorse di migrazione, tutto in un unico posto.

  • Mi prenderò un secondo, farò una pausa.

  • Ok.

  • Grazie a tutti.

  • Siamo arrivati alla fine del nostro intervento.

Codice

Snippet di codice

Snippet Kotlin alle 04:18 in "Funzionalità del mirino adattivo"
var surfaceRequest by remember {
    mutableStateOf<SurfaceRequest?>(null)
}

LaunchedEffect(...) {
    preview.setSurfaceProvider { surfaceRequest = it }
    cameraProvider.bindToLifecycle(..., preview)
}

surfaceRequest?.let { request ->
    CameraXViewfinder(
        surfaceRequest = request,
        contentScale = ContentScale.Fit
    )
}
Snippet Kotlin alle 05:14 in "Funzionalità del mirino adattivo"
CameraXViewfinder(
    surfaceRequest = viewModel.surfaceRequest,
    contentScale = ContentScale.Fit,
    isTapToFocusEnabled = true,
    isPinchToZoomEnabled = true,
    onScreenFlashReady =
        {
           imageCapture.screenFlash = it
           imageCapture.flashMode = FLASH_MODE_SCREEN
        }
)
Snippet di Kotlin al minuto 07:30 in "Acquisizione con la fotocamera con Android XR"
// In a coroutine
val imageCapture = ImageCapture.Builder().build()

ProjectedContext.isProjectedDeviceConnected(activity, coroutineContext)
    .collectLatest { isConnected ->
        if (isConnected) {
            val projectedContext = ProjectedContext.createProjectedDeviceContext(activity)
            val cameraConfig = CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig())
                .setRepeatingStreamForced(false)
                .build()
            val cameraProvider = LifecycleCameraProvider.createInstance(projectedContext, cameraConfig)
            cameraProvider.bindToLifecycle(activity, DEFAULT_BACK_CAMERA, imageCapture)
        }
    }
// Shutter button clicked
imageCapture.takePicture(...)
Snippet Kotlin al minuto 09:42 in "Acquisisci funzionalità e API"
cameraProvider.bindToLifecycle(
    lifecycleOwner,
    cameraSelector,
    SessionConfig(
        useCases = listOf(preview, videoCapture),
        // HDR_HLG10 > FPS_60 > Preview Stabilization.
        preferredFeatureGroup =
           listOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION),
    )
)
Snippet di Kotlin al minuto 09:58 in "Acquisisci funzionalità e API"
// CameraX 1.6+ supports:
// 4K, video stabilization & Effect
val sessionConfig = SessionConfig(
   useCases = listOf(preview, videoCapture),
   requiredFeatureGroup =
     setOf(UHD_RECORDING, VIDEO_STABILIZATION),
   effects = listOf(overlayEffect)
)
Snippet Kotlin al minuto 11:20 in "Capture features and APIs"
val cameraInfo = cameraProvider.getCameraInfo(cameraSelector,
        ExtensionSessionConfig(ExtensionMode.NIGHT, extensionsManager))

val imageCapabilities = ImageCapture.getImageCaptureCapabilities(cameraInfo)

val imageCapture = ImageCapture.Builder().apply {
       if (imageCapabilities.supportedOutputFormats
                .contains(OUTPUT_FORMAT_JPEG_ULTRA_HDR)) {
           setOutputFormat(OUTPUT_FORMAT_JPEG_ULTRA_HDR)
       }
     }.build()

val extensionSessionConfig = ExtensionSessionConfig(
    ExtensionMode.NIGHT, extensionsManager, preview, imageCapture
)

cameraProvider.bindToLifecycle(...,  extensionSessionConfig)
Snippet Kotlin al minuto 12:11 in "Acquisisci funzionalità e API"
val imageCapture = ImageCapture.Builder()
        .setMotionPhotoMode(
             ImageCapture.MOTION_PHOTO_MODE_ON,
             customConfig
         )
        .build()

cameraProvider.bindToLifecycle(.. imageCapture)
imageCapture.takePicture(...)
Snippet Kotlin al minuto 13:06 in "Capture features and APIs"
val recorder = Recorder.Builder().build()
val videoCapture = VideoCapture.withOutput(recorder)

val frameRateRange = cameraInfo.getSupportedFrameRateRanges(
       HighSpeedVideoSessionConfig(videoCapture, preview)).first()

val sessionConfig = HighSpeedVideoSessionConfig(
    videoCapture,
    preview,
    frameRateRange = frameRateRange,
    isSlowMotionEnabled = true
)

cameraProvider.bindToLifecycle(
     lifecycleOwner, cameraSelector, sessionConfig)

// Start recording slow motion videos.
val recording = recorder.prepareRecording(context, outputOption)
      .start(executor, {})
Snippet di Kotlin al minuto 14:18 in "Acquisire funzionalità e API"
val concurrentCamera =
        cameraProvider.bindToLifecycle(list(config1, config2))
// CameraX 1.7 features: rounded corner, border width & color
val pipSettings = CompositionSettings.Builder()
    .setOffset(0.2f, 0.2f)
    .setScale(0.35f, 0.35f)
    .setRoundedCornerRatio(0.15f)
    .setBorderWidthRatio(0.02f)
    .setBorderColor(Color.WHITE)
    .setZOrder(1)
    .build()
// CameraX 1.7 features: dynamical composition update
concurrentCamera.setCompositionSettings(
listOf(mainSettings, pipSettings))
Snippet di Kotlin al minuto 17:51 in "On-device machine learning"
// 1. Initialize the on-device GenerativeModel client
val generativeModel = Generation.getClient()

// 2. Check whether Gemini Nano is available on the device
val status = generativeModel.checkStatus()
when (status) {
    FeatureStatus.UNAVAILABLE -> {}
    FeatureStatus.DOWNLOADABLE -> {}
    FeatureStatus.DOWNLOADING -> {}
    FeatureStatus.AVAILABLE -> {}
}
Snippet Kotlin al minuto 18:06 in "On-device machine learning"
// 3. Build a multimodal request with the image and text prompt
val request = generateContentRequest(
    ImagePart(bitmap),
    TextPart("Describe this image in detail.")
) {}

// 4. Run inference on-device and get the description
val response = generativeModel.generateContent(request)
val description = response.candidates.first().text
Snippet di Kotlin alle 19:38 in "Machine learning on-device"
// 1. Build GestureRecognizerOptions
val options = GestureRecognizerOptions.builder().setBaseOptions(
    BaseOptions.builder().setModelAssetPath(MP_RECOGNIZER_TASK).build())
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setResultListener { result, image -> /* Handle detected gesture */ }
    .build()

// 2. Create the GestureRecognizer
val gestureRecognizer = GestureRecognizer.createFromOptions(context, options)

// 3. Convert CameraX ImageProxy to MediaPipe MPImage
val bitmap = rotateBitmap(imageProxy.toBitmap(),
imageProxy.imageInfo.rotationDegrees)
val mpImage = BitmapImageBuilder(bitmap).build()

// 4. Run gesture recognition on the image
gestureRecognizer.recognizeAsync(mpImage, frameTime)
Snippet di Kotlin al minuto 20:44 in "Image and video enhancement"
// Step 1: Verify device support & install module
val enhancementClient = Enhancement.getClient(context)

suspend fun prepare(): Boolean {
    if (!enhancementClient.isDeviceSupported().await()) return false
    if (!enhancementClient.isModuleInstalled().await()) {
        check(enhancementClient.installModule().await()) {
            "Enhancement module install failed"
        }
    }
    return true
}
Snippet di Kotlin al minuto 20:57 in "Image and video enhancement"
// Step 2: Select Enhancement options & create session
val options = EnhancementOptions(
    width = bitmap.width,
    height = bitmap.height,
    enhancementMode = EnhancementMode.BITMAP,
    isTonemappingEnabled = true,
    isDeblurAndDenoisePhotoEnabled = true,
    isDeblurAndDenoiseVideoEnabled = false,
    isUpscalePhotoEnabled = false,
    isUpscaleVideoEnabled = false
)

val enhancementSession = enhancementClient
    .createSessionAsync(options, enhancementExecutor)
Snippet Kotlin al minuto 21:05 in "Image and video enhancement"
// Step 3: Process Enhancement
val enhancedBitmap = suspendCancellableCoroutine { continuation ->
    val enhancementCallback = object : EnhancementCallback {
        override fun onBitmapProcessed(result: Bitmap) {
            if (continuation.isActive) continuation.resume(result)
        }
        override fun onError(statusCode: Int) {
            if (continuation.isActive) {
                continuation.resumeWithException(
                    Exception("Bitmap processing failed: $statusCode")
                )
            }
        }
        override fun onSurfaceProcessed(timestamp: Long) {}
    }

    enhancementSession.process(bitmap, options, enhancementCallback)
}
Snippet Kotlin al minuto 22:51 in "Image and video enhancement"
// Integrates SW Low Light Boost
val lowLightBoostEffect =
    LowLightBoostEffect(
        CameraEffect.PREVIEW or
        CameraEffect.VIDEO_CAPTURE or
        CameraEffect.IMAGE_CAPTURE
    )

val sessionConfig = SessionConfig(
    useCases = listOf(preview, imageCapture),
    effects = lowLightBoostEffect
)

cameraProvider.bindToLifecycle(.. sessionConfig)