Erste Schritte mit der Bilderkennung in Core ML
German (Deutsch) translation by Katharina Grigorovich-Nevolina (you can also view the original English article)
Mit dem technologischen Fortschritt sind wir an dem Punkt angelangt, an dem unsere Geräte ihre eingebauten Kameras verwenden können, um Bilder mithilfe eines vorab trainierten Datensatzes genau zu identifizieren und zu kennzeichnen. Sie können auch Ihre eigenen Modelle trainieren. In diesem Lernprogramm verwenden wir jedoch ein Open-Source-Modell, um eine Bildklassifizierungs-App zu erstellen.
Ich zeige Ihnen, wie Sie eine App erstellen, mit der Bilder identifiziert werden können. Wir beginnen mit einem leeren Xcode-Projekt und implementieren Schritt für Schritt die maschinell lernbasierte Bilderkennung.
Einstieg
Xcode-Version
Bevor wir beginnen, stellen Sie sicher, dass Sie die neueste Version von Xcode auf Ihrem Mac installiert haben. Dies ist sehr wichtig, da Core ML nur für Xcode 9 oder höher verfügbar ist. Sie können Ihre Version überprüfen, indem Sie Xcode öffnen und in der oberen Symbolleiste zu Xcode > Über Xcode gehen.
Wenn Ihre Version von Xcode älter als Xcode 9 ist, können Sie den Mac App Store aufrufen und aktualisieren. Wenn Sie ihn nicht haben, können Sie ihn kostenlos herunterladen.
Beispielprojekt
Neues Projekt
Nachdem Sie sichergestellt haben, dass Sie die richtige Version von Xcode haben, müssen Sie ein neues Xcode-Projekt erstellen.
Öffnen Sie Xcode und klicken Sie auf Neues Xcode-Projekt erstellen.



Als Nächstes müssen Sie eine Vorlage für Ihr neues Xcode-Projekt auswählen. Es ist ziemlich üblich, eine Single View-App zu verwenden. Wählen Sie diese aus und klicken Sie auf Weiter.



Sie können Ihr Projekt beliebig benennen, aber ich werde meine CoreML-Bildklassifizierung benennen. Für dieses Projekt verwenden wir Swift. Stellen Sie daher sicher, dass es in der Dropdown-Liste Sprache ausgewählt ist.



Vorbereitung zum Debuggen
IPhone anschließen
Da der Xcode Simulator keine Kamera hat, müssen Sie Ihr iPhone anschließen. Wenn Sie kein iPhone haben, müssen Sie sich leider eines ausleihen, um diesem Tutorial (und allen anderen kamerabezogenen Apps) folgen zu können. Wenn Sie bereits ein iPhone mit Xcode verbunden haben, können Sie mit dem nächsten Schritt fortfahren.
Eine raffinierte neue Funktion in Xcode 9 ist, dass Sie Ihre App drahtlos auf einem Gerät debuggen können. Nehmen Sie sich also die Zeit, dies jetzt einzurichten:
Wählen Sie in der oberen Menüleiste Fenster > Geräte und Simulatoren. Stellen Sie im angezeigten Fenster sicher, dass oben Geräte ausgewählt ist.
Schließen Sie jetzt Ihr Gerät mit einem Blitzkabel an. Dadurch sollte Ihr Gerät im linken Bereich des Fensters Geräte und Simulatoren angezeigt werden. Klicken Sie einfach auf Ihr Gerät und aktivieren Sie das Kontrollkästchen Über Netzwerk verbinden.



Sie können jetzt auf diesem iPhone drahtlos für alle zukünftigen Apps debuggen. Um weitere Geräte hinzuzufügen, können Sie einen ähnlichen Vorgang ausführen.
Simulatorauswahl



Wenn Sie Ihr iPhone endlich zum Debuggen verwenden möchten, wählen Sie es einfach aus der Dropdown-Liste neben der Schaltfläche Ausführen aus. Daneben sollte ein Netzwerksymbol angezeigt werden, das anzeigt, dass es für das drahtlose Debuggen verbunden ist. Ich habe Vardhans iPhone ausgewählt, aber Sie müssen Ihr spezielles Gerät auswählen.
Tiefer tauchen
Nachdem Sie Ihr Projekt erstellt und Ihr iPhone als Simulator eingerichtet haben, werden wir etwas tiefer gehen und mit der Programmierung der Echtzeit-Bildklassifizierungs-App beginnen.
Vorbereiten Ihres Projekts
Ein Modell bekommen
Um mit der Erstellung Ihrer Core ML-Bildklassifizierungs-App beginnen zu können, müssen Sie zunächst das Core ML-Modell von der Apple-Website herunterladen. Wie bereits erwähnt, können Sie auch Ihre eigenen Modelle trainieren, dies erfordert jedoch einen separaten Prozess. Wenn Sie zum Ende der Apple-Website für maschinelles Lernen scrollen, können Sie ein Modell auswählen und herunterladen.
In diesem Tutorial werde ich das MobileNet.mlmodel-Modell verwenden, aber Sie können jedes Modell verwenden, solange Sie seinen Namen kennen und sicherstellen, dass es mit .mlmodel endet.



Bibliotheken importieren
Es gibt einige Frameworks, die Sie zusammen mit dem üblichen UIKit importieren müssen. Stellen Sie oben in der Datei sicher, dass die folgenden Importanweisungen vorhanden sind:
1 |
import UIKit |
2 |
import AVKit |
3 |
import Vision |
Wir benötigen AVKit, da wir eine AVCaptureSession erstellen, um einen Live-Feed anzuzeigen und gleichzeitig Bilder in Echtzeit zu klassifizieren. Da hierfür Computer Vision verwendet wird, müssen wir das Vision-Framework importieren.
Entwerfen Ihrer Benutzeroberfläche
Ein wichtiger Teil dieser App ist die Anzeige der Bildklassifizierungsdatenetiketten sowie des Live-Video-Feeds von der Kamera des Geräts. Um mit dem Entwerfen Ihrer Benutzeroberfläche zu beginnen, rufen Sie Ihre Main.storyboard-Datei auf.
Hinzufügen einer Bildansicht
Gehen Sie zur Objektbibliothek und suchen Sie nach einer Bildansicht. Ziehen Sie dies einfach auf Ihren View Controller, um es hinzuzufügen. Wenn Sie möchten, können Sie auch ein Platzhalterbild hinzufügen, um eine allgemeine Vorstellung davon zu erhalten, wie die App bei Verwendung aussehen wird.
Wenn Sie sich für ein Platzhalterbild entscheiden, stellen Sie sicher, dass der Inhaltsmodus auf Aspektanpassung eingestellt ist und dass Sie das Kontrollkästchen Clip to Bounds aktivieren. Auf diese Weise wird das Bild nicht gestreckt und nicht außerhalb des UIImageView-Felds angezeigt.



So sollte Ihr Storyboard jetzt aussehen:



Hinzufügen einer Ansicht
Suchen Sie in der Objektbibliothek nach einer Ansicht und ziehen Sie sie auf Ihren View Controller. Dies dient als schöner Hintergrund für unsere Etiketten, damit sie nicht im angezeigten Bild versteckt werden. Wir werden diese Ansicht durchscheinend machen, damit ein Teil der Vorschauebene noch sichtbar ist (dies ist nur eine nette Geste für die Benutzeroberfläche der App).
Ziehen Sie dies an den unteren Bildschirmrand, sodass es den Container an drei Seiten berührt. Es spielt keine Rolle, welche Höhe Sie wählen, da wir hier gleich Einschränkungen festlegen werden.



Etiketten hinzufügen
Dies ist vielleicht der wichtigste Teil unserer Benutzeroberfläche. Wir müssen anzeigen, was unsere App für das Objekt hält und wie sicher es ist (Konfidenzniveau). Wie Sie wahrscheinlich erraten haben, müssen Sie zwei Beschriftung(en) aus der Objektbibliothek in die gerade erstellte Ansicht ziehen. Ziehen Sie diese Beschriftungen irgendwo in der Nähe der Mitte übereinander gestapelt.
Gehen Sie für die oberste Beschriftung zum Attributinspektor, klicken Sie auf die Schaltfläche T neben dem Schriftstil und der Schriftgröße und wählen Sie im Popup System als Schriftart aus. Um dies vom Konfidenzetikett zu unterscheiden, wählen Sie Schwarz als Stil. Zuletzt ändern Sie die Größe auf 24.



Befolgen Sie für die untere Beschriftung die gleichen Schritte, wählen Sie jedoch anstelle von Schwarz als Stil Normal und für die Größe 17 aus.



Das folgende Bild zeigt, wie Ihr Storyboard aussehen sollte, wenn Sie alle diese Ansichten und Beschriftungen hinzugefügt haben. Mach dir keine Sorgen, wenn sie nicht genau die gleichen sind wie deine. Wir werden ihnen im nächsten Schritt Einschränkungen hinzufügen.



Hinzufügen von Einschränkungen
Damit diese App auf verschiedenen Bildschirmgrößen funktioniert, müssen Einschränkungen hinzugefügt werden. Dieser Schritt ist für den Rest der App nicht entscheidend, es wird jedoch dringend empfohlen, dies in allen Ihren iOS-Apps zu tun.
Bildansichtsbeschränkungen
Das erste, was Sie einschränken müssen, ist unser UIImageView. Wählen Sie dazu Ihre Bildansicht aus und öffnen Sie das Pin-Menü in der unteren Symbolleiste (dies sieht aus wie ein Quadrat mit den Einschränkungen und ist das zweite von rechts). Dann müssen Sie die folgenden Werte hinzufügen:



Bevor Sie fortfahren, stellen Sie sicher, dass das Kontrollkästchen Auf Ränder beschränken nicht aktiviert ist, da dadurch eine Lücke zwischen dem Bildschirm und der tatsächlichen Bildansicht entsteht. Drücken Sie dann die Eingabetaste. Jetzt ist Ihr UIImageView auf dem Bildschirm zentriert und sollte auf allen Gerätegrößen richtig aussehen.
Einschränkungen anzeigen
Der nächste Schritt besteht nun darin, die Ansicht einzuschränken, in der die Beschriftungen angezeigt werden. Wählen Sie die Ansicht aus und gehen Sie erneut zum Pin-Menü. Fügen Sie die folgenden Werte hinzu:



Drücken Sie jetzt einfach die Eingabetaste, um die Werte zu speichern. Ihre Ansicht ist jetzt auf den unteren Bildschirmrand beschränkt.
Beschriftung-Beschränkungen
Da die Ansicht jetzt eingeschränkt ist, können Sie den Beschriftungen Einschränkungen in Bezug auf die Ansicht anstelle des Bildschirms hinzufügen. Dies ist hilfreich, wenn Sie später die Position der Beschriftungen oder der Ansicht ändern möchten.
Wählen Sie beide Beschriftungen aus und legen Sie sie in einer Stapelansicht ab. Wenn Sie nicht wissen, wie das geht, müssen Sie nur die Taste (zweite von links) drücken, die wie ein Stapel Bücher mit einem Abwärtspfeil aussieht. Sie werden dann sehen, dass die Schaltflächen zu einem auswählbaren Objekt werden.
Klicken Sie auf Ihre Stapelansicht und dann auf das Ausrichtungsmenü (drittes von links) und stellen Sie sicher, dass die folgenden Kontrollkästchen aktiviert sind:



Drücken Sie jetzt die Eingabetaste. Ihre Beschriftungen sollten in der Ansicht aus dem vorherigen Schritt zentriert sein und werden nun auf allen Bildschirmgrößen gleich angezeigt.
Schnittstellen-Builder-Ausgänge
Der letzte Schritt in der Benutzeroberfläche besteht darin, die Elemente mit Ihrer ViewController()-Klasse zu verbinden. Öffnen Sie einfach den Assistenten-Editor und klicken Sie bei gedrückter Ctrl-Taste und ziehen Sie jedes Element in ViewController.swift an den Anfang Ihrer Klasse. In diesem Tutorial werde ich sie wie folgt benennen:
-
UILabel:objectLabel -
UILabel:confidenceLabel -
UIImageView:imageView
Natürlich können Sie sie benennen, was Sie wollen, aber diese Namen finden Sie in meinem Code.
Vorbereiten einer Erfassungssitzung
Für den Live-Video-Feed ist eine AVCaptureSession erforderlich. Erstellen wir also jetzt eine. Wir werden dem Benutzer auch unsere Kameraeingaben in Echtzeit anzeigen. Das Erstellen einer Aufnahmesitzung ist ein ziemlich langer Prozess, und es ist wichtig, dass Sie verstehen, wie dies zu tun ist, da dies bei jeder anderen Entwicklung hilfreich ist, die Sie mit der integrierten Kamera auf einem der Apple-Geräte durchführen.
Klassenerweiterung und Funktion
Zunächst können wir eine Klassenerweiterung erstellen und sie dann an das AVCaptureVideoDataOutputSampleBufferDelegate-Protokoll anpassen. Sie können dies problemlos innerhalb der eigentlichen ViewController-Klasse tun. Wir verwenden hier jedoch bewährte Methoden, damit der Code ordentlich und organisiert ist (so würden Sie es für Produktions-Apps tun).
Damit wir dies in viewDidLoad() aufrufen können, müssen wir eine Funktion namens setupSession() erstellen, die keine Parameter akzeptiert. Sie können dies beliebig benennen, aber beachten Sie die Benennung, wenn wir diese Methode später aufrufen.
Sobald Sie fertig sind, sollte Ihr Code wie folgt aussehen:
1 |
// MARK: - AVCaptureSession
|
2 |
extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate { |
3 |
func setupSession() { |
4 |
// Your code goes here
|
5 |
}
|
6 |
}
|
Geräteeingabe und Erfassungssitzung
Der erste Schritt beim Erstellen der Erfassungssitzung besteht darin, zu überprüfen, ob das Gerät über eine Kamera verfügt. Mit anderen Worten, versuchen Sie nicht, die Kamera zu verwenden, wenn keine Kamera vorhanden ist. Wir müssen dann die eigentliche Erfassungssitzung erstellen.
Fügen Sie Ihrer setupSession()-Methode den folgenden Code hinzu:
1 |
guard let device = AVCaptureDevice.default(for: .video) else { return } |
2 |
guard let input = try? AVCaptureDeviceInput(device: device) else { return } |
3 |
|
4 |
let session = AVCaptureSession() |
5 |
session.sessionPreset = .hd4K3840x2160 |
Hier verwenden wir eine guard let-Anweisung, um zu überprüfen, ob das Gerät (AVCaptureDevice) über eine Kamera verfügt. Wenn Sie versuchen, die Kamera des Geräts abzurufen, müssen Sie auch den mediaType angeben, in diesem Fall .video.
Anschließend erstellen wir einen AVCaptureDeviceInput, einen Eingang, der die Medien vom Gerät zur Erfassungssitzung bringt.
Schließlich erstellen wir einfach eine Instanz der AVCaptureSession-Klasse und weisen sie dann einer Variablen namens session zu. Wir haben die Sitzungsbitrate und -qualität an Ultra-High-Definition(UHD) angepasst, die 3840 x 2160 Pixel beträgt. Sie können mit dieser Einstellung experimentieren, um zu sehen, was für Sie funktioniert.
Vorschau von Ebene und Ausgabe
Der nächste Schritt bei der Einrichtung von AVCaptureSession besteht darin, eine Vorschauebene zu erstellen, in der der Benutzer die Eingaben von der Kamera sehen kann. Wir werden dies zu der UIImageView hinzufügen, die wir zuvor in unserem Storyboard erstellt haben. Der wichtigste Teil ist jedoch die Erstellung unserer Ausgabe für das Core ML-Modell, die später in diesem Lernprogramm verarbeitet werden soll. Dies werden wir auch in diesem Schritt tun.
Fügen Sie den folgenden Code direkt unter dem Code aus dem vorherigen Schritt hinzu:
1 |
et previewLayer = AVCaptureVideoPreviewLayer(session: session) |
2 |
previewLayer.frame = view.frame |
3 |
imageView.layer.addSublayer(previewLayer) |
4 |
|
5 |
let output = AVCaptureVideoDataOutput() |
6 |
output.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue")) |
7 |
session.addOutput(output) |
Wir erstellen zuerst eine Instanz der AVCaptureVideoPreviewLayer-Klasse und initialisieren sie dann mit der Sitzung, die wir im vorherigen Schritt erstellt haben. Danach weisen wir es einer Variablen namens previewLayer zu. Diese Ebene wird verwendet, um die Eingabe von der Kamera tatsächlich anzuzeigen.
Als Nächstes wird die Vorschauebene den gesamten Bildschirm ausfüllen, indem die Rahmenabmessungen auf die der Ansicht festgelegt werden. Auf diese Weise bleibt das gewünschte Erscheinungsbild für alle Bildschirmgrößen erhalten. Um die Vorschauebene tatsächlich anzuzeigen, fügen wir sie als Unterebene der UIImageView hinzu, die wir bei der Erstellung der Benutzeroberfläche erstellt haben.
Nun zum wichtigen Teil: Wir erstellen eine Instanz der AVCaptureDataOutput-Klasse und weisen sie einer Variablen namens output zu.
Sitzung eingeben und starten
Schließlich sind wir mit unserer Erfassungssitzung fertig. Alles, was Sie vor dem eigentlichen Core ML-Code tun müssen, ist, die Eingabe hinzuzufügen und die Erfassungssitzung zu starten.
Fügen Sie die folgenden zwei Codezeilen direkt unter dem vorherigen Schritt hinzu:
1 |
// Sets the input of the AVCaptureSession to the device's camera input
|
2 |
session.addInput(input) |
3 |
// Starts the capture session
|
4 |
session.startRunning() |
Dadurch wird die zuvor erstellte Eingabe zur AVCaptureSession hinzugefügt, da wir zuvor nur die Eingabe erstellt und nicht hinzugefügt hatten. Zuletzt startet diese Codezeile die Sitzung, die wir so lange erstellt haben.
Integration des ML-Kernmodells
Wir haben das Modell bereits heruntergeladen. Der nächste Schritt besteht darin, es tatsächlich in unserer App zu verwenden. Beginnen wir also damit, Bilder zu klassifizieren.
Methode delegieren
Zunächst müssen Sie Ihrer App die folgende Delegierungsmethode hinzufügen:
1 |
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { |
2 |
// Your code goes here
|
3 |
}
|
Diese Delegatmethode wird ausgelöst, wenn ein neuer Videorahmen geschrieben wird. In unserer App geschieht dies jedes Mal, wenn ein Frame über unseren Live-Video-Feed aufgezeichnet wird (die Geschwindigkeit hängt ausschließlich von der Hardware ab, auf der die App ausgeführt wird).
Pixelpuffer und Modell
Jetzt verwandeln wir das Bild (ein Bild aus dem Live-Feed) in einen Pixelpuffer, der vom Modell erkannt wird. Damit können wir später eine VNCoreMLRequest erstellen.
Fügen Sie die folgenden zwei Codezeilen in die zuvor erstellte Delegatenmethode ein:
1 |
guard let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } |
2 |
guard let model = try? VNCoreMLModel(for: MobileNet().model) else { return } |
Zuerst erstellen wir aus dem Argument, das über die Delegate-Methode übergeben wird, einen Pixelpuffer (ein Format, das Core ML akzeptiert) und weisen ihn dann einer Variablen namens pixelBuffer zu. Dann weisen wir unser MobileNet-Modell einer Konstante zu, die als model bezeichnet wird.
Beachten Sie, dass beide mithilfe von guard let-Anweisungen erstellt werden und dass die Funktion zurückgegeben wird, wenn einer dieser Werte nil ist.
Anfrage erstellen
Nachdem die beiden vorherigen Codezeilen ausgeführt wurden, wissen wir mit Sicherheit, dass wir einen Pixelpuffer und ein Modell haben. Der nächste Schritt wäre das Erstellen einer VNCoreMLRequest mit beiden.
Fügen Sie direkt unter dem vorherigen Schritt die folgenden Codezeilen in die Delegate-Methode ein:
1 |
let request = VNCoreMLRequest(model: model) { (data, error) in { |
2 |
// Your code goes here
|
3 |
}
|
Hier erstellen wir eine Konstante namens request und weisen ihr den Rückgabewert der Methode VNCoreMLRequest zu, wenn unser Modell an sie übergeben wird.
Ergebnisse abrufen und sortieren
Wir sind fast fertig! Jetzt müssen wir nur noch unsere Ergebnisse abrufen (was das Modell für unser Bild hält) und sie dann dem Benutzer anzeigen.
Fügen Sie die nächsten zwei Codezeilen in den Vervollständigungshandler Ihrer Anfrage ein:
1 |
// Checks if the data is in the correct format and assigns it to results
|
2 |
guard let results = data.results as? [VNClassificationObservation] else { return } |
3 |
// Assigns the first result (if it exists) to firstObject
|
4 |
guard let firstObject = results.first else { return } |
Wenn die Ergebnisse aus den Daten (vom Abschlusshandler der Anforderung) als Array von VNClassificationObservations verfügbar sind, erhält diese Codezeile das erste Objekt aus dem zuvor erstellten Array. Es wird dann einer Konstante namens firstObject zugewiesen. Das erste Objekt in diesem Array ist dasjenige, für das die Bilderkennungs-Engine das größte Vertrauen hat.
Anzeigen von Daten und Bildverarbeitung
Erinnern Sie sich, als wir die beiden Labels (Vertrauen und Objekt) erstellt haben? Wir werden sie jetzt verwenden, um anzuzeigen, was das Modell für das Bild hält.
Fügen Sie nach dem vorherigen Schritt die folgenden Codezeilen hinzu:
1 |
if firstObject.confidence * 100 >= 50 { |
2 |
self.objectLabel.text = firstObject.identifier.capitalized |
3 |
self.confidenceLabel.text = String(firstObject.confidence * 100) + "%" |
4 |
}
|
Die if-Anweisung stellt sicher, dass der Algorithmus mindestens 50% sicher ist, ob er das Objekt identifiziert. Dann setzen wir einfach das firstObject als Text des objectLabel, weil wir wissen, dass das Konfidenzniveau hoch genug ist. Wir zeigen nur den Prozentsatz der Sicherheit mit der Texteigenschaft von confidenceLabel an. Da firstObject.confidence als Dezimalzahl dargestellt wird, müssen wir mit 100 multiplizieren, um den Prozentsatz zu erhalten.
Als letztes müssen Sie das Bild mit dem soeben erstellten Algorithmus verarbeiten. Dazu müssen Sie die folgende Codezeile direkt eingeben, bevor Sie die delegate-Methode captureOutput(_:didOutput: from:) beenden:
1 |
try? VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:]).perform([request]) |
Schlussfolgerung
Die Konzepte, die Sie in diesem Lernprogramm gelernt haben, können auf viele Arten von Apps angewendet werden. Ich hoffe, es hat Ihnen Spaß gemacht, das Klassifizieren von Bildern mit Ihrem Telefon zu lernen. Obwohl es möglicherweise noch nicht perfekt ist, können Sie in Zukunft Ihre eigenen Modelle trainieren, um genauer zu sein.
So sollte die App aussehen, wenn sie fertig ist:



Während Sie hier sind, lesen Sie einige unserer anderen Beiträge zum maschinellen Lernen und zur Entwicklung von iOS-Apps!







