Per chiamare un'API Google Cloud dalla tua app, devi creare un'API REST intermedia che gestisca l'autorizzazione e protegga i valori segreti come le chiavi API. Dopodiché, devi scrivere codice nella tua app mobile per autenticarti e comunicare con questo servizio intermedio.
Un modo per creare questa API REST è utilizzare Firebase Authentication e Functions, che ti offre un gateway serverless gestito per le API Cloud di Google che gestisce l'autenticazione e può essere chiamato dalla tua app mobile con SDK predefiniti.
Questa guida mostra come utilizzare questa tecnica per chiamare l'API Cloud Vision dalla tua app. Questo metodo consentirà a tutti gli utenti autenticati di accedere ai servizi a pagamento di Cloud Vision tramite il tuo progetto Cloud, quindi valuta se questo meccanismo di autenticazione è sufficiente per il tuo caso d'uso prima di procedere.
Prima di iniziare
Configura il tuo progetto
- Se non l'hai già fatto, aggiungi Firebase al tuo progetto Android.
-
Se non hai ancora abilitato le API basate sul cloud per il tuo progetto, fallo ora:
- Apri la pagina API Firebase ML nella console Firebase.
-
Se non hai ancora eseguito l'upgrade del tuo progetto al piano tariffario Blaze con pagamento a consumo, fai clic su Esegui l'upgrade per farlo. Ti verrà chiesto di eseguire l'upgrade solo se il tuo progetto non è incluso nel piano tariffario Blaze.
Solo i progetti inclusi nel piano tariffario Blaze possono utilizzare le API basate sul cloud.
- Se le API basate sul cloud non sono ancora abilitate, fai clic su Abilita API basate sul cloud.
- Configura le chiavi API Firebase esistenti in modo da non consentire l'accesso all'API Cloud
Vision:
- Apri la pagina Credenziali della console Cloud.
- Per ogni chiave API nell'elenco, apri la visualizzazione di modifica e, nella sezione Limitazioni della chiave, aggiungi all'elenco tutte le API disponibili tranne l'API Cloud Vision.
Esegui il deployment della funzione richiamabile
Poi, esegui il deployment della funzione Cloud che utilizzerai per collegare la tua app e l'API Cloud
Vision. Il repository functions-samples contiene un esempio
che puoi utilizzare.
Per impostazione predefinita, l'accesso all'API Cloud Vision tramite questa funzione consentirà solo agli utenti autenticati della tua app di accedere all'API Cloud Vision. Puoi modificare la funzione per requisiti diversi.
Per eseguire il deployment della funzione:
- Clona o scarica il repository functions-samples
e passa alla directory
Node-1st-gen/vision-annotate-image:git clone https://github.com/firebase/functions-samplescd Node-1st-gen/vision-annotate-image - Installa le dipendenze:
cd functionsnpm installcd .. - Se non hai l'interfaccia a riga di comando di Firebase, installala.
- Inizializza un progetto Firebase nella
vision-annotate-imagedirectory. Quando ti viene richiesto, seleziona il tuo progetto nell'elenco.firebase init
- Esegui il deployment della funzione:
firebase deploy --only functions:annotateImage
Aggiungi Firebase Authentication alla tua app
La funzione richiamabile di cui sopra rifiuterà qualsiasi richiesta da utenti non autenticati della tua app. Se non l'hai ancora fatto, devi aggiungere Firebase Authentication alla tua app.
Aggiungi le dipendenze necessarie alla tua app
<project>/<app-module>/build.gradle.kts o
<project>/<app-module>/build.gradle):
implementation("com.google.firebase:firebase-functions:22.1.1") implementation("com.google.code.gson:gson:2.8.6")
Ora puoi etichettare le immagini.
1. Prepara l'immagine di input
Per chiamare Cloud Vision, l'immagine deve essere formattata come stringa con codifica base64. Per elaborare un'immagine da un URI di file salvato:- Ottieni l'immagine come oggetto
Bitmap:Kotlin
var bitmap: Bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)
Java
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
- Se vuoi, ridimensiona l'immagine per risparmiare larghezza di banda. Consulta le
dimensioni delle immagini consigliate per Cloud Vision.
Kotlin
private fun scaleBitmapDown(bitmap: Bitmap, maxDimension: Int): Bitmap { val originalWidth = bitmap.width val originalHeight = bitmap.height var resizedWidth = maxDimension var resizedHeight = maxDimension if (originalHeight > originalWidth) { resizedHeight = maxDimension resizedWidth = (resizedHeight * originalWidth.toFloat() / originalHeight.toFloat()).toInt() } else if (originalWidth > originalHeight) { resizedWidth = maxDimension resizedHeight = (resizedWidth * originalHeight.toFloat() / originalWidth.toFloat()).toInt() } else if (originalHeight == originalWidth) { resizedHeight = maxDimension resizedWidth = maxDimension } return Bitmap.createScaledBitmap(bitmap, resizedWidth, resizedHeight, false) }
Java
private Bitmap scaleBitmapDown(Bitmap bitmap, int maxDimension) { int originalWidth = bitmap.getWidth(); int originalHeight = bitmap.getHeight(); int resizedWidth = maxDimension; int resizedHeight = maxDimension; if (originalHeight > originalWidth) { resizedHeight = maxDimension; resizedWidth = (int) (resizedHeight * (float) originalWidth / (float) originalHeight); } else if (originalWidth > originalHeight) { resizedWidth = maxDimension; resizedHeight = (int) (resizedWidth * (float) originalHeight / (float) originalWidth); } else if (originalHeight == originalWidth) { resizedHeight = maxDimension; resizedWidth = maxDimension; } return Bitmap.createScaledBitmap(bitmap, resizedWidth, resizedHeight, false); }
Kotlin
// Scale down bitmap size bitmap = scaleBitmapDown(bitmap, 640)
Java
// Scale down bitmap size bitmap = scaleBitmapDown(bitmap, 640);
- Converti l'oggetto bitmap in una stringa con codifica base64:
Kotlin
// Convert bitmap to base64 encoded string val byteArrayOutputStream = ByteArrayOutputStream() bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream) val imageBytes: ByteArray = byteArrayOutputStream.toByteArray() val base64encoded = Base64.encodeToString(imageBytes, Base64.NO_WRAP)
Java
// Convert bitmap to base64 encoded string ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream); byte[] imageBytes = byteArrayOutputStream.toByteArray(); String base64encoded = Base64.encodeToString(imageBytes, Base64.NO_WRAP);
L'immagine rappresentata dall'oggetto
Bitmap deve
essere verticale, senza rotazione aggiuntiva.
2. Richiama la funzione richiamabile per etichettare l'immagine
Per etichettare gli oggetti in un'immagine, richiama la funzione richiamabile passando una richiesta JSON di Cloud Vision.Innanzitutto, inizializza un'istanza di Cloud Functions:
Kotlin
private lateinit var functions: FirebaseFunctions // ... functions = Firebase.functionsJava
private FirebaseFunctions mFunctions; // ... mFunctions = FirebaseFunctions.getInstance();Definisci un metodo per richiamare la funzione:
Kotlin
private fun annotateImage(requestJson: String): Task<JsonElement> { return functions .getHttpsCallable("annotateImage") .call(requestJson) .continueWith { task -> // This continuation runs on either success or failure, but if the task // has failed then result will throw an Exception which will be // propagated down. val result = task.result?.data JsonParser.parseString(Gson().toJson(result)) } }Java
private Task<JsonElement> annotateImage(String requestJson) { return mFunctions .getHttpsCallable("annotateImage") .call(requestJson) .continueWith(new Continuation<HttpsCallableResult, JsonElement>() { @Override public JsonElement then(@NonNull Task<HttpsCallableResult> task) { // This continuation runs on either success or failure, but if the task // has failed then getResult() will throw an Exception which will be // propagated down. return JsonParser.parseString(new Gson().toJson(task.getResult().getData())); } }); }Crea la richiesta JSON con Tipo impostato su
LABEL_DETECTION:Kotlin
// Create json request to cloud vision val request = JsonObject() // Add image to request val image = JsonObject() image.add("content", JsonPrimitive(base64encoded)) request.add("image", image) // Add features to the request val feature = JsonObject() feature.add("maxResults", JsonPrimitive(5)) feature.add("type", JsonPrimitive("LABEL_DETECTION")) val features = JsonArray() features.add(feature) request.add("features", features)Java
// Create json request to cloud vision JsonObject request = new JsonObject(); // Add image to request JsonObject image = new JsonObject(); image.add("content", new JsonPrimitive(base64encoded)); request.add("image", image); //Add features to the request JsonObject feature = new JsonObject(); feature.add("maxResults", new JsonPrimitive(5)); feature.add("type", new JsonPrimitive("LABEL_DETECTION")); JsonArray features = new JsonArray(); features.add(feature); request.add("features", features);Infine, richiama la funzione:
Kotlin
annotateImage(request.toString()) .addOnCompleteListener { task -> if (!task.isSuccessful) { // Task failed with an exception // ... } else { // Task completed successfully // ... } }Java
annotateImage(request.toString()) .addOnCompleteListener(new OnCompleteListener<JsonElement>() { @Override public void onComplete(@NonNull Task<JsonElement> task) { if (!task.isSuccessful()) { // Task failed with an exception // ... } else { // Task completed successfully // ... } } });
3. Ottieni informazioni sugli oggetti etichettati
Se l'operazione di etichettatura delle immagini ha esito positivo, nel risultato dell'attività viene restituita una risposta JSON di BatchAnnotateImagesResponse. Ogni oggetto nell'arraylabelAnnotations rappresenta un elemento etichettato nell'immagine. Per ogni etichetta, puoi ottenere la descrizione testuale dell'etichetta, il suo
ID entità Knowledge Graph
(se disponibile) e il punteggio di attendibilità della corrispondenza. Ad esempio:
Kotlin
for (label in task.result!!.asJsonArray[0].asJsonObject["labelAnnotations"].asJsonArray) {
val labelObj = label.asJsonObject
val text = labelObj["description"]
val entityId = labelObj["mid"]
val confidence = labelObj["score"]
}
Java
for (JsonElement label : task.getResult().getAsJsonArray().get(0).getAsJsonObject().get("labelAnnotations").getAsJsonArray()) {
JsonObject labelObj = label.getAsJsonObject();
String text = labelObj.get("description").getAsString();
String entityId = labelObj.get("mid").getAsString();
float score = labelObj.get("score").getAsFloat();
}