Vision API-Produktsuche-Backend unter Android aufrufen

1. Hinweis

bd8c01b2f8013c6d.png

Haben Sie sich die Google Lens-Demo angesehen, in der Sie die Kamera Ihres Smartphones auf ein Objekt richten und herausfinden können, wo Sie es online kaufen können? Wenn Sie wissen möchten, wie Sie dieselbe Funktion in Ihre App einfügen können, sind Sie hier genau richtig. Sie ist Teil eines Lernpfads, in dem Sie erfahren, wie Sie eine Funktion zur Produktsuche per Bild in eine mobile App einbauen.

In diesem Codelab erfahren Sie, wie Sie ein mit der Vision API-Produktsuche erstelltes Backend über eine mobile App aufrufen. Dieses Backend kann ein Abfragebild entgegennehmen und in einem Produktkatalog nach visuell ähnlichen Produkten suchen.

Hier finden Sie weitere Informationen zu den verbleibenden Schritten zum Erstellen einer visuellen Produktsuche, einschließlich der Verwendung von ML Kit Object Detection and Tracking zum Erkennen von Objekten im Anfragebild und zum Ermöglichen der Auswahl des gewünschten Produkts durch Nutzer.

Umfang

  • In diesem Codelab beginnen Sie mit der Android-App, die Objekte aus einem Eingabebild erkennen kann. Sie schreiben Code, um das vom Nutzer ausgewählte Objekt zu übernehmen, an das Backend der Produktsuche zu senden und das Suchergebnis auf dem Bildschirm anzuzeigen.
  • Am Ende sollte das Ergebnis in etwa so aussehen wie im Bild rechts.

Lerninhalte

  • Vision API-Produktsuche-APIs über eine Android-App aufrufen und die Antwort analysieren

Voraussetzungen

  • Eine aktuelle Version von Android Studio (ab Version 4.1.2)
  • Android Studio-Emulator oder physisches Android-Gerät
  • Der Beispielcode
  • Grundkenntnisse in der Android-Entwicklung mit Kotlin

In diesem Codelab geht es um die Vision API-Produktsuche. Irrelevante Konzepte und Codeblöcke werden nicht behandelt und können einfach kopiert und eingefügt werden.

2. Informationen zur Vision API-Produktsuche

Die Vision API-Produktsuche ist eine Funktion in Google Cloud, mit der Nutzer in einem Produktkatalog nach visuell ähnlichen Produkten suchen können. Einzelhändler können Produkte mit Referenzbildern erstellen, die das Produkt optisch aus mehreren Perspektiven darstellen. Anschließend können Sie diese Produkte Produktgruppen (d.h. dem Produktkatalog) hinzufügen. Derzeit unterstützt die Vision API-Produktsuche die folgenden Produktkategorien: Haushaltswaren, Bekleidung, Spielzeug, abgepackte Waren und allgemein.

Wenn ein Nutzer die Produktgruppe mit eigenen Bildern abfragt, nutzt die API Vision-Produktsuche maschinelles Lernen, um das Produkt im Bild des Nutzers mit den Bildern in der Produktgruppe des Einzelhändlers zu vergleichen. Zurückgegeben wird eine nach Rang sortierte Liste mit optisch und semantisch ähnlichen Ergebnissen.

3. Start-App herunterladen und ausführen

Code herunterladen

Klicken Sie auf den folgenden Link, um den gesamten Code für dieses Codelab herunterzuladen:

Entpacken Sie die heruntergeladene ZIP-Datei. Dadurch wird ein Stammordner (odml-pathways-main) mit allen benötigten Ressourcen entpackt. Für dieses Codelab benötigen Sie nur die Quellen im Unterverzeichnis product-search/codelab2/android.

Das Unterverzeichnis codelab2 im Repository odml-pathways enthält zwei Verzeichnisse:

  • android_studio_folder.pngstarter: Der Startcode, auf dem Sie in diesem Codelab aufbauen.
  • android_studio_folder.pngfinal: Der vollständige Code der fertigen Beispiel-App.

Die Starter-App ist die, die Sie im Codelab Objekte in Bildern erkennen, um eine visuelle Produktsuche zu erstellen: Android erstellt haben. Dazu wird ML Kit Object Detection and Tracking verwendet, um Objekte in einem Bild zu erkennen und auf dem Bildschirm anzuzeigen.

App in Android Studio importieren

Importieren Sie zuerst die Starter-App in Android Studio.

Wählen Sie in Android Studio Import Project (Gradle, Eclipse ADT, etc.) aus und wählen Sie den Ordner starter aus dem Quellcode aus, den Sie zuvor heruntergeladen haben.

7c0f27882a2698ac.png

Start-App ausführen

Nachdem Sie das Projekt in Android Studio importiert haben, kann die App zum ersten Mal ausgeführt werden. Verbinden Sie Ihr Android-Gerät über USB mit Ihrem Host oder starten Sie den Android Studio-Emulator und klicken Sie in der Android Studio-Symbolleiste auf Ausführen ( execute.png).

Wenn diese Schaltfläche deaktiviert ist, importieren Sie nur „starter/app/build.gradle“ und nicht das gesamte Repository.

Die App sollte jetzt auf Ihrem Android-Gerät gestartet worden sein. Die Funktion zur Objekterkennung ist bereits integriert: Sie erkennt Modeartikel auf dem Bild und zeigt Ihnen, wo sie sich befinden. Versuchen Sie es mit den voreingestellten Fotos.

c6102a808fdfcb11.png

Screenshot der Starter-App, die Objekte in einem Bild erkennen kann

Als Nächstes erweitern Sie die App, um die erkannten Objekte an das Vision API-Produktsuche-Backend zu senden und die Suchergebnisse auf dem Bildschirm anzuzeigen.

4. Objektauswahl verarbeiten

Nutzern erlauben, auf ein erkanntes Objekt zu tippen, um es auszuwählen

Jetzt fügen Sie Code hinzu, damit Nutzer ein Objekt aus dem Bild auswählen und die Produktsuche starten können. Die Starter-App kann bereits Objekte im Bild erkennen. Möglicherweise sind mehrere Objekte im Bild zu sehen oder das erkannte Objekt nimmt nur einen kleinen Teil des Bildes ein. Daher muss der Nutzer auf eines der erkannten Objekte tippen, um anzugeben, welches Objekt er für die Produktsuche verwenden möchte.

9cdfcead6d95a87.png

Ein Screenshot der im Bild erkannten Modeartikel

Damit das Codelab einfach bleibt und sich auf maschinelles Lernen konzentriert, wurde in der Starter-App Boilerplate-Android-Code implementiert, mit dem erkannt werden kann, auf welches Objekt der Nutzer getippt hat. Die Ansicht, in der das Bild in der Hauptaktivität (ObjectDetectorActivity) angezeigt wird, ist eigentlich eine benutzerdefinierte Ansicht (ImageClickableView), die die Standard-ImageView von Android OS erweitert. Es implementiert einige praktische Dienstprogrammmethoden, darunter:

  • fun setOnObjectClickListener(listener: ((objectImage: Bitmap) -> Unit)) Dies ist ein Callback, um das zugeschnittene Bild zu empfangen, das nur das Objekt enthält, auf das der Nutzer getippt hat. Sie senden dieses zugeschnittene Bild an das Backend der Produktsuche.

Fügen Sie Code hinzu, um zu verarbeiten, wenn ein Nutzer auf die erkannten Objekte tippt.

Rufen Sie die Methode initViews in der Klasse ObjectDetectorActivity auf und fügen Sie diese Zeilen am Ende der Methode ein: (Android Studio meldet, dass die Methode startProductImageSearch nicht gefunden werden kann. Keine Sorge, Sie werden sie etwas später implementieren.)

// Callback received when the user taps on any of the detected objects.
ivPreview.setOnObjectClickListener { objectImage ->
    startProductImageSearch(objectImage)
}

Die onObjectClickListener wird aufgerufen, wenn der Nutzer auf eines der erkannten Objekte auf dem Bildschirm tippt. Es wird das zugeschnittene Bild empfangen, das nur das ausgewählte Objekt enthält. Wenn der Nutzer beispielsweise auf die Person tippt, die das Kleid rechts trägt, wird der Listener mit objectImage ausgelöst (siehe unten).

9cac8458d0f326e6.png

Beispiel für das zugeschnittene Bild, das an onObjectClickListener übergeben wird

Das zugeschnittene Bild an die Produktsuche senden

Jetzt implementieren Sie die Logik zum Senden des Anfragebilds an das Vision API-Produktsuche-Backend in einer separaten Aktivität (ProductSearchActivity).

Alle UI-Komponenten wurden im Voraus implementiert, sodass Sie sich auf das Schreiben des Codes für die Kommunikation mit dem Backend der Produktsuche konzentrieren können.

25939f5a13eeb3c3.png

Screenshot der UI-Komponenten in der ProductSearchActivity

Fügen Sie Code hinzu, um das vom Nutzer ausgewählte Objektbild an ProductSearchActivity zu senden.

Kehren Sie zu Android Studio zurück und fügen Sie der Klasse ObjectDetectorActivity die folgende startProductImageSearch-Methode hinzu:

private fun startProductImageSearch(objectImage: Bitmap) {
    try {
        // Create file based Bitmap. We use PNG to preserve the image quality
        val savedFile = createImageFile(ProductSearchActivity.CROPPED_IMAGE_FILE_NAME)
        objectImage.compress(Bitmap.CompressFormat.PNG, 100, FileOutputStream(savedFile))

        // Start the product search activity (using Vision Product Search API.).
        startActivity(
            Intent(
                    this,
                    ProductSearchActivity::class.java
            ).apply {
                // As the size limit of a bundle is 1MB, we need to save the bitmap to a file
                // and reload it in the other activity to support large query images.
                putExtra(
                    ProductSearchActivity.REQUEST_TARGET_IMAGE_PATH,
                    savedFile.absolutePath
                )
            })
    } catch (e: Exception) {
        // IO Exception, Out Of memory ....
        Toast.makeText(this, e.message, Toast.LENGTH_SHORT).show()
        Log.e(TAG, "Error starting the product image search activity.", e)
    }
}

Das Code-Snippet führt drei Aktionen aus:

  • Nimmt das zugeschnittene Bild und serialisiert es in eine PNG-Datei.
  • Startet die ProductSearchActivity, um die Produktfolge auszuführen.
  • Enthält den URI des zugeschnittenen Bildes im Intent „start-activity“, damit ProductSearchActivity ihn später als Abfragebild abrufen kann.

Beachten Sie dabei Folgendes:

  • Die Logik zum Erkennen von Objekten und zum Abfragen des Back-Ends wurde nur in zwei Aktivitäten aufgeteilt, um das Codelab leichter verständlich zu machen. Sie können selbst entscheiden, wie Sie sie in Ihrer App implementieren.
  • Sie müssen das Anfragebild in eine Datei schreiben und den Bild-URI zwischen Aktivitäten übergeben, da das Anfragebild größer als das Größenlimit von 1 MB für einen Android-Intent sein kann.
  • Sie können das Anfragebild im PNG-Format speichern, da es sich um ein verlustfreies Format handelt.

Das Abfragebild in der Produkt-Suchaktivität abrufen

Im ProductSearchActivity wurde der Code zum Abrufen des Anfragebilds und zum Anzeigen auf dem Bildschirm bereits in der Starter-App implementiert.

Rufen Sie die Methode onCreate auf und prüfen Sie, ob dieser Code bereits vorhanden ist:

// Receive the query image and show it on the screen
intent.getStringExtra(REQUEST_TARGET_IMAGE_PATH)?.let { absolutePath ->
    viewBinding.ivQueryImage.setImageBitmap(BitmapFactory.decodeFile(absolutePath))
}

App ausführen

Klicken Sie nun in der Android Studio-Symbolleiste auf Ausführen ( execute.png).

Tippen Sie nach dem Laden der App auf ein beliebiges Preset-Bild und wählen Sie eines der erkannten Objekte aus.

Prüfen Sie, ob das ProductSearchActivity mit dem Bild angezeigt wird, auf das Sie getippt haben. Die Schaltfläche Suchen hat noch keine Funktion, wird aber als Nächstes implementiert.

fed40f81b8b43801.png

Nachdem Sie auf eines der erkannten Objekte getippt haben, sollte ein ähnlicher Bildschirm angezeigt werden.

5. Produkt-Such-Backend ansehen

Back-End für die Produktsuche mit Bildern erstellen

Für dieses Codelab ist ein Produktsuche-Backend erforderlich, das mit der Vision API-Produktsuche erstellt wurde. Dafür gibt es zwei Möglichkeiten:

Option 1: Das für Sie bereitgestellte Demobackend verwenden

Sie können dieses Codelab mit dem Produkt-Such-Backend durchführen, das Google bereits für Sie bereitgestellt hat. Das Demobackend kann mithilfe des Schnellstarts für die Vision API-Produktsuche repliziert werden.

Option 2: Eigenes Back-End erstellen (Kurzanleitung zur Produktsuche der Vision API)

Diese Option wird für Nutzer empfohlen, die detailliert erfahren möchten, wie ein Backend für die Produktsuche erstellt wird, damit sie später eines für ihren eigenen Produktkatalog erstellen können. Sie benötigen Folgendes:

  • Ein Google Cloud-Konto mit aktivierter Abrechnung. Das kann auch ein Konto für die kostenlose Testversion sein.
  • Grundkenntnisse zu Google Cloud-Konzepten wie Projekten und Dienstkonten

Wie das geht, erfahren Sie später im Lernpfad.

Wichtige Konzepte kennenlernen

Die folgenden Konzepte werden Ihnen bei der Interaktion mit dem Backend der Produktsuche begegnen:

  • Produktgruppe: Eine Produktgruppe ist ein einfacher Container für eine Gruppe von Produkten. Ein Produktkatalog kann als Produktgruppe und die zugehörigen Produkte dargestellt werden.
  • Produkt: Nachdem Sie eine Produktgruppe erstellt haben, können Sie Produkte erstellen und sie der Produktgruppe hinzufügen.
  • Referenzbilder des Produkts: Das sind Bilder mit verschiedenen Ansichten Ihrer Produkte. Mit Referenzbildern wird nach optisch ähnlichen Produkten gesucht.
  • Nach Produkten suchen: Nachdem Sie die Produktgruppe erstellt und indexiert haben, können Sie sie über die Cloud Vision API abfragen.

Voreingestellten Produktkatalog verwenden

Das Backend der Produktsuche-Demo, das in diesem Codelab verwendet wird, wurde mit der Vision API-Produktsuche und einem Produktkatalog mit etwa 100 Schuh- und Kleiderbildern erstellt. Hier sind einige Bilder aus dem Katalog:

4f1a8507b74ab178.png 79a5fc6c829eca77.png 3528c872f813826e.png

Beispiele aus dem voreingestellten Produktkatalog

Backend der Produktsuche-Demo aufrufen

Sie können die Vision API-Produktsuche direkt aus einer mobilen App aufrufen, indem Sie einen Google Cloud API-Schlüssel einrichten und den Zugriff auf den API-Schlüssel auf Ihre App beschränken.

Damit dieses Codelab einfach bleibt, wurde ein Proxy-Endpunkt eingerichtet, über den Sie auf das Demobackend zugreifen können, ohne sich um den API-Schlüssel und die Authentifizierung kümmern zu müssen. Er empfängt die HTTP-Anfrage von der mobilen App, hängt den API-Schlüssel an und leitet die Anfrage an das Vision API Product Search-Backend weiter. Der Proxy empfängt dann die Antwort vom Backend und gibt sie an die mobile App zurück.

In diesem Codelab verwenden Sie zwei APIs der Vision API-Produktsuche:

6. API-Client implementieren

Workflow für die Produktsuche

Folgen Sie diesem Workflow, um die Produktsuche mit dem Backend durchzuführen:

API-Clientklasse implementieren

Jetzt implementieren Sie Code, um das Back-End für die Produktsuche in einer speziellen Klasse namens ProductSearchAPIClient aufzurufen. In der Starter-App wurde bereits Boilerplate-Code für Sie implementiert:

  • class ProductSearchAPIClient: Diese Klasse ist derzeit größtenteils leer, enthält aber einige Methoden, die Sie später in diesem Codelab implementieren werden.
  • fun convertBitmapToBase64(bitmap: Bitmap): Eine Bitmap-Instanz in ihre Base64-Darstellung konvertieren, um sie an das Back-End für die Produktsuche zu senden
  • fun annotateImage(image: Bitmap): Task<List<ProductSearchResult>>: Rufen Sie die API projects.locations.images.annotate auf und parsen Sie die Antwort.
  • fun fetchReferenceImage(searchResult: ProductSearchResult): Task<ProductSearchResult>: Rufen Sie die API projects.locations.products.referenceImages.get auf und parsen Sie die Antwort.
  • SearchResult.kt: Diese Datei enthält mehrere Datenklassen zur Darstellung der Typen, die vom Vision API-Produktsuche-Backend zurückgegeben werden.

API-Konfigurationen angeben

Rufen Sie die Klasse ProductSearchAPIClient auf. Dort sind bereits einige Konfigurationen des Backends für die Produktsuche definiert:

// Define the product search backend
// Option 1: Use the demo project that we have already deployed for you
const val VISION_API_URL =
    "https://us-central1-odml-codelabs.cloudfunctions.net/productSearch"
const val VISION_API_KEY = ""
const val VISION_API_PROJECT_ID = "odml-codelabs"
const val VISION_API_LOCATION_ID = "us-east1"
const val VISION_API_PRODUCT_SET_ID = "product_set0"
  • VISION_API_URL ist der API-Endpunkt der Cloud Vision API. Wenn Sie mit dem Demo-Backend fortfahren, legen Sie diesen Wert auf den Proxy-Endpunkt fest. Wenn Sie jedoch Ihr eigenes Back-End bereitstellen, müssen Sie es in den Cloud Vision API-Endpunkt ändern. https://vision.googleapis.com/v1.
  • VISION_API_KEY ist der API-Schlüssel Ihres Cloud-Projekts. Da die Authentifizierung bereits vom Proxy übernommen wird, können Sie dieses Feld leer lassen.
  • VISION_API_PROJECT_ID ist die Cloud-Projekt-ID. odml-codelabs ist das Cloud-Projekt, in dem das Demobackend bereitgestellt wird.
  • VISION_API_LOCATION_ID ist der Cloud-Standort, an dem das Backend für die Produktsuche bereitgestellt wird. us-east1 ist der Ort, an dem wir das Demo-Backend bereitgestellt haben.
  • VISION_API_PRODUCT_SET_ID ist die ID des Produktkatalogs (in der Vision API als „Produktgruppe“ bezeichnet), in dem Sie nach visuell ähnlichen Produkten suchen möchten. Ein Cloud-Projekt kann mehrere Kataloge enthalten. product_set0 ist der voreingestellte Produktkatalog des Demobackends.

7. Produkt-Such-API aufrufen

API-Anfrage- und ‑Antwortformat ansehen

Sie können ähnliche Produkte zu einem bestimmten Bild finden. Dazu übergeben Sie den Google Cloud Storage-URI, die Web-URL oder die Base64-codierte Zeichenfolge des Bildes an die Vision API-Produktsuche. In diesem Codelab verwenden Sie die Option für base64-codierte Strings, da unser Anfragebild nur auf dem Gerät des Nutzers vorhanden ist.

Sie müssen eine POST-Anfrage mit diesem JSON-Text an den Endpunkt projects.locations.images.annotate senden:

{
  "requests": [
    {
      "image": {
        "content": {base64-encoded-image}
      },
      "features": [
        {
          "type": "PRODUCT_SEARCH",
          "maxResults": 5
        }
      ],
      "imageContext": {
        "productSearchParams": {
          "productSet": "projects/{project-id}/locations/{location-id}/productSets/{product-set-id}",
          "productCategories": [
               "apparel-v2"
          ],
        }
      }
    }
  ]
}

Es gibt einige Parameter, die angegeben werden müssen::

  • base64-encoded-image: die Base64-Darstellung (ASCII-String) der Binärdaten des Anfragebilds.
  • project-id: ID Ihres GCP-Projekts.
  • location-id: Eine gültige Standort-ID.
  • product-set-id: Die ID der Produktgruppe, für die der Vorgang ausgeführt werden soll.

Da Ihr Produktkatalog nur Bilder von Schuhen und Kleidern enthält, geben Sie für productCategories apparel-v2 an. v2 bedeutet, dass wir Version 2 des ML-Modells für die Suche nach Bekleidungsprodukten verwenden.

Bei einer erfolgreichen Anfrage gibt der Server den HTTP-Statuscode 200 OK und die Antwort im JSON-Format zurück. Der JSON-Antwortcode enthält die folgenden zwei Ergebnistypen:

  • productSearchResults: Enthält eine Liste übereinstimmender Produkte zum gesamten Bild.
  • productGroupedResults: Enthält die Koordinaten der Begrenzungsrahmen und übereinstimmende Objekte für jedes im Bild erkannte Produkt.

Da das Produkt bereits aus dem Originalbild herausgeschnitten wurde, werden die Ergebnisse in der Liste productSearchResults analysiert.

Hier sind einige wichtige Felder im Produkt-Suchergebnisobjekt:

  • product.name: Die eindeutige Kennzeichnung eines Produkts im Format projects/{project-id}/locations/{location-id}/products/{product_id}
  • product.score: Ein Wert, der angibt, wie ähnlich das Suchergebnis dem Abfragebild ist. Höhere Werte bedeuten mehr Ähnlichkeit.
  • product.image: Die eindeutige Kennung des Referenzbilds eines Produkts im Format projects/{project-id}/locations/{location-id}/products/{product_id}/referenceImages/{image_id}. Sie müssen eine weitere API-Anfrage an projects.locations.products.referenceImages.get senden, um die URL dieses Referenzbilds abzurufen, damit es auf dem Bildschirm angezeigt wird.
  • product.labels: Eine Liste vordefinierter Tags des Produkts. Das ist nützlich, wenn Sie die Suchergebnisse filtern möchten, um nur eine Kategorie von Kleidung wie Kleider anzuzeigen.

Anfragebild in Base64 konvertieren

Sie müssen das Anfragebild in seine Base64-Stringdarstellung konvertieren und den String an das JSON-Objekt im Anfragetext anhängen.

Rufen Sie die Klasse ProductSearchAPIClient auf, suchen Sie nach der leeren Methode convertBitmapToBase64 und ersetzen Sie sie durch diese Implementierung:

private fun convertBitmapToBase64(bitmap: Bitmap): String {
    val byteArrayOutputStream = ByteArrayOutputStream()
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
    val byteArray: ByteArray = byteArrayOutputStream.toByteArray()
    return Base64.encodeToString(byteArray, Base64.DEFAULT)
}

API-Aufruf implementieren

Erstellen Sie als Nächstes eine API-Anfrage zur Produktsuche und senden Sie sie an das Backend. Sie verwenden Volley, um die API-Anfrage zu senden, und geben das Ergebnis über die Task API zurück.

Kehren Sie zur Klasse ProductSearchAPIClient zurück, suchen Sie die leere Methode annotateImage und ersetzen Sie sie durch diese Implementierung:

fun annotateImage(image: Bitmap): Task<List<ProductSearchResult>> {
    // Initialization to use the Task API
    val apiSource = TaskCompletionSource<List<ProductSearchResult>>()
    val apiTask = apiSource.task

    // Convert the query image to its Base64 representation to call the Product Search API.
    val base64: String = convertBitmapToBase64(image)

    // Craft the request body JSON.
    val requestJson = """
        {
          "requests": [
            {
              "image": {
                "content": """".trimIndent() + base64 + """"
              },
              "features": [
                {
                  "type": "PRODUCT_SEARCH",
                  "maxResults": $VISION_API_PRODUCT_MAX_RESULT
                }
              ],
              "imageContext": {
                "productSearchParams": {
                  "productSet": "projects/${VISION_API_PROJECT_ID}/locations/${VISION_API_LOCATION_ID}/productSets/${VISION_API_PRODUCT_SET_ID}",
                  "productCategories": [
                       "apparel-v2"
                     ]
                }
              }
            }
          ]
        }
    """.trimIndent()

    // Add a new request to the queue
    requestQueue.add(object :
        JsonObjectRequest(
            Method.POST,
            "$VISION_API_URL/images:annotate?key=$VISION_API_KEY",
            JSONObject(requestJson),
            { response ->
                // Parse the API JSON response to a list of ProductSearchResult object/
                val productList = apiResponseToObject(response)

                // Return the list.
                apiSource.setResult(productList)
            },
            // Return the error
            { error -> apiSource.setException(error) }
        ) {
        override fun getBodyContentType() = "application/json"
    }.apply {
        setShouldCache(false)
    })

    return apiTask
}

Suchergebnis in der Benutzeroberfläche anzeigen

Der API-Code in ProductSearchAPIClient ist jetzt fertig. Kehren Sie zur Aktivität ProductSearchActivity zurück, um den UI-Code zu implementieren.

Die Aktivität enthält bereits etwas Boilerplate-Code, der die Methode searchByImage(queryImage: Bitmap) auslöst. Fügen Sie dieser derzeit leeren Methode Code hinzu, um das Backend aufzurufen und Ergebnisse in der Benutzeroberfläche anzuzeigen.

apiClient.annotateImage(queryImage)
    .addOnSuccessListener { showSearchResult(it) }
    .addOnFailureListener { error ->
        Log.e(TAG, "Error calling Vision API Product Search.", error)
        showErrorResponse(error.localizedMessage)
    }

Die Methode showSearchResult enthält etwas Boilerplate-Code, der die API-Antwort parst und auf dem Bildschirm anzeigt.

Ausführen

Klicken Sie nun in der Android Studio-Symbolleiste auf Ausführen ( execute.png). Tippen Sie nach dem Laden der App auf ein beliebiges voreingestelltes Bild, wählen Sie ein erkanntes Objekt aus, tippen Sie auf die Schaltfläche Suchen und sehen Sie sich die Suchergebnisse an, die vom Backend zurückgegeben werden. Die Ansicht sieht ungefähr so aus:

bb5e7c27c283a2fe.png

Screenshot des Bildschirms mit den Suchergebnissen für das Produkt

Das Backend gibt bereits eine Liste mit visuell ähnlichen Produkten aus dem voreingestellten Produktkatalog zurück. Das Produktbild ist jedoch noch leer. Das liegt daran, dass der Endpunkt projects.locations.images.annotate nur Produktbild-IDs wie projects/odml-codelabs/locations/us-east1/products/product_id77/referenceImages/image77 zurückgibt. Sie müssen einen weiteren API-Aufruf an den Endpunkt projects.locations.products.referenceImages.get senden und die URL dieses Referenzbilds abrufen, um es auf dem Bildschirm anzuzeigen.

8. Produktreferenzbilder abrufen

API-Anfrage- und ‑Antwortformat ansehen

Sie senden eine HTTP-GET-Anfrage mit einem leeren Anfragetext an den Endpunkt projects.locations.products.referenceImages.get, um die URIs der Produktbilder abzurufen, die vom Endpunkt für die Produktsuche zurückgegeben werden.

Die HTTP-Anfrage sieht so aus:

GET $VISION_API_URL/projects/odml-codelabs/locations/us-east1/products/product_id77/referenceImages/image77?key=$VISION_API_KEY

Bei einer erfolgreichen Anfrage liefert der Server den HTTP-Statuscode 200 OK und die Antwort im JSON-Format wie unten:

{
  "name":"projects/odml-codelabs/locations/us-east1/products/product_id77/referenceImages/image77",
  "uri":"gs://cloud-ai-vision-data/product-search-tutorial/images/46991e7370ba11e8a1bbd20059124800.jpg"
}
  • name: Die Kennung des Referenzbildes
  • uri: Der URI des Bildes in Google Cloud Storage (GCS).

Für die Referenzbilder des Back-Ends der Demo-Produktsuche wurde die Berechtigung „public-read“ eingerichtet. Daher können Sie den GCS-URI ganz einfach in eine HTTP-URL umwandeln und in der Benutzeroberfläche der App anzeigen. Sie müssen nur das Präfix gs:// durch https://storage.googleapis.com/ ersetzen.

API-Aufruf implementieren

Erstellen Sie als Nächstes eine API-Anfrage zur Produktsuche und senden Sie sie an das Backend. Sie verwenden Volley und die Task API ähnlich wie beim Produktsuch-API-Aufruf.

Kehren Sie zur Klasse ProductSearchAPIClient zurück, suchen Sie die leere Methode fetchReferenceImage und ersetzen Sie sie durch diese Implementierung:

private fun fetchReferenceImage(searchResult: ProductSearchResult): Task<ProductSearchResult> {
    // Initialization to use the Task API
    val apiSource = TaskCompletionSource<ProductSearchResult>()
    val apiTask = apiSource.task

    // Craft the API request to get details about the reference image of the product
    val stringRequest = object : StringRequest(
        Method.GET,
        "$VISION_API_URL/${searchResult.imageId}?key=$VISION_API_KEY",
        { response ->
            val responseJson = JSONObject(response)
            val gcsUri = responseJson.getString("uri")

            // Convert the GCS URL to its HTTPS representation
            val httpUri = gcsUri.replace("gs://", "https://storage.googleapis.com/")

            // Save the HTTPS URL to the search result object
            searchResult.imageUri = httpUri

            // Invoke the listener to continue with processing the API response (eg. show on UI)
            apiSource.setResult(searchResult)
        },
        { error -> apiSource.setException(error) }
    ) {

        override fun getBodyContentType(): String {
            return "application/json; charset=utf-8"
        }
    }
    Log.d(ProductSearchActivity.TAG, "Sending API request.")

    // Add the request to the RequestQueue.
    requestQueue.add(stringRequest)

    return apiTask
}

Diese Methode verwendet ein searchResult: ProductSearchResult-Objekt, das vom Produkt-Such-Endpunkt zurückgegeben wurde, und führt dann die folgenden Schritte aus:

  1. Ruft den Referenzbild-Endpunkt auf, um den GCS-URI des Referenzbildes abzurufen.
  2. Wandelt den GCS-URI in eine HTTP-URL um.
  3. Aktualisiert die httpUri-Property des searchResult-Objekts mit dieser HTTP-URL.

Die beiden API-Anfragen verknüpfen

Gehen Sie zurück zu annotateImage und ändern Sie die Funktion so, dass alle HTTP-URLs der Referenzbilder abgerufen werden, bevor die Liste ProductSearchResult an den Aufrufer zurückgegeben wird.

Suchen Sie diese Zeile:

// Return the list.
apiSource.setResult(productList)

Ersetzen Sie es dann durch diese Implementierung:

// Loop through the product list and create tasks to load reference images.
// We will call the projects.locations.products.referenceImages.get endpoint
// for each product.
val fetchReferenceImageTasks = productList.map { fetchReferenceImage(it) }

// When all reference image fetches have completed,
// return the ProductSearchResult list
Tasks.whenAllComplete(fetchReferenceImageTasks)
    // Return the list of ProductSearchResult with product images' HTTP URLs.
    .addOnSuccessListener { apiSource.setResult(productList) }
    // An error occurred so returns it to the caller.
    .addOnFailureListener { apiSource.setException(it) }

Der Boilerplate-Code zum Anzeigen der Referenzbilder auf dem Bildschirm ist bereits in der Klasse ProductSearchAdapter implementiert. Sie können die App also noch einmal ausführen.

Ausführen

Klicken Sie nun in der Android Studio-Symbolleiste auf Ausführen ( execute.png). Tippen Sie nach dem Laden der App auf ein beliebiges voreingestelltes Bild, wählen Sie ein erkanntes Objekt aus und tippen Sie auf die Schaltfläche Suchen, um die Suchergebnisse aufzurufen. Diesmal werden auch die Produktbilder angezeigt.

Sind die Produkt-Suchergebnisse für Sie nachvollziehbar?

25939f5a13eeb3c3.png

9. Glückwunsch!

Sie haben gelernt, wie Sie ein Vision API-Produktsuche-Backend aufrufen, um Ihrer Android-App die Möglichkeit zu geben, nach Produktbildern zu suchen. Das ist alles, was Sie für den Einstieg benötigen.

Im weiteren Verlauf möchten Sie vielleicht Ihr eigenes Backend mit Ihrem Produktkatalog erstellen. Im nächsten Codelab im Lernpfad Produktbildsuche erfahren Sie, wie Sie Ihr eigenes Backend erstellen und den API-Schlüssel einrichten, um es über eine mobile App aufzurufen.

Behandelte Themen

  • Back-End der Vision API-Produktsuche über eine Android-App aufrufen

Nächste Schritte

Weitere Informationen