Google 致力于为黑人社区推动种族平等。查看具体举措
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Etichetta le immagini in modo sicuro con Cloud Vision utilizzando Firebase Auth and Functions su Android

Per chiamare un'API di Google Cloud dalla tua app, devi creare un'API REST intermedia che gestisca l'autorizzazione e protegga i valori segreti come le chiavi API. Devi quindi scrivere il codice nella tua app mobile per autenticarti e comunicare con questo servizio intermedio.

Un modo per creare questa API REST è utilizzare Firebase Authentication and Functions, che offre un gateway gestito e senza server per le API di Google Cloud 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 fatturati 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

  1. Se non l'hai già fatto, aggiungi Firebase al tuo progetto Android .
  2. Se non hai già abilitato le API basate su cloud per il tuo progetto, fallo ora:

    1. Apri la pagina delle API Firebase ML della console Firebase.
    2. Se non hai già aggiornato il tuo progetto al piano tariffario Blaze, fai clic su Aggiorna per farlo. (Ti verrà chiesto di eseguire l'upgrade solo se il tuo progetto non è nel piano Blaze.)

      Solo i progetti a livello di Blaze possono utilizzare API basate su cloud.

    3. Se le API basate su cloud non sono già abilitate, fai clic su Abilita API basate su cloud .
  3. Configura le tue chiavi API Firebase esistenti per non consentire l'accesso all'API Cloud Vision:
    1. Apri la pagina Credenziali della console Cloud.
    2. Per ogni chiave API nell'elenco, apri la visualizzazione di modifica e, nella sezione Restrizioni chiave, aggiungi all'elenco tutte le API disponibili tranne l'API Cloud Vision.

Distribuisci la funzione richiamabile

Successivamente, distribuisci la funzione Cloud che utilizzerai per collegare la tua app e l'API Cloud Vision. Il repository di 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. È possibile modificare la funzione per esigenze diverse.

Per distribuire la funzione:

  1. Clona o scarica il repository functions-samples e passa alla directory vision-annotate-image :
    git clone https://github.com/firebase/functions-samples
    cd vision-annotate-image
    
  2. Installa le dipendenze:
    cd functions
    npm install
    cd ..
    
  3. Se non hai la Firebase CLI, installala .
  4. Inizializza un progetto Firebase nella directory vision-annotate-image . Quando richiesto, seleziona il tuo progetto nell'elenco.
    firebase init
  5. Distribuire la funzione:
    firebase deploy --only functions:annotateImage

Aggiungi Firebase Auth alla tua app

La funzione richiamabile distribuita sopra rifiuterà qualsiasi richiesta da parte degli utenti non autenticati della tua app. Se non l'hai già fatto, dovrai aggiungere Firebase Auth alla tua app.

Aggiungi le dipendenze necessarie alla tua app

  • Aggiungi le dipendenze per le funzioni Firebase e le librerie Android gson al file Gradle del modulo (a livello di app) (solitamente app / build.gradle):
    implementation 'com.google.firebase:firebase-functions:19.2.0'
    implementation 'com.google.code.gson:gson:2.8.6'
    
  • Ora sei pronto per etichettare le immagini.

    1. Preparare l'immagine in ingresso

    Per chiamare Cloud Vision, l'immagine deve essere formattata come una stringa con codifica base64. Per elaborare un'immagine da un URI di file salvato:
    1. Ottieni l'immagine come oggetto Bitmap :

      Giava

      Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);

      Kotlin + KTX

      var bitmap: Bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)
    2. Facoltativamente, ridimensionare l'immagine per risparmiare sulla larghezza di banda. Consulta le dimensioni delle immagini consigliate da Cloud Vision.

      Giava

      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 + KTX

      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)
      }

      Giava

      // Scale down bitmap size
      bitmap = scaleBitmapDown(bitmap, 640);

      Kotlin + KTX

      // Scale down bitmap size
      bitmap = scaleBitmapDown(bitmap, 640)
    3. Converti l'oggetto bitmap in una stringa con codifica base64:

      Giava

      // 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);

      Kotlin + KTX

      // 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)
    4. L'immagine rappresentata dall'oggetto Bitmap deve essere in posizione verticale, senza alcuna rotazione aggiuntiva richiesta.

    2. Richiamare la funzione richiamabile per etichettare l'immagine

    Per etichettare gli oggetti in un'immagine, richiama la funzione richiamabile passando una richiesta JSON Cloud Vision .

    1. Innanzitutto, inizializza un'istanza di Cloud Functions:

      Giava

      private FirebaseFunctions mFunctions;
      // ...
      mFunctions = FirebaseFunctions.getInstance();
      

      Kotlin + KTX

      private lateinit var functions: FirebaseFunctions
      // ...
      functions = Firebase.functions
      
    2. Definisci un metodo per invocare la funzione:

      Giava

      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()));
                      }
                  });
      }
      

      Kotlin + KTX

      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))
                  }
      }
      
    3. Crea la richiesta JSON con Tipo impostato su LABEL_DETECTION :

      Giava

      // 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);
      

      Kotlin + KTX

      // 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)
      
    4. Infine, invoca la funzione:

      Giava

      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
                          // ...
                      }
                  }
              });
      

      Kotlin + KTX

      annotateImage(request.toString())
              .addOnCompleteListener { task ->
                  if (!task.isSuccessful) {
                      // Task failed with an exception
                      // ...
                  } else {
                      // Task completed successfully
                      // ...
                  }
              }
      

    3. Ottenere informazioni sugli oggetti etichettati

    Se l'operazione di etichettatura dell'immagine riesce, nel risultato dell'attività verrà restituita una risposta JSON di BatchAnnotateImagesResponse . Ogni oggetto nell'array labelAnnotations rappresenta qualcosa che è stato etichettato nell'immagine. Per ogni etichetta, puoi ottenere la descrizione del testo dell'etichetta, il relativo ID entità Knowledge Graph (se disponibile) e il punteggio di affidabilità della corrispondenza. Per esempio:

    Giava

    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();
    }
    

    Kotlin + KTX

    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"]
    }