Mit Firebase ML für Android Sehenswürdigkeiten erkennen

Sie können Firebase ML verwenden, um bekannte Sehenswürdigkeiten in einem Bild zu erkennen.

Hinweis

  1. Falls noch nicht geschehen, Fügen Sie Firebase zu Ihrem Android-Projekt hinzu.
  2. Fügen Sie in der Gradle-Datei des Moduls (auf App-Ebene) (in der Regel <project>/<app-module>/build.gradle.kts oder <project>/<app-module>/build.gradle) die Abhängigkeit für die Firebase ML Vision-Bibliothek für Android hinzu. Wir empfehlen die Verwendung des Firebase Android BoM um die Versionsverwaltung der Bibliothek zu steuern.
    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:33.2.0"))
    
        // Add the dependency for the Firebase ML Vision library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-ml-vision'
    }

    Mit dem Firebase Android BoM Ihre App verwendet immer kompatible Versionen der Firebase Android Libraries.

    (Alternative) Firebase-Bibliotheksabhängigkeiten ohne BoM hinzufügen

    Wenn Sie Firebase BoM nicht verwenden, müssen Sie jede Firebase-Bibliotheksversion angeben in der Abhängigkeitszeile ein.

    Wenn Sie in Ihrer App mehrere Firebase-Bibliotheken verwenden, empfehlen, Bibliotheksversionen mit der BoM zu verwalten. Dadurch wird sichergestellt, dass alle Versionen kompatibel.

    dependencies {
        // Add the dependency for the Firebase ML Vision library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-ml-vision:24.1.0'
    }
    Sie suchen nach einem Kotlin-spezifischen Bibliotheksmodul? Beginnt in Oktober 2023 (Firebase BoM 32.5.0) können sowohl Kotlin- als auch Java-Entwickler sind vom Modul der Hauptbibliothek abhängig (Details finden Sie in der FAQs zu dieser Initiative).
  3. Wenn Sie noch keine cloudbasierten APIs für Ihr Projekt aktiviert haben, tun Sie dies jetzt. jetzt:

    1. Öffnen Sie in der Firebase-Konsole die Seite Firebase MLAPIs.
    2. Wenn Sie für Ihr Projekt noch kein Upgrade auf das Blaze-Preismodell durchgeführt haben, klicken Sie auf Führen Sie ein Upgrade durch. Sie werden nur dann zum Upgrade aufgefordert, Projekt nicht im Tarif "Blaze" ist.)

      Nur Projekte auf Blaze-Ebene können cloudbasierte APIs verwenden.

    3. Wenn cloudbasierte APIs noch nicht aktiviert sind, klicken Sie auf Cloudbasiertes Erstellen aktivieren APIs

Detektoren für Sehenswürdigkeiten konfigurieren

Standardmäßig verwendet der Cloud-Detektor die STABLE-Version des Modells und gibt bis zu 10 Ergebnisse zurück. Wenn Sie eine dieser Optionen können Sie diese mit einem FirebaseVisionCloudDetectorOptions -Objekt enthält.

Um beispielsweise beide Standardeinstellungen zu ändern, erstellen Sie ein FirebaseVisionCloudDetectorOptions-Objekt wie im Folgenden gezeigt. Beispiel:

Kotlin+KTX

val options = FirebaseVisionCloudDetectorOptions.Builder()
    .setModelType(FirebaseVisionCloudDetectorOptions.LATEST_MODEL)
    .setMaxResults(15)
    .build()

Java

FirebaseVisionCloudDetectorOptions options =
        new FirebaseVisionCloudDetectorOptions.Builder()
                .setModelType(FirebaseVisionCloudDetectorOptions.LATEST_MODEL)
                .setMaxResults(15)
                .build();

Wenn Sie die Standardeinstellungen verwenden möchten, können Sie im nächsten Schritt FirebaseVisionCloudDetectorOptions.DEFAULT eingeben.

Sehenswürdigkeiten-Erkennung ausführen

Wenn Sie Markierungen in einem Bild erkennen möchten, erstellen Sie ein FirebaseVisionImage-Objekt aus einem Bitmap-, media.Image-, ByteBuffer-, Byte-Array oder einer Datei auf dem Gerät. Übergeben Sie dann das FirebaseVisionImage-Objekt an die Die Methode detectInImage von FirebaseVisionCloudLandmarkDetector.

  1. Erstellen Sie ein FirebaseVisionImage-Objekt aus Ihrem Bild.

    • Um ein FirebaseVisionImage-Objekt aus einem media.Image-Objekt, z. B. beim Aufnehmen eines Bildes von einem des Geräts an und übergib das media.Image-Objekt und die Rotation auf FirebaseVisionImage.fromMediaImage().

      Wenn Sie die CameraX-Bibliothek verwenden, wird der Drehwert von den Klassen OnImageCapturedListener und ImageAnalysis.Analyzer für Sie berechnet. Sie müssen die Drehung also nur in eine der ROTATION_-Konstanten von Firebase ML umwandeln, bevor Sie FirebaseVisionImage.fromMediaImage() aufrufen:

      Kotlin+KTX

      private class YourImageAnalyzer : ImageAnalysis.Analyzer {
          private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) {
              0 -> FirebaseVisionImageMetadata.ROTATION_0
              90 -> FirebaseVisionImageMetadata.ROTATION_90
              180 -> FirebaseVisionImageMetadata.ROTATION_180
              270 -> FirebaseVisionImageMetadata.ROTATION_270
              else -> throw Exception("Rotation must be 0, 90, 180, or 270.")
          }
      
          override fun analyze(imageProxy: ImageProxy?, degrees: Int) {
              val mediaImage = imageProxy?.image
              val imageRotation = degreesToFirebaseRotation(degrees)
              if (mediaImage != null) {
                  val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation)
                  // Pass image to an ML Vision API
                  // ...
              }
          }
      }

      Java

      private class YourAnalyzer implements ImageAnalysis.Analyzer {
      
          private int degreesToFirebaseRotation(int degrees) {
              switch (degrees) {
                  case 0:
                      return FirebaseVisionImageMetadata.ROTATION_0;
                  case 90:
                      return FirebaseVisionImageMetadata.ROTATION_90;
                  case 180:
                      return FirebaseVisionImageMetadata.ROTATION_180;
                  case 270:
                      return FirebaseVisionImageMetadata.ROTATION_270;
                  default:
                      throw new IllegalArgumentException(
                              "Rotation must be 0, 90, 180, or 270.");
              }
          }
      
          @Override
          public void analyze(ImageProxy imageProxy, int degrees) {
              if (imageProxy == null || imageProxy.getImage() == null) {
                  return;
              }
              Image mediaImage = imageProxy.getImage();
              int rotation = degreesToFirebaseRotation(degrees);
              FirebaseVisionImage image =
                      FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
              // Pass image to an ML Vision API
              // ...
          }
      }

      Wenn Sie keine Kamerabibliothek verwenden, die Ihnen die Rotation des Bildes anzeigt, anhand der Drehung des Geräts und der Ausrichtung der Kamera Sensor im Gerät:

      Kotlin+KTX

      private val ORIENTATIONS = SparseIntArray()
      
      init {
          ORIENTATIONS.append(Surface.ROTATION_0, 90)
          ORIENTATIONS.append(Surface.ROTATION_90, 0)
          ORIENTATIONS.append(Surface.ROTATION_180, 270)
          ORIENTATIONS.append(Surface.ROTATION_270, 180)
      }
      /**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      @Throws(CameraAccessException::class)
      private fun getRotationCompensation(cameraId: String, activity: Activity, context: Context): Int {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          val deviceRotation = activity.windowManager.defaultDisplay.rotation
          var rotationCompensation = ORIENTATIONS.get(deviceRotation)
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager
          val sensorOrientation = cameraManager
              .getCameraCharacteristics(cameraId)
              .get(CameraCharacteristics.SENSOR_ORIENTATION)!!
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          val result: Int
          when (rotationCompensation) {
              0 -> result = FirebaseVisionImageMetadata.ROTATION_0
              90 -> result = FirebaseVisionImageMetadata.ROTATION_90
              180 -> result = FirebaseVisionImageMetadata.ROTATION_180
              270 -> result = FirebaseVisionImageMetadata.ROTATION_270
              else -> {
                  result = FirebaseVisionImageMetadata.ROTATION_0
                  Log.e(TAG, "Bad rotation value: $rotationCompensation")
              }
          }
          return result
      }

      Java

      private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
      static {
          ORIENTATIONS.append(Surface.ROTATION_0, 90);
          ORIENTATIONS.append(Surface.ROTATION_90, 0);
          ORIENTATIONS.append(Surface.ROTATION_180, 270);
          ORIENTATIONS.append(Surface.ROTATION_270, 180);
      }
      
      /**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      private int getRotationCompensation(String cameraId, Activity activity, Context context)
              throws CameraAccessException {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
          int rotationCompensation = ORIENTATIONS.get(deviceRotation);
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
          int sensorOrientation = cameraManager
                  .getCameraCharacteristics(cameraId)
                  .get(CameraCharacteristics.SENSOR_ORIENTATION);
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360;
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          int result;
          switch (rotationCompensation) {
              case 0:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  break;
              case 90:
                  result = FirebaseVisionImageMetadata.ROTATION_90;
                  break;
              case 180:
                  result = FirebaseVisionImageMetadata.ROTATION_180;
                  break;
              case 270:
                  result = FirebaseVisionImageMetadata.ROTATION_270;
                  break;
              default:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  Log.e(TAG, "Bad rotation value: " + rotationCompensation);
          }
          return result;
      }

      Übergeben Sie dann das media.Image-Objekt und den Drehwert an FirebaseVisionImage.fromMediaImage():

      Kotlin+KTX

      val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
    • Um ein FirebaseVisionImage-Objekt aus einem Datei-URI zu erstellen, übergeben Sie App-Kontext und Datei-URI zu FirebaseVisionImage.fromFilePath(). Dies ist nützlich, wenn Sie Verwenden Sie den Intent ACTION_GET_CONTENT, um den Nutzer zur Auswahl aufzufordern ein Bild aus ihrer Galerie-App.

      Kotlin+KTX

      val image: FirebaseVisionImage
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri)
      } catch (e: IOException) {
          e.printStackTrace()
      }

      Java

      FirebaseVisionImage image;
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri);
      } catch (IOException e) {
          e.printStackTrace();
      }
    • Wenn Sie ein FirebaseVisionImage-Objekt aus einem ByteBuffer oder einem Byte-Array erstellen möchten, berechnen Sie zuerst die Bilddrehung wie oben für die media.Image-Eingabe beschrieben.

      Erstellen Sie dann ein FirebaseVisionImageMetadata-Objekt. die die Höhe, Breite, Farbcodierung, und Rotation:

      Kotlin+KTX

      val metadata = FirebaseVisionImageMetadata.Builder()
          .setWidth(480) // 480x360 is typically sufficient for
          .setHeight(360) // image recognition
          .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
          .setRotation(rotation)
          .build()

      Java

      FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
              .setWidth(480)   // 480x360 is typically sufficient for
              .setHeight(360)  // image recognition
              .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
              .setRotation(rotation)
              .build();

      Verwenden Sie den Zwischenspeicher oder das Array und das Metadatenobjekt, um einen Objekt FirebaseVisionImage:

      Kotlin+KTX

      val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata)
      // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata);
      // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
    • Um ein FirebaseVisionImage-Objekt aus einem Bitmap-Objekt:

      Kotlin+KTX

      val image = FirebaseVisionImage.fromBitmap(bitmap)

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
      Das vom Bitmap-Objekt dargestellte Bild muss aufrecht sein und darf nicht zusätzlich gedreht werden.

  2. Rufen Sie eine FirebaseVisionCloudLandmarkDetector-Instanz ab:

    Kotlin+KTX

    val detector = FirebaseVision.getInstance()
        .visionCloudLandmarkDetector
    // Or, to change the default settings:
    // val detector = FirebaseVision.getInstance()
    //         .getVisionCloudLandmarkDetector(options)

    Java

    FirebaseVisionCloudLandmarkDetector detector = FirebaseVision.getInstance()
            .getVisionCloudLandmarkDetector();
    // Or, to change the default settings:
    // FirebaseVisionCloudLandmarkDetector detector = FirebaseVision.getInstance()
    //         .getVisionCloudLandmarkDetector(options);
  3. Übergeben Sie zuletzt das Bild an die Methode detectInImage:

    Kotlin+KTX

    val result = detector.detectInImage(image)
        .addOnSuccessListener { firebaseVisionCloudLandmarks ->
            // Task completed successfully
            // ...
        }
        .addOnFailureListener { e ->
            // Task failed with an exception
            // ...
        }

    Java

    Task<List<FirebaseVisionCloudLandmark>> result = detector.detectInImage(image)
            .addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionCloudLandmark>>() {
                @Override
                public void onSuccess(List<FirebaseVisionCloudLandmark> firebaseVisionCloudLandmarks) {
                    // Task completed successfully
                    // ...
                }
            })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    // Task failed with an exception
                    // ...
                }
            });

Informationen zu erkannten Sehenswürdigkeiten abrufen

Wenn die Landmark-Erkennung erfolgreich war, wird dem Erfolgs-Listener eine Liste von FirebaseVisionCloudLandmark-Objekten übergeben. Jedes Das Objekt FirebaseVisionCloudLandmark steht für eine Sehenswürdigkeit, die in der Bild. Für jede Sehenswürdigkeit können Sie die Begrenzungskoordinaten im Eingabebild abrufen. den Namen, den Breiten- und Längengrad, die Knowledge Graph-Entitäts-ID (falls verfügbar) und den Konfidenzwert der Übereinstimmung. Beispiel:

Kotlin+KTX

for (landmark in firebaseVisionCloudLandmarks) {
    val bounds = landmark.boundingBox
    val landmarkName = landmark.landmark
    val entityId = landmark.entityId
    val confidence = landmark.confidence

    // Multiple locations are possible, e.g., the location of the depicted
    // landmark and the location the picture was taken.
    for (loc in landmark.locations) {
        val latitude = loc.latitude
        val longitude = loc.longitude
    }
}

Java

for (FirebaseVisionCloudLandmark landmark: firebaseVisionCloudLandmarks) {

    Rect bounds = landmark.getBoundingBox();
    String landmarkName = landmark.getLandmark();
    String entityId = landmark.getEntityId();
    float confidence = landmark.getConfidence();

    // Multiple locations are possible, e.g., the location of the depicted
    // landmark and the location the picture was taken.
    for (FirebaseVisionLatLng loc: landmark.getLocations()) {
        double latitude = loc.getLatitude();
        double longitude = loc.getLongitude();
    }
}

Nächste Schritte