Pour appeler une API Google Cloud depuis votre application, vous devez créer une API REST intermédiaire qui gère l'autorisation et protège les valeurs secrètes telles que les clés API. Vous devez ensuite écrire du code dans votre application mobile pour vous authentifier auprès de ce service intermédiaire et communiquer avec lui.
Pour créer cette API REST, vous pouvez utiliser Firebase Authentication et Firebase Functions. Vous obtiendrez ainsi une passerelle sans serveur gérée vers les API Google Cloud, qui gère l'authentification et peut être appelée depuis votre application mobile avec des SDK prédéfinis.
Ce guide explique comment utiliser cette technique pour appeler l'API Cloud Vision depuis votre application. Cette méthode permettra à tous les utilisateurs authentifiés d'accéder aux services payants Cloud Vision via votre projet Cloud. Avant de continuer, vérifiez donc si ce mécanisme d'authentification est suffisant pour votre cas d'utilisation.
Avant de commencer
Configurez votre projet
- Si ce n'est pas déjà fait, ajoutez Firebase à votre projet Android.
-
Si vous n'avez pas encore activé les API cloud pour votre projet, faites-le maintenant :
- Ouvrez la page API Firebase ML dans la console Firebase.
-
Si vous n'avez pas encore migré votre projet vers le forfait Blaze avec paiement à l'usage, cliquez sur Mettre à niveau pour le faire. (Vous serez invité à effectuer la mise à niveau uniquement si votre projet n'est pas associé au forfait Blaze.)
Seuls les projets associés au forfait Blaze peuvent utiliser les API basées sur le cloud.
- Si les API basées sur le cloud ne sont pas déjà activées, cliquez sur Activer les API basées sur le cloud.
- Configurez vos clés API Firebase existantes pour interdire l'accès à l'API Cloud Vision :
- Ouvrez la page Identifiants de la console Cloud.
- Pour chaque clé API de la liste, ouvrez la vue d'édition et, dans la section "Restrictions de clé", ajoutez toutes les API disponibles sauf l'API Cloud Vision à la liste.
Déployer la fonction appelable
Ensuite, déployez la fonction Cloud que vous utiliserez pour faire le lien entre votre application et l'API Cloud Vision. Le dépôt functions-samples contient un exemple que vous pouvez utiliser.
Par défaut, l'accès à l'API Cloud Vision via cette fonction n'autorise que les utilisateurs authentifiés de votre application à accéder à l'API Cloud Vision. Vous pouvez modifier la fonction pour répondre à différents besoins.
Pour déployer la fonction, procédez comme suit :
- Clonez ou téléchargez le dépôt functions-samples et accédez au répertoire
Node-1st-gen/vision-annotate-image:git clone https://github.com/firebase/functions-samplescd Node-1st-gen/vision-annotate-image - Installez les dépendances :
cd functionsnpm installcd .. - Si vous n'avez pas la CLI Firebase, installez-la.
- Initialisez un projet Firebase dans le répertoire
vision-annotate-image. Lorsque vous y êtes invité, sélectionnez votre projet dans la liste.firebase init
- Déployez la fonction :
firebase deploy --only functions:annotateImage
Ajouter Firebase Auth à votre application
La fonction appelable déployée ci-dessus refusera toute requête provenant d'utilisateurs non authentifiés de votre application. Si vous ne l'avez pas encore fait, vous devrez ajouter Firebase Auth à votre application.
Ajouter les dépendances nécessaires à votre application
<project>/<app-module>/build.gradle.kts ou <project>/<app-module>/build.gradle) :
implementation("com.google.firebase:firebase-functions:22.1.0") implementation("com.google.code.gson:gson:2.8.6")
Vous êtes maintenant prêt à étiqueter des images.
1. Préparer l'image d'entrée
Pour appeler Cloud Vision, l'image doit être mise en forme en tant que chaîne encodée en base64. Pour traiter une image à partir d'un URI de fichier enregistré :- Obtenez l'image en tant qu'objet
Bitmap:Kotlin
var bitmap: Bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)
Java
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
- Vous pouvez également réduire la taille de l'image pour économiser de la bande passante. Consultez les
tailles d'image recommandées pour 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);
- Convertissez l'objet bitmap en chaîne encodée en 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'image représentée par l'objet
Bitmap doit être à l'endroit, sans rotation supplémentaire requise.
2. Appeler la fonction appelable pour libeller l'image
Pour étiqueter des objets dans une image, appelez la fonction appelable en transmettant une requête Cloud Vision JSON.Commencez par initialiser une instance de Cloud Functions :
Kotlin
private lateinit var functions: FirebaseFunctions // ... functions = Firebase.functionsJava
private FirebaseFunctions mFunctions; // ... mFunctions = FirebaseFunctions.getInstance();Définissez une méthode pour appeler la fonction :
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())); } }); }Créez la requête JSON avec Type défini sur
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);Enfin, appelez la fonction :
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. Obtenir des informations sur les objets libellés
Si l'opération d'étiquetage d'images réussit, une réponse JSON BatchAnnotateImagesResponse est renvoyée dans le résultat de la tâche. Chaque objet du tableaulabelAnnotations représente un élément identifié dans l'image. Pour chaque libellé, vous pouvez obtenir sa description textuelle, son ID d'entité Knowledge Graph (si disponible) et le score de confiance de la correspondance. Exemple :
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();
}