Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Узнайте, как использовать ML.NET для обнаружения объектов в изображениях с помощью модели ONNX, обученной в службе Пользовательского визуального распознавания Майкрософт.
Служба Пользовательского визуального распознавания Майкрософт — это служба искусственного интеллекта, которая обучает модель на основе отправленных изображений. Затем можно экспортировать модель в формат ONNX и использовать ее в ML.NET для прогнозирования.
В этом руководстве вы узнаете, как:
- Создание модели ONNX с помощью службы пользовательского визуального распознавания
- Включение модели ONNX в конвейер ML.NET
- Обучение модели ML.NET
- Обнаружение признаков остановки в тестовых образах
Предпосылки
- Visual Studio 2022 или более поздней версии.
- Скачайте набор данных из 50 образов стоп-подписей.
- Учетная запись Azure. Если у вас нет учетной записи Azure, создайте бесплатную учетную запись Azure.
Создание модели
Создание проекта в службе "Пользовательское визуальное распознавание"
Войдите в службу Пользовательского визуального распознавания Майкрософт и выберите новый проект.
В диалоговом окне "Новый проект" заполните следующие обязательные элементы:
- Задайте имя проекта пользовательского визуального распознавания как StopSignDetection.
- Выберите ресурс , который вы будете использовать. Это ресурс Azure, который будет создан для проекта Пользовательского визуального распознавания. Если нет в списке, его можно создать, выбрав ссылку "Создать новую ".
- Задайте тип проекта как обнаружение объектов.
- Задайте типы классификации как мультикласс , так как на изображение будет один класс.
- Задайте домен как общий (компактный) [S1]. Компактный домен позволяет скачать модель ONNX.
- Для возможностей экспорта выберите базовые платформы, чтобы разрешить экспорт модели ONNX.
После заполнения указанных выше полей нажмите кнопку "Создать проект".
Добавление изображений
- После создания проекта нажмите кнопку "Добавить изображения ", чтобы начать добавление изображений для модели для обучения. Выберите загруженные изображения дорожных знаков 'Стоп'.
- Выберите первое изображение, которое отображается. Вы можете выбрать объекты на изображении, которое требуется обнаружить модели. Выберите знак остановки на изображении. Всплывающее окно отображает и задает тег как знак остановки.
- Повторите действие для всех оставшихся изображений. Некоторые изображения имеют более одного знака остановки, поэтому обязательно пометьте все, что находятся в изображениях.
Обучение модели
После загрузки и маркировки изображений модель можно обучить. Выберите "Обучение".
Появляется всплывающее окно с вопросом, какой тип обучения использовать. Выберите быстрое обучение и нажмите кнопку "Обучение".
Скачивание модели ONNX
После завершения обучения нажмите кнопку "Экспорт ". При отображении всплывающего окна выберите ONNX, чтобы скачать модель ONNX .
Проверка модели ONNX
Распакуйте скачанный ONNX-файл. Папка содержит несколько файлов, но они используются в этом руководстве:
- labels.txt, который представляет собой текстовый файл, содержащий метки, определенные в службе пользовательского визуального распознавания.
- model.onnx, которая является моделью ONNX, которая будет использоваться для прогнозирования в ML.NET.
Чтобы создать конвейер ML.NET, вам потребуется имена входных и выходных столбцов. Чтобы получить эти сведения, используйте Netron, веб-приложение и классическое приложение, которое может анализировать модели ONNX и показывать их архитектуру.
При использовании веб-приложения или классического приложения Netron откройте модель ONNX в приложении. После открытия отображается граф. На этом графе показано, что вам потребуется создать конвейер ML.NET для прогнозирования.
Имя входного столбца — имя входного столбца , необходимое при применении модели ONNX в ML.NET.
Имя выходного столбца — имя выходного столбца , необходимое при применении модели ONNX в ML.NET.
Размер изображения — размер, необходимый при изменении размера изображений в конвейере ML.NET.
Создание консольного проекта C#
В Visual Studio создайте консольное приложение C# с именем StopSignDetection. Выберите .NET 8 в качестве целевой платформы.
Установите следующие пакеты NuGet для проекта:
- Microsoft.ML
- Microsoft.ML.ImageAnalytics
- Microsoft.Onnx.Transformer
Замечание
В этом примере используется последняя стабильная версия упомянутых пакетов NuGet, если не указано иное.
Ссылка на модель ONNX
Найдите два файла из модели ONNX (labels.txt и model.onnx) в обозревателе решений Visual Studio. Щелкните их правой кнопкой мыши, и в окне "Свойства" установите параметр Копировать в выходной каталог на значение Копировать при изменении.
Создание входных и прогнозирующих классов
Добавьте новый класс в проект и назовите его
StopSignInput. Затем добавьте в класс следующую структуру:public struct ImageSettings { public const int imageHeight = 320; public const int imageWidth = 320; }Затем добавьте в класс следующее свойство.
public class StopSignInput { [ImageType(ImageSettings.imageHeight, ImageSettings.imageWidth)] public Bitmap Image { get; set; } }Свойство
Imageсодержит растровое изображение изображения, используемого для прогнозирования. АтрибутImageTypeсообщает ML.NET, что свойство является изображением с размерами 320 на 320, определённое с помощью Netron.Добавьте в проект другой класс и назовите его
StopSignPrediction. Затем добавьте в класс следующие свойства.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; } }Свойство
PredictedLabelsсодержит прогнозы меток для каждого обнаруженного объекта. Тип - это массив типа float, поэтому каждый элемент в массиве является предсказанием для каждой метки. АтрибутColumnNameсообщает ML.NET, что этот столбец в модели является именем, указанным какdetected_classes.Свойство
BoundingBoxesсодержит ограничивающие прямоугольники для каждого обнаруженного объекта. Тип представляет собой массив чисел с плавающей запятой, и каждый обнаруженный объект содержит четыре элемента в массиве для ограничивающей рамки. АтрибутColumnNameсообщает ML.NET, что этот столбец в модели является именем, указанным какdetected_boxes.Свойство
Scoresсодержит оценки достоверности каждого прогнозируемого объекта и его метки. Тип представляет собой массив с плавающей запятой, поэтому каждый элемент в массиве — это оценка достоверности каждой метки. АтрибутColumnNameсообщает ML.NET, что этот столбец в модели является указанным именем.detected_scores
Использование модели для прогнозирования
Добавьте директивы using.
В файле Program.cs добавьте следующие using директивы в начало файла.
using Microsoft.ML;
using Microsoft.ML.Transforms.Image;
using System.Drawing;
using WeatherRecognition;
Создание объектов
MLContextСоздайте объект.var context = new MLContext();Создайте новый пустой
IDataViewStopSignInputсписок.var data = context.Data.LoadFromEnumerable(new List<StopSignInput>());Для согласованности сохраните прогнозируемые образы в пути сборки.
var root = new FileInfo(typeof(Program).Assembly.Location); var assemblyFolderPath = root.Directory.FullName;
Создание конвейера
С помощью пустого IDataView созданного конвейера можно создать для прогнозирования любых новых образов. Конвейер состоит из нескольких шагов:
Измените размер входящих изображений.
Изображение, отправляемое в модель для прогнозирования, часто будет в другом пропорциональном отношении к изображениям, которые были использованы для обучения модели. Чтобы обеспечить согласованность изображения для точных прогнозов, измените размер изображения на 320x320. Для этого используйте
ResizeImagesметод и задайтеimageColumnNameимяStopSignInput.Imageсвойства.var pipeline = context.Transforms.ResizeImages(resizing: ImageResizingEstimator.ResizingKind.Fill, outputColumnName: "image_tensor", imageWidth: ImageSettings.imageWidth, imageHeight: ImageSettings.imageHeight, inputColumnName: nameof(StopSignInput.Image))Извлеките пиксели изображения.
После изменения размера изображения необходимо извлечь пиксели изображения. Добавьте метод в
ExtractPixelsконвейер и укажите имя столбца, чтобы вывести пиксели на использованиеoutputColumnNameпараметра..Append(context.Transforms.ExtractPixels(outputColumnName: "image_tensor"))Примените модель ONNX к изображению, чтобы сделать прогноз. Для этого требуется несколько параметров:
- modelFile — путь к файлу модели ONNX
- outputColumnNames — массив строк, содержащий имена всех имен выходных столбцов, которые можно найти при анализе модели ONNX в Netron.
- inputColumnNames — строковый массив, содержащий имена всех входных столбцов, которые также можно найти при анализе модели ONNX в Netron.
.Append(context.Transforms.ApplyOnnxModel(outputColumnNames: new string[] { "detected_boxes", "detected_scores", "detected_classes" }, inputColumnNames: new string[] { "image_tensor" }, modelFile: "./Model/model.onnx"));
Соответствие модели
Теперь, когда вы определили конвейер, его можно использовать для сборки модели ML.NET.
Fit Используйте метод в конвейере и передайте пустоеIDataView.
var model = pipeline.Fit(data);
Затем, чтобы сделать прогнозы, используйте модель для создания подсистемы прогнозирования. Это универсальный метод, поэтому он принимает классы StopSignInput и StopSignPrediction, которые были созданы ранее.
var predictionEngine = context.Model.CreatePredictionEngine<StopSignInput, StopSignPrediction>(model);
Извлечение меток
Чтобы сопоставить выходные данные модели с метками, необходимо извлечь метки, предоставляемые Custom Vision. Эти метки находятся в labels.txt файле, который был включен в ZIP-файл с моделью ONNX.
ReadAllLines Вызовите метод для чтения всех меток в файле.
var labels = File.ReadAllLines("./model/labels.txt");
Прогнозирование на тестовом изображении
Теперь модель можно использовать для прогнозирования на новых изображениях. В проекте есть тестовая папка, которую можно использовать для прогнозирования. Эта папка содержит два случайных изображения со знаком остановки на нём из Unsplash. Один образ имеет один знак остановки, а другой имеет два знака остановки.
GetFiles Используйте метод для чтения путей к файлам изображений в каталоге.
var testFiles = Directory.GetFiles("./test");
Прокрутите пути к файлам, чтобы сделать прогноз с помощью модели и вывести результат.
foreachСоздайте цикл для циклического прохождения тестовых образов.Bitmap testImage; foreach (var image in testFiles) { }В цикле
foreachсоздайте прогнозируемое имя образа на основе имени исходного тестового образа.var predictedImage = $"{Path.GetFileName(image)}-predicted.jpg";Кроме того, в цикле
foreachсоздайтеFileStreamизображения и преобразуйте его вBitmap.using (var stream = new FileStream(image, FileMode.Open)) { testImage = (Bitmap)Image.FromStream(stream); }Кроме того, в цикле
foreachвызовитеPredictметод в подсистеме прогнозирования.var prediction = predictionEngine.Predict(new StopSignInput { Image = testImage });С помощью прогноза можно получить ограничивающие прямоугольники. Chunk Используйте метод, чтобы определить, сколько объектов обнаружена модель. Это можно сделать, приняв количество прогнозируемых ограничивающих прямоугольников и разделив это значение на число прогнозируемых меток. Например, если в изображении обнаружены три объекта, в
BoundingBoxesмассиве было бы 12 элементов, а прогнозируются три метки. ЗатемChunkметод даст вам три массива из четырех, чтобы представлять ограничивающие прямоугольники для каждого объекта.var boundingBoxes = prediction.BoundingBoxes.Chunk(prediction.BoundingBoxes.Count() / prediction.PredictedLabels.Count());Затем зафиксировать исходную ширину и высоту изображений, используемых для прогнозирования.
var originalWidth = testImage.Width; var originalHeight = testImage.Height;Вычислите, где на изображении нужно нарисовать коробки. Для этого создайте
forцикл на основе количества ограничивающих прямоугольников.for (int i = 0; i < boundingBoxes.Count(); i++) { }forВ цикле вычислите положение координат x и y, а также ширину и высоту поля, нарисуемого на изображении. Первое, что необходимо сделать, — это получить набор ограничивающих прямоугольников с помощью методаElementAt.var boundingBox = boundingBoxes.ElementAt(i);С помощью текущего ограничивающего прямоугольника теперь можно вычислить место для рисования поля. Используйте исходные размеры изображения: ширину для первых и третьих элементов ограничительной рамки и высоту для второго и четвертого элементов.
var left = boundingBox[0] * originalWidth; var top = boundingBox[1] * originalHeight; var right = boundingBox[2] * originalWidth; var bottom = boundingBox[3] * originalHeight;Вычислите ширину и высоту поля для рисования вокруг обнаруженного объекта в изображении. Элементы x и y — это
lefttopпеременные из предыдущего вычисления.Math.AbsИспользуйте метод, чтобы получить абсолютное значение от вычислений ширины и высоты, если это отрицательно.var x = left; var y = top; var width = Math.Abs(right - left); var height = Math.Abs(top - bottom);Затем получите предсказанную метку из массива меток.
var label = labels[prediction.PredictedLabels[i]];Создайте рисунок на основе тестового
Graphics.FromImageобраза с помощью метода.using var graphics = Graphics.FromImage(testImage);Нарисуйте изображение с помощью сведений об ограничивающем поле. Во-первых, нарисуйте прямоугольник вокруг обнаруженных объектов, используя метод
DrawRectangle, который принимает объектPen, чтобы определить цвет и ширину прямоугольника, и передайте в него переменныеx,y,widthиheight.graphics.DrawRectangle(new Pen(Color.NavajoWhite, 8), x, y, width, height);Затем покажите прогнозируемую метку внутри рамки с помощью метода
DrawString, который принимает строку для печати и объектFont, чтобы определить, как нарисовать строку и где её разместить.graphics.DrawString(label, new Font(FontFamily.Families[0], 18f), Brushes.NavajoWhite, x + 5, y + 5);После цикла проверьте, существует ли прогнозируемый
forфайл. Если да, удалите это. Затем сохраните его в определенный выходной путь.if (File.Exists(predictedImage)) { File.Delete(predictedImage); } testImage.Save(Path.Combine(assemblyFolderPath, predictedImage));
Дальнейшие шаги
Ознакомьтесь с одним из других руководств по классификации изображений: