Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Erfahren Sie, wie Sie ML.NET verwenden, um Objekte in Bildern mithilfe eines ONNX-Modells zu erkennen, das im Microsoft Custom Vision-Dienst trainiert wurde.
Der Microsoft Custom Vision-Dienst ist ein KI-Dienst, der ein Modell basierend auf Bildern trainiert, die Sie hochladen. Anschließend können Sie das Modell in das ONNX-Format exportieren und in ML.NET verwenden, um Vorhersagen zu erstellen.
In diesem Tutorial erfahren Sie, wie:
- Verwenden des Custom Vision-Diensts zum Erstellen eines ONNX-Modells
- Integrieren des ONNX-Modells in die ML.NET Pipeline
- Trainieren des ML.NET Modells
- Erkennen von Stoppzeichen in Testbildern
Voraussetzungen
- Visual Studio 2022 oder höher.
- Laden Sie das Dataset von 50 Stoppzeichenbildern herunter.
- Azure-Konto. Wenn Sie kein Konto besitzen, erstellen Sie ein kostenloses Azure-Konto.
Erstellen des Modells
Erstellen des Custom Vision-Projekts
Melden Sie sich beim Microsoft Custom Vision-Dienst an, und wählen Sie "Neues Projekt" aus.
Füllen Sie im Dialogfeld "Neues Projekt " die folgenden erforderlichen Elemente aus:
- Legen Sie den Namen des Projekts "Custom Vision " als StopSignDetection fest.
- Wählen Sie die Ressource aus, die Sie verwenden möchten. Dies ist eine Azure-Ressource, die für das Projekt "Custom Vision" erstellt wird. Wenn keines aufgeführt ist, kann man eines erstellen, indem man den Link "Neues Erstellen" auswählt.
- Legen Sie den Projekttyp als Objekterkennung fest.
- Legen Sie die Klassifizierungstypen als "Multiclass " fest, da pro Bild eine Klasse vorhanden ist.
- Legen Sie die Domäne als Allgemein (kompakt) [S1] fest. Mit der kompakten Domäne können Sie das ONNX-Modell herunterladen.
- Wählen Sie für Exportfunktionendie Standardplattformen aus, um den Export des ONNX-Modells zuzulassen.
Nachdem die obigen Felder ausgefüllt wurden, wählen Sie "Projekt erstellen" aus.
Hinzufügen von Bildern
- Wählen Sie mit dem erstellten Projekt "Bilder hinzufügen" aus, um mit dem Hinzufügen von Bildern für das Modell zu beginnen, auf dem trainiert werden soll. Wählen Sie die von Ihnen heruntergeladenen Stoppzeichenbilder aus.
- Wählen Sie das erste angezeigte Bild aus. Sie können Objekte in dem Bild auswählen, das vom Modell erkannt werden soll. Wählen Sie das Stoppschild im Bild aus. Ein Popup zeigt das Tag als Stoppzeichen an und legt es fest.
- Wiederholen Sie diesen Vorgang für alle verbleibenden Bilder. Einige Bilder weisen mehr als ein Stoppzeichen auf. Stellen Sie daher sicher, dass Sie alle Bilder markieren, die sich in den Bildern befinden.
Trainieren des Modells
Mit hochgeladenen und markierten Bildern kann das Modell jetzt trainiert werden. Wählen Sie Trainieren aus.
Ein Popup zeigt an, welche Art von Schulung verwendet werden soll. Wählen Sie "Schnelle Schulung" und dann " Trainieren" aus.
Herunterladen des ONNX-Modells
Klicken Sie nach Abschluss der Schulung auf die Schaltfläche " Exportieren ". Wenn das Popup angezeigt wird, wählen Sie ONNX aus, um das ONNX-Modell herunterzuladen.
ONNX-Modell prüfen
Entzippen Sie die heruntergeladene ONNX-Datei. Der Ordner enthält mehrere Dateien, aber die beiden, die Sie in diesem Lernprogramm verwenden werden, sind:
- labels.txt, bei der es sich um eine Textdatei handelt, die die Bezeichnungen enthält, die im Benutzerdefinierten Vision-Dienst definiert wurden.
- model.onnx, bei dem es sich um das ONNX-Modell handelt, mit dem Sie Vorhersagen in ML.NET erstellen können.
Um die ML.NET Pipeline zu erstellen, benötigen Sie die Namen der Eingabe- und Ausgabespaltennamen. Um diese Informationen zu erhalten, verwenden Sie Netron, eine Web - und Desktop-App , die ONNX-Modelle analysieren und ihre Architektur anzeigen kann.
Wenn Sie die Web- oder Desktop-App von Netron verwenden, öffnen Sie das ONNX-Modell in der App. Nach dem Öffnen wird ein Diagramm angezeigt. Dieses Diagramm informiert Sie über einige Dinge, die Sie zum Erstellen der ML.NET Pipeline für Vorhersagen benötigen.
Eingabespaltenname – Der Eingabespaltenname , der beim Anwenden des ONNX-Modells in ML.NET erforderlich ist.
Ausgabespaltenname – Der Ausgabespaltenname, der beim Anwenden des ONNX-Modells in ML.NET erforderlich ist.
Bildgröße – Die beim Ändern der Größe von Bildern in der ML.NET-Pipeline erforderliche Größe.
Erstellen eines C#-Konsolenprojekts
Erstellen Sie in Visual Studio eine C#-Konsolenanwendung namens "StopSignDetection". Wählen Sie .NET 8 als Zielframework aus.
Installieren Sie die folgenden NuGet-Pakete für das Projekt:
- Microsoft.ML
- Microsoft.ML.ImageAnalytics
- Microsoft.Onnx.Transformer
Hinweis
In diesem Beispiel wird die neueste stabile Version der erwähnten NuGet-Pakete verwendet, sofern nichts anderes angegeben ist.
Verweisen auf das ONNX-Modell
Suchen Sie die beiden Dateien aus dem ONNX-Modell (labels.txt und model.onnx) im Visual Studio-Projektmappen-Explorer. Klicken Sie mit der rechten Maustaste darauf und legen Sie im Fenster "Eigenschaften" die Option Auf Ausgabeverzeichnis kopieren mit der Einstellung Kopieren, wenn neuer fest.
Erstellen von Eingabe- und Vorhersageklassen
Fügen Sie ihrem Projekt eine neue Klasse hinzu, und nennen Sie sie
StopSignInput. Fügen Sie dann der Klasse die folgende Struktur hinzu:public struct ImageSettings { public const int imageHeight = 320; public const int imageWidth = 320; }Fügen Sie als Nächstes der Klasse die folgende Eigenschaft hinzu.
public class StopSignInput { [ImageType(ImageSettings.imageHeight, ImageSettings.imageWidth)] public Bitmap Image { get; set; } }Die
ImageEigenschaft enthält die Bitmap des Bilds, das für die Vorhersage verwendet wird. DasImageTypeAttribut teilt ML.NET mit, dass es sich bei der Eigenschaft um ein Bild mit abmessungen 320 und 320 handelt, das mithilfe von Netron bestimmt wurde.Fügen Sie Ihrem Projekt eine weitere Klasse hinzu, und nennen Sie sie
StopSignPrediction. Fügen Sie dann der Klasse die folgenden Eigenschaften hinzu.public class StopSignPrediction { [ColumnName("detected_classes")] public long[] PredictedLabels { get; set; } [ColumnName("detected_boxes")] public float[] BoundingBoxes { get; set; } [ColumnName("detected_scores")] public float[] Scores { get; set; } }Die
PredictedLabelsEigenschaft enthält die Vorhersagen von Bezeichnungen für jedes erkannte Objekt. Der Typ ist ein Float-Array, sodass jedes Element im Array die Vorhersage jeder Beschriftung ist. DasColumnNameAttribut teilt ML.NET mit, dass diese Spalte im Modell der angegebene Name istdetected_classes.Die
BoundingBoxesEigenschaft enthält die Begrenzungsfelder für jedes erkannte Objekt. Der Typ ist ein Float-Array, und jedes erkannte Objekt enthält vier Elemente im Array für den begrenzenden Rahmen. DasColumnNameAttribut teilt ML.NET mit, dass diese Spalte im Modell der angegebene Name istdetected_boxes.Die
ScoresEigenschaft enthält die Konfidenzbewertungen der einzelnen vorhergesagten Objekte und deren Beschriftung. Der Typ ist ein Float-Array, sodass jedes Element im Array die Konfidenzbewertung jeder Bezeichnung ist. DasColumnNameAttribut teilt ML.NET mit, dass diese Spalte im Modell der angegebene Name istdetected_scores.
Verwenden des Modells zum Erstellen von Vorhersagen
Hinzufügen von using-Direktiven
Fügen Sie in der datei Program.cs die folgenden using Direktiven am Anfang der Datei hinzu.
using Microsoft.ML;
using Microsoft.ML.Transforms.Image;
using System.Drawing;
using WeatherRecognition;
Objekte erstellen
Erstellen Sie das
MLContextObjekt.var context = new MLContext();Erstellen Sie eine
IDataViewmit einer neuen leerenStopSignInputListe.var data = context.Data.LoadFromEnumerable(new List<StopSignInput>());Speichern Sie aus Gründen der Konsistenz die vorhergesagten Bilder im Assemblypfad.
var root = new FileInfo(typeof(Program).Assembly.Location); var assemblyFolderPath = root.Directory.FullName;
Erstellen der Pipeline
Wenn die leere IDataView erstellt ist, kann die Pipeline gebaut werden, um Vorhersagen für beliebige neue Bilder zu treffen. Die Pipeline besteht aus mehreren Schritten:
Ändern Sie die Größe der eingehenden Bilder.
Das Bild, das für die Vorhersage an das Modell gesendet wird, befindet sich häufig in einem anderen Seitenverhältnis zu den Bildern, die auf dem Modell trainiert wurden. Um das Bild für genaue Vorhersagen konsistent zu halten, ändern Sie die Größe des Bilds auf 320 x 320. Verwenden Sie dazu die
ResizeImagesMethode, und legen Sie denimageColumnNameNamen derStopSignInput.ImageEigenschaft fest.var pipeline = context.Transforms.ResizeImages(resizing: ImageResizingEstimator.ResizingKind.Fill, outputColumnName: "image_tensor", imageWidth: ImageSettings.imageWidth, imageHeight: ImageSettings.imageHeight, inputColumnName: nameof(StopSignInput.Image))Extrahieren Sie die Pixel des Bilds.
Nachdem die Größe des Bilds geändert wurde, müssen Sie die Pixel des Bilds extrahieren. Fügen Sie die
ExtractPixelsMethode zu Ihrer Pipeline hinzu und geben Sie den Namen der Spalte an, um die Pixel über denoutputColumnNameParameter auszugeben..Append(context.Transforms.ExtractPixels(outputColumnName: "image_tensor"))Wenden Sie das ONNX-Modell auf das Bild an, um eine Vorhersage zu erstellen. Dies erfordert einige Parameter:
- modelFile – Der Pfad zur ONNX-Modelldatei
- outputColumnNames – Ein Zeichenfolgenarray mit den Namen aller Ausgabespaltennamen, die beim Analysieren des ONNX-Modells in Netron gefunden werden können.
- inputColumnNames – Ein Zeichenfolgenarray mit den Namen aller Eingabespaltennamen, das auch bei der Analyse des ONNX-Modells in Netron gefunden werden kann.
.Append(context.Transforms.ApplyOnnxModel(outputColumnNames: new string[] { "detected_boxes", "detected_scores", "detected_classes" }, inputColumnNames: new string[] { "image_tensor" }, modelFile: "./Model/model.onnx"));
Anpassen des Modells
Nachdem Sie eine Pipeline definiert haben, können Sie sie verwenden, um das ML.NET Modell zu erstellen. Verwenden Sie die Fit Methode für die Pipeline, und übergeben Sie die leere IDataView.
var model = pipeline.Fit(data);
Verwenden Sie als Nächstes zum Erstellen von Vorhersagen das Modell, um ein Vorhersagemodul zu erstellen. Dies ist eine generische Methode, daher werden die zuvor erstellten Klassen StopSignInput und StopSignPrediction übergeben.
var predictionEngine = context.Model.CreatePredictionEngine<StopSignInput, StopSignPrediction>(model);
Extrahieren der Etiketten
Um die Ausgabe des Modells den Etiketten zuzuordnen, müssen Sie die etiketten extrahieren, die von Custom Vision bereitgestellt werden. Diese Bezeichnungen befinden sich in der labels.txt Datei, die in der ZIP-Datei mit dem ONNX-Modell enthalten war.
Rufen Sie die ReadAllLines Methode auf, um alle Bezeichnungen zu lesen, die die Datei bilden.
var labels = File.ReadAllLines("./model/labels.txt");
Vorhersagen für ein Testbild
Jetzt können Sie das Modell verwenden, um neue Bilder vorherzusagen. Im Projekt gibt es einen Testordner , den Sie zum Erstellen von Vorhersagen verwenden können. Dieser Ordner enthält zwei zufällige Bilder mit einem Stoppschild darin von Unsplash. Ein Bild weist ein Stoppzeichen auf, während das andere zwei Stoppzeichen aufweist. Verwenden Sie die GetFiles Methode, um die Dateipfade der Bilder im Verzeichnis zu lesen.
var testFiles = Directory.GetFiles("./test");
Durchlaufen Sie die Dateipfade, um eine Vorhersage mit dem Modell zu erstellen und das Ergebnis auszugeben.
Erstellen Sie eine
foreachSchleife, um die Testbilder zu durchlaufen.Bitmap testImage; foreach (var image in testFiles) { }Generieren Sie in der
foreachSchleife den vorhergesagten Bildnamen basierend auf dem Namen des ursprünglichen Testbilds.var predictedImage = $"{Path.GetFileName(image)}-predicted.jpg";Erstellen Sie auch in der
foreachSchleife einFileStreamBild, und konvertieren Sie es in einBitmap.using (var stream = new FileStream(image, FileMode.Open)) { testImage = (Bitmap)Image.FromStream(stream); }Rufen Sie auch in der
foreachSchleife diePredictMethode für das Vorhersagemodul auf.var prediction = predictionEngine.Predict(new StopSignInput { Image = testImage });Mit der Vorhersage können Sie die Begrenzungsrahmen abrufen. Verwenden Sie die Chunk Methode, um zu bestimmen, wie viele Objekte das Modell erkannt hat. Verwenden Sie dazu die Anzahl der vorhergesagten Begrenzungsfelder, und dividieren Sie dies durch die Anzahl der vorhergesagten Bezeichnungen. Wenn Sie beispielsweise drei Objekte in einem Bild erkannt haben, wären 12 Elemente im
BoundingBoxesArray und drei Beschriftungen vorhergesagt. DieChunkMethode liefert dann drei Arrays von vier zurück, um die Begrenzungsrahmen für jedes Objekt darzustellen.var boundingBoxes = prediction.BoundingBoxes.Chunk(prediction.BoundingBoxes.Count() / prediction.PredictedLabels.Count());Erfassen Sie als Nächstes die ursprüngliche Breite und Höhe der Bilder, die für die Vorhersage verwendet werden.
var originalWidth = testImage.Width; var originalHeight = testImage.Height;Berechnen Sie, wo im Bild die Boxen gezeichnet werden sollen. Erstellen Sie dazu eine
forSchleife basierend auf der Anzahl der umgebenden Kästchenblöcke.for (int i = 0; i < boundingBoxes.Count(); i++) { }Berechnen Sie in der
forSchleife die Position der X- und Y-Koordinaten sowie die Breite und Höhe der Box, um auf dem Bild zu zeichnen. Als Erstes müssen Sie den Satz von Begrenzungsrahmen unter Verwendung derElementAt-Methode abrufen.var boundingBox = boundingBoxes.ElementAt(i);Mit dem aktuellen Begrenzungsrahmen können Sie jetzt berechnen, wo der Rahmen gezeichnet werden soll. Verwenden Sie die ursprüngliche Bildbreite für die ersten und dritten Elemente des Begrenzungsrahmens und die ursprüngliche Bildhöhe für die zweiten und vierten Elemente.
var left = boundingBox[0] * originalWidth; var top = boundingBox[1] * originalHeight; var right = boundingBox[2] * originalWidth; var bottom = boundingBox[3] * originalHeight;Berechnen Sie die Breite und die Höhe des Rahmens, um das erkannte Objekt innerhalb des Bilds zu umrahmen. Die x- und y-Elemente sind die
leftundtopVariablen aus der vorherigen Berechnung. Verwenden Sie dieMath.AbsMethode, um den absoluten Wert aus den Berechnungen für Breite und Höhe abzurufen, falls dies negativ ist.var x = left; var y = top; var width = Math.Abs(right - left); var height = Math.Abs(top - bottom);Rufen Sie als Nächstes das vorhergesagte Label aus dem Array von Labels ab.
var label = labels[prediction.PredictedLabels[i]];Erstellen Sie eine Grafik basierend auf dem Testbild mithilfe der
Graphics.FromImageMethode.using var graphics = Graphics.FromImage(testImage);Zeichnen Sie auf dem Bild mithilfe der Informationen zum Begrenzungsrahmen. Zeichnen Sie zuerst das Rechteck um die erkannten Objekte mithilfe der Methode
DrawRectangle, die einPenObjekt verwendet, um die Farbe und Breite des Rechtecks zu bestimmen, und übergeben Sie die Variablenx,y,widthundheight.graphics.DrawRectangle(new Pen(Color.NavajoWhite, 8), x, y, width, height);Zeigen Sie dann die vorhergesagte Beschriftung innerhalb des Feldes mit der
DrawString-Methode an, die die Zeichenfolge druckt, und einemFont-Objekt, das bestimmt, wie und wo die Zeichenfolge gezeichnet werden soll.graphics.DrawString(label, new Font(FontFamily.Families[0], 18f), Brushes.NavajoWhite, x + 5, y + 5);Überprüfen Sie nach der
forSchleife, ob die vorhergesagte Datei bereits vorhanden ist. Wenn dies der Fall ist, löschen Sie es. Speichern Sie sie dann im definierten Ausgabepfad.if (File.Exists(predictedImage)) { File.Delete(predictedImage); } testImage.Save(Path.Combine(assemblyFolderPath, predictedImage));
Nächste Schritte
Probieren Sie eines der anderen Lernprogramme zur Bildklassifizierung aus: