
Teilen Sie:
Britt Barak ist Produktmanagerin bei Nexmo und zuständig für die Nexmo Conversation API und Client SDKs.
Eine Erdbeere oder nicht? Klassifizieren Sie ein Bild mit MLKit für Android
Vor nicht allzu langer Zeit klang maschinelles Lernen (ML) noch wie ein Zauberwort. Details darüber, was und wie es verwendet werden sollte, waren für viele von uns eine Zeit lang ziemlich vage.
Das war damals. Spulen Sie vor bis heute, und eine der aufregendsten Ankündigungen der Google I/O 2018war für mich MLKit .. Kurz gesagt, MLKit nimmt einige gemeinsame ML Anwendungsfälle, und wickelt sie mit einem schönen API.
Wenn Ihre Anwendung einen speziellen Anwendungsfall abdeckt, können Sie mit MLKit außerdem benutzerdefinierte Modelle erstellen und verwenden sowie nützliche Funktionen zur Versionsverwaltung nutzen.
Einer der sofort einsetzbaren Anwendungsfälle ist Bildbeschriftung, auch bekannt als Bildklassifizierung. Dies bedeutet, dass man ein Bild nimmt und die darin enthaltenen Objekte erkennt, wie z. B. Tiere, Früchte, Aktivitäten usw. Für jede Bildeingabe wird eine Liste von Entitäten (Labels) mit einer Punktzahl ausgegeben, die den Grad des Vertrauens darstellt, dass diese Entität tatsächlich in dem Bild vorhanden ist. Diese Labels können zur Durchführung von Aktionen wie Inhaltsmoderation, Filterung oder Suche verwendet werden.
Da mobile Geräte nur über begrenzte Ressourcen verfügen und die Minimierung des Datenverbrauchs oft ein Segen ist, kann die Arbeit mit Metadaten anstelle eines ganzen Fotos bei Fragen der Leistung, des Datenschutzes, der Bandbreite, der Offline-Unterstützung und mehr helfen. Bei einer Chat-App kann es zum Beispiel von großem Vorteil sein, nur Beschriftungen und nicht ein ganzes Foto senden zu können.
Dieses Tutorial führt Sie durch das Schreiben einer mobilen Anwendung, die ein Bild aufnehmen und die darin enthaltenen Objekte erkennen kann. Es besteht aus 3 Teilen:
Mein absolutes Lieblingsessen auf der Welt sind Erdbeeren ?! Ich könnte sie jeden Tag essen, den ganzen Tag, und es würde mich so glücklich machen!
Wir wollen eine App entwickeln, die ein Bild aufnimmt und dann erkennt, ob es eine Erdbeere enthält oder nicht!
Die App, die Sie erstellen werden:
Der Benutzer wählt ein Bild aus und wählt über eine Schaltfläche, wie es klassifiziert werden soll.
Die Benutzeroberfläche übergibt das Bild (Bitmap Objekt) an die ImageClassifier Klasse, die das Bild an einen bestimmten Klassifikator sendet, der ausgewählt wurde (LocalClassifier, CloudClassifier oder CustomClassifier. In diesem Lernprogramm werden nur die ersten beiden behandelt). Jeder Klassifikator verarbeitet die Eingabe, führt das Modell aus, verarbeitet die Ausgabe, falls erforderlich, und sendet dann das Ergebnis an ImageClassifier der es so aufbereitet, dass es von der Benutzeroberfläche möglichst einfach angezeigt werden kann.
Bevor Sie anfangen:
Klonen Sie dieses Projekt mit dem Code für den Einstieg und die Implementierung pro Schritt https://github.com/brittBarak/MLKitDemo
Fügen Sie Firebase zu Ihrer Anwendung hinzu:
Melden Sie sich bei der Firebase-Konsole an: https://console.firebase.google.com
Erstellen Sie ein neues Projekt, oder wählen Sie ein bestehendes aus
Gehen Sie im Menü auf der linken Seite auf Einstellungen → Einstellungen.
Wählen Sie auf der Registerkarte Allgemein → im Abschnitt Ihre Apps die Option "App hinzufügen".
Folgen Sie den Schritten im Firebase-Tutorial, um Firebase zu Ihrer Anwendung hinzuzufügen.
Fügen Sie
firebase-ml-visionBibliothek zu Ihrer Anwendung: auf Ihrer Anwendungsebenebuild.gradleDatei hinzufügen:
dependencies {
// …
implementation ‘com.google.firebase:firebase-ml-vision:17.0.0’
}Wie bereits erwähnt, werden in diesem Lernprogramm sowohl lokale als auch cloudbasierte Detektoren eingesetzt. Jeder hat 4 Schritte:
Einrichten (das ist kein Schummeln :) zählt nicht wirklich als Schritt...)
Einrichten des Klassifikators
Verarbeiten Sie die Eingabe
Verarbeiten Sie die Ausgabe
Hinweis: Wenn Sie es vorziehen, lange mit dem endgültigen Code zu folgen, können Sie es auf Zweig finden 1.run_local_model der Demo im Repo.
Ausführung eines lokalen (geräteinternen) Modells
Die Wahl eines lokalen Modells ist die leichteste, offline unterstützte Option, und sie ist kostenlos. Im Gegenzug hat es 400+ Etiketten, so dass die Genauigkeit begrenzt ist, was wir berücksichtigen müssen.
Die Benutzeroberfläche nimmt die Bitmap → ruft ImageClassifier.executeLocal(bitmap)→ ImageClassifier ruft auf. LocalClassifier.execute()
Wenn Sie es vorziehen, dem endgültigen Code zu folgen, finden Sie ihn in der Verzweigung 1.run_local_model.
Schritt 0: Einrichten
Hinzufügen des lokalen Detektors zu Ihrer App, erleichtert durch Firebase MLKit:
Auf Ihrer App-Ebene build.gradle Datei hinzufügen:
dependencies {
// ...
implementation 'com.google.firebase:firebase-ml-vision-image-label-model:15.0.0'
}Optional, aber empfohlenStandardmäßig wird das ML-Modell selbst nur heruntergeladen, wenn Sie den Detektor ausführen. Das bedeutet, dass es bei der ersten Ausführung zu einer gewissen Latenz kommt und ein Netzwerkzugang erforderlich ist. Um dies zu umgehen und das ML-Modell bei der Installation der App aus dem Play Store herunterzuladen, fügen Sie einfach die folgende Erklärung in die Datei AndroidManifest.xml Ihrer App ein:
...
<!-- To use multiple models: android:value="label,barcode,face..." --> Schritt 1: Einrichten des Klassifikators
Erstellen Sie LocalClassifier Klasse, die das Detektorobjekt enthält:
public class LocalClassifier {
detector = FirebaseVision.getInstance().getVisionLabelDetector();
}Dies ist die Basisinstanz des Detektors. Sie können mehr über die zurückgegebene Ausgabe bestimmen, und fügen Sie Konfidenz-Schwellenwerthinzufügen, der zwischen 0-1 liegt, mit 0,5 als Standard.
class LocalClassifier {
//...
FirebaseVisionImage image;
public void execute(Bitmap bitmap) {
image = FirebaseVisionImage.fromBitmap(bitmap);
}
} Schritt 2: Verarbeiten der Eingabe
FirebaseVisionLabelDetector weiß, wie man mit einer Eingabe vom Typ FirebaseVisionImage. Sie können eine FirebaseVisionImage Instanz entweder von:
Bitmap (das werden wir hier verwenden) , Image Uri, MediaImage(von Medien, z. B. der Gerätekamera), ByteArray, oder ByteBuffer.
Die Verarbeitung eines Bitmap wird folgendermaßen durchgeführt:
public class LocalClassifier {
//...
public void execute(Bitmap bitmap, OnSuccessListener successListener, OnFailureListener failureListener) {
//...
detector.detectInImage(image)
.addOnSuccessListener(successListener)
.addOnFailureListener(failureListener);
}
}Tipp: Einer der Gründe für die Verwendung eines lokalen Modells ist die schnellere Ausführung, aber die Ausführung eines jeden Modells nimmt einige Zeit in Anspruch. Wenn Sie das Modell in einer Echtzeitanwendung verwenden, benötigen Sie die Ergebnisse möglicherweise noch schneller. Eine Verringerung der Bitmap-Größe vor dem nächsten Schritt kann die Verarbeitungszeit des Modells verbessern.
Schritt 3: Das Modell ausführen
Hier passiert die Magie! ? Da das Modell eine gewisse Berechnungszeit benötigt, sollten wir das Modell asynchron laufen lassen und das Ergebnis bei Erfolg oder Misserfolg mit Hilfe von Listenern zurückgeben.
public class LocalClassifier {
//...
public void execute(Bitmap bitmap, OnSuccessListener successListener, OnFailureListener failureListener) {
//...
detector.detectInImage(image)
.addOnSuccessListener(successListener)
.addOnFailureListener(failureListener);
}
} Schritt 4: Verarbeiten der Ausgabe
Der Erkennungsausgang ist vorgesehen für OnSuccessListener. Ich ziehe es vor, dass die OnSuccessListener übergeben an LocalClassifier von ImageClassifierübergeben, das die Kommunikation zwischen der Benutzeroberfläche und LocalClassifier.
Die UI ruft ImageClassifier.executeLocal() auf, was in etwa so aussehen sollte:
Auf ImageClassifier.java:
localClassifier = new LocalClassifier();
public void executeLocal(Bitmap bitmap, ClassifierCallback callback) {
successListener = new OnSuccessListener<List>() {
public void onSuccess(List labels) {
processLocalResult(labels, callback, start);
}
};
localClassifier.execute(bitmap, successListener, failureListener);
processLocalResult() bereitet lediglich die Ausgabebeschriftungen für die Anzeige auf der Benutzeroberfläche vor.
In meinem speziellen Fall habe ich mich dafür entschieden, die 3 Ergebnisse mit der höchsten Wahrscheinlichkeit anzuzeigen. Sie können jeden anderen Formattyp wählen. Um das Bild zu vervollständigen, ist dies meine Implementierung:
OnImageClassifier.java:
void processLocalResult(List labels, ClassifierCallback callback) {
labels.sort(localLabelComparator);
resultLabels.clear();
FirebaseVisionLabel label;
for (int i = 0; i < Math.min(3, labels.size()); ++i) {
label = labels.get(i);
resultLabels.add(label.getLabel() + “:” + label.getConfidence());
}
callback.onClassified(“Local Model”, resultLabels);
}ClassifierCallback ist eine einfache Schnittstelle, die ich erstellt habe, um die Ergebnisse an die Benutzeroberfläche weiterzugeben. Wir hätten auch jede andere verfügbare Methode verwenden können. Das ist eine Frage der Vorliebe.
interface ClassifierCallback {
void onClassified(String modelTitle, List topLabels);
} Das war's!
Sie haben Ihr erstes ML-Modell zur Klassifizierung eines Bildes verwendet! ? Wie einfach war das?!
Lassen wir die Anwendung laufen und sehen wir uns die Ergebnisse an! Den endgültigen Code für diesen Teil finden Sie in der Demo Repo auf dem Zweig 1.run_local_model
Ziemlich gut! Wir haben einige allgemeine Bezeichnungen wie "Lebensmittel" oder "Obst", die definitiv ins Bild passen. Für einige Anwendungsfälle ist dieses Modell sehr gut geeignet. Es kann helfen, Bilder zu gruppieren, eine Suche durchzuführen und so weiter. Aber für unseren Fall erwarten wir ein Modell, das angeben kann, welche Früchte auf dem Foto sind.
Versuchen wir, einige aussagekräftigere und genauere Kennzeichnungen zu erhalten, indem wir den cloudbasierten Detektor verwenden, der mehr als 10.000 Kennzeichnungen zur Verfügung hat:
Betrieb eines cloudbasierten Modells
Schritt 0: Einrichten
Die Cloud-basierten Modelle von MLKit gehören zur Cloud Vision APIzu, die Sie für Ihr Projekt aktivieren müssen:
Bei einem Cloud-basierten Modell muss ein Kontingent von mehr als 1000 monatlichen Nutzungen bezahlt werden. Für Demo- und Entwicklungszwecke ist es unwahrscheinlich, dass Sie in die Nähe dieses Kontingents kommen werden. Sie müssen jedoch Ihren Firebase-Projektplan aktualisieren, so dass er theoretisch bei Bedarf in Rechnung gestellt werden kann. Aktualisieren Sie Ihr Spark Projektplan, der kostenlos ist, auf einen Blaze Plan, der kostenpflichtig ist und Ihnen die Nutzung der Cloud Vision-APIs ermöglicht. Sie können dies über die Firebase-Konsole.
Aktivieren Sie die Cloud Vision API in der Cloud Console-API-Bibliothek. Wählen Sie im oberen Menü Ihr Firebase-Projekt aus und klicken Sie, falls noch nicht aktiviert, auf Aktivieren.
Hinweis: Für die Entwicklung ist diese Konfiguration ausreichend. Vor dem Einsatz in der Produktion sollten Sie jedoch einige zusätzliche Schritte unternehmen, um sicherzustellen, dass mit Ihrem Account keine unbefugten Anrufe getätigt werden. Für diesen Fall lesen Sie bitte die Anweisungen hier.
Schritt 1: Einrichten des Klassifikators
Erstellen Sie eine CloudClassifier Klasse, die das Detektorobjekt enthält:
public class CloudClassifier {
detector = FirebaseVision.getInstance().getVisionCloudLabelDetector();
}Dies ist fast dasselbe wie das oben beschriebene LocalClassifieraußer dem Typ des Detektors.
Es gibt ein paar zusätzliche Optionen, die wir am Detektor einstellen können:
setMaxResults()- werden standardmäßig 10 Ergebnisse zurückgegeben. Wenn Sie mehr als das brauchen, müssen Sie das angeben. Andererseits habe ich bei der Entwicklung der Demo-Anwendung beschlossen, nur die ersten 3 Ergebnisse anzuzeigen. Ich kann sie hier definieren und die Berechnung ein wenig beschleunigen.setModelType()- kann entweder STABIL_MODELL oder sein. LATEST_MODELsein, letzteres ist Standard.
public class CloudClassifier {
options = new FirebaseVisionCloudDetectorOptions.Builder()
.setModelType(FirebaseVisionCloudDetectorOptions.LATEST_MODEL)
.setMaxResults(ImageClassifier.RESULTS_TO_SHOW)
.build();
detector = FirebaseVision.getInstance().getVisionCloudLabelDetector(options);
} Schritt 2: Verarbeiten der Eingabe
Ähnlich wie bei LocalDetector, FirebaseVisionCloudLabelDetector verwendet eine Eingabe von FirebaseVisionImagedie wir von einem Bitmap, um die Benutzeroberfläche zu erleichtern;
public class CloudClassifier {
//...
FirebaseVisionImage image;
public void execute(Bitmap bitmap) {
image = FirebaseVisionImage.fromBitmap(bitmap);
}
} Schritt 3: Das Modell ausführen
Wie die vorangegangenen Schritte ähnelt auch dieser Schritt stark dem, den wir für die Ausführung des lokalen Modells durchgeführt haben:
public class CloudClassifier {
public void execute(Bitmap bitmap, OnSuccessListener successListener, OnFailureListener failureListener) {
//...
detector.detectInImage(image)
.addOnSuccessListener(successListener)
.addOnFailureListener(failureListener);
}
} Schritt 4: Verarbeiten der Ausgabe
Da sich das lokale Modell von dem wolkenbasierten Modell unterscheidet, sind auch die Ausgaben unterschiedlich, so dass der Objekttyp, den wir als Antwort auf OnSuccessListener pro Detektor unterschiedlich ist. Dennoch sind die Objekte, mit denen wir arbeiten, ziemlich gleich.
Auf ImageClassifier.java:
cloudClassifier = new CloudClassifier();
public void executeCloud(Bitmap bitmap, ClassifierCallback callback) {
successListener = new OnSuccessListener<List>() {
public void onSuccess(List labels) {
processCloudResult(labels, callback, start);
}
};
cloudClassifier.execute(bitmap, successListener, failureListener);
}Auch hier ist die Verarbeitung der Ergebnisse, die die Benutzeroberfläche anzeigen soll, Ihre eigene Entscheidung, was die Benutzeroberfläche anzeigen soll. Für dieses Beispiel:
processCloudResult(List labels, ClassifierCallback callback) {
labels.sort(cloudLabelComparator);
resultLabels.clear();
FirebaseVisionCloudLabel label;
for (int i = 0; i < Math.min(RESULTS_TO_SHOW, labels.size()); ++i) {
label = labels.get(i);
resultLabels.add(label.getLabel() + ":" + label.getConfidence());
}
callback.onClassified("Cloud Model", resultLabels);
} Das war's dann auch schon! ?
Schauen wir uns einige Ergebnisse an: Der Code für diesen Beitrag ist im Repo zu finden, im Zweig 2.run_cloud_model
Wie erwartet, brauchte das Modell etwas länger, kann aber nun erkennen, welche Frucht auf dem Bild zu sehen ist. Außerdem ist es zu mehr als 90 % sicher, dass das Ergebnis stimmt, im Vergleich zu 70-80 % Sicherheit beim lokalen Modell.
Ich hoffe, dies hilft Ihnen zu verstehen, wie einfach und unterhaltsam es ist, Firebase MLKit zu verwenden. Die Verwendung der anderen Modelle: Gesichtserkennung, Barcode-Scanning, etc. funktioniert auf sehr ähnliche Weise und ich ermutige Sie, es auszuprobieren!
Können wir noch bessere Ergebnisse erzielen? Auch das werden wir in einem der nächsten Beiträge anhand eines benutzerdefinierten Modells untersuchen.
Was kommt als Nächstes?
Wenn Sie mehr darüber erfahren möchten, was maschinelles Lernen ist und wie es funktioniert, lesen Sie diese entwicklerfreundlichen Blogbeiträge zur Einführung: bit.ly/brittML-1, bit.ly/brittML-2, bit.ly/brittML-3
Weitere Informationen darüber, warum MLKit verwendet werden sollte, finden Sie in diesen Beitrag und die offizielle Dokumentation