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.
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.ProjectedDeviceContext consente a CameraX di acquisire immagini direttamente dagli occhiali.Trascrizione
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.
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.
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.
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.
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().textSì, 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.
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.
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.
var surfaceRequest by remember {
mutableStateOf<SurfaceRequest?>(null)
}
LaunchedEffect(...) {
preview.setSurfaceProvider { surfaceRequest = it }
cameraProvider.bindToLifecycle(..., preview)
}
surfaceRequest?.let { request ->
CameraXViewfinder(
surfaceRequest = request,
contentScale = ContentScale.Fit
)
}CameraXViewfinder(
surfaceRequest = viewModel.surfaceRequest,
contentScale = ContentScale.Fit,
isTapToFocusEnabled = true,
isPinchToZoomEnabled = true,
onScreenFlashReady =
{
imageCapture.screenFlash = it
imageCapture.flashMode = FLASH_MODE_SCREEN
}
)// 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(...)cameraProvider.bindToLifecycle(
lifecycleOwner,
cameraSelector,
SessionConfig(
useCases = listOf(preview, videoCapture),
// HDR_HLG10 > FPS_60 > Preview Stabilization.
preferredFeatureGroup =
listOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION),
)
)// CameraX 1.6+ supports:
// 4K, video stabilization & Effect
val sessionConfig = SessionConfig(
useCases = listOf(preview, videoCapture),
requiredFeatureGroup =
setOf(UHD_RECORDING, VIDEO_STABILIZATION),
effects = listOf(overlayEffect)
)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)val imageCapture = ImageCapture.Builder()
.setMotionPhotoMode(
ImageCapture.MOTION_PHOTO_MODE_ON,
customConfig
)
.build()
cameraProvider.bindToLifecycle(.. imageCapture)
imageCapture.takePicture(...)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, {})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))// 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 -> {}
}// 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// 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)// 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
}// 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)// 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)
}// 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)