Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Aprenda a usar ML.NET para detectar objetos en imágenes mediante un modelo ONNX entrenado en el servicio Microsoft Custom Vision.
El servicio Microsoft Custom Vision es un servicio de IA que entrena un modelo basado en imágenes que se cargan. A continuación, puede exportar el modelo al formato ONNX y usarlo en ML.NET para realizar predicciones.
En este tutorial, aprenderá a:
- Uso del servicio Custom Vision para crear un modelo ONNX
- Incorporación del modelo ONNX a la canalización de ML.NET
- Entrenamiento del modelo de ML.NET
- Detectar señales de stop en imágenes de prueba
Prerrequisitos
- Visual Studio 2022 o posterior.
- Descargue el conjunto de datos de 50 imágenes de señales de stop.
- Cuenta de Azure. Si no tiene una, cree una cuenta gratuita de Azure.
Creación del modelo
Creación del proyecto de Custom Vision
Inicie sesión en el servicio Microsoft Custom Vision y seleccione Nuevo proyecto.
En el cuadro de diálogo Nuevo proyecto , rellene los siguientes elementos necesarios:
- Establezca el nombre del proyecto de Custom Vision como StopSignDetection.
- Seleccione el recurso que usará. Se trata de un recurso de Azure que se creará para el proyecto de Custom Vision. Si no aparece ninguno, se puede crear seleccionando el vínculo Crear nuevo .
- Establezca el tipo de proyecto como Detección de objetos.
- Establezca los tipos de clasificación como multiclase , ya que habrá una clase por imagen.
- Establezca el dominio como General (compacto) [S1]. El dominio compacto le permite descargar el modelo ONNX.
- En Funcionalidades de exportación, seleccione Plataformas básicas para permitir la exportación del modelo ONNX.
Una vez rellenados los campos anteriores, seleccione Crear proyecto.
Agregar imágenes
- Con el proyecto creado, elija Agregar imágenes para empezar a agregar imágenes para que el modelo se entrene. Seleccione las imágenes de señal de stop que descargó.
- Seleccione la primera imagen que se muestra. Puede seleccionar objetos en la imagen que desea que el modelo detecte. Seleccione la señal de alto en la imagen. Una ventana emergente se muestra y establece la etiqueta como stop-sign.
- Repita esta operación para todas las imágenes restantes. Algunas imágenes tienen más de una señal de stop, por lo tanto, asegúrese de marcar todas las señales que están en las imágenes.
Entrenamiento del modelo
Con las imágenes cargadas y etiquetadas, el modelo ahora se puede entrenar. Seleccione Entrenar.
Se muestra una ventana emergente preguntando qué tipo de entrenamiento usar. Elija Entrenamiento rápido y, a continuación, seleccione Entrenar.
Descarga del modelo ONNX
Una vez completado el entrenamiento, haga clic en el botón Exportar . Cuando se muestre el elemento emergente, seleccione ONNX para descargar el modelo ONNX.
Inspección del modelo ONNX
Descomprima el archivo ONNX descargado. La carpeta contiene varios archivos, pero los dos que usará en este tutorial son:
- labels.txt, que es un archivo de texto que contiene las etiquetas definidas en el servicio Custom Vision.
- model.onnx, que es el modelo de ONNX que usará para hacer predicciones en ML.NET.
Para compilar la canalización de ML.NET, necesitará los nombres de las columnas de entrada y salida. Para obtener esta información, use Netron, una aplicación web y de escritorio que pueda analizar modelos ONNX y mostrar su arquitectura.
Al usar la aplicación web o de escritorio de Netron, abra el modelo ONNX en la aplicación. Una vez que se abre, muestra un gráfico. Este gráfico le informa sobre algunas cosas que necesitará para construir la canalización de ML.NET para las predicciones.
Nombre de columna de entrada: el nombre de columna de entrada necesario al aplicar el modelo ONNX en ML.NET.
Nombre de columna de salida: el nombre de columna de salida necesario al aplicar el modelo ONNX en ML.NET.
Tamaño de imagen - El tamaño que se requiere al redimensionar las imágenes en la canalización de ML.NET.
Creación de un proyecto de consola de C#
En Visual Studio, cree una aplicación de consola de C# denominada "StopSignDetection". Elija .NET 8 como marco de destino.
Instale los siguientes paquetes NuGet para el proyecto:
- Microsoft.ML
- Microsoft.ML.ImageAnalytics
- Microsoft.Onnx.Transformer
Nota:
En este ejemplo se usa la versión estable más reciente de los paquetes NuGet mencionados a menos que se indique lo contrario.
Referencia al modelo ONNX
Busque los dos archivos del modelo ONNX (labels.txt y model.onnx) en el Explorador de soluciones de Visual Studio. Haga clic con el botón derecho en ellos y, en la ventana Propiedades, establezca Copiar en el directorio de salida en Copiar si es más reciente.
Creación de clases de entrada y predicción
Agregue una nueva clase al proyecto y asígnele
StopSignInputel nombre . A continuación, agregue la siguiente estructura a la clase :public struct ImageSettings { public const int imageHeight = 320; public const int imageWidth = 320; }A continuación, agregue la siguiente propiedad a la clase .
public class StopSignInput { [ImageType(ImageSettings.imageHeight, ImageSettings.imageWidth)] public Bitmap Image { get; set; } }La
Imagepropiedad contiene el mapa de bits de la imagen utilizada para la predicción. ElImageTypeatributo indica ML.NET que la propiedad es una imagen con dimensiones de 320 y 320, que se determinó mediante Netron.Agregue otra clase al proyecto y asígnele
StopSignPredictionel nombre . A continuación, agregue las siguientes propiedades a la clase .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; } }La
PredictedLabelspropiedad contiene las predicciones de etiquetas para cada objeto detectado. El tipo es un arreglo de números flotantes, por lo que cada elemento del arreglo predice cada etiqueta. ElColumnNameatributo indica ML.NET que esta columna del modelo es el nombre especificado, que esdetected_classes.La
BoundingBoxespropiedad contiene los cuadros de límite para cada objeto detectado. El tipo es un arreglo de flotantes y cada objeto detectado viene con cuatro elementos en el arreglo para la caja delimitadora. ElColumnNameatributo indica ML.NET que esta columna del modelo es el nombre especificado, que esdetected_boxes.La
Scorespropiedad contiene las puntuaciones de confianza de cada objeto previsto y su etiqueta. El tipo es una matriz float, por lo que cada elemento de la matriz es la puntuación de confianza de cada etiqueta. ElColumnNameatributo indica ML.NET que esta columna del modelo es el nombre especificado, que esdetected_scores.
Uso del modelo para realizar predicciones
Adición de directivas using
En el archivo Program.cs , agregue las siguientes using directivas a la parte superior del archivo.
using Microsoft.ML;
using Microsoft.ML.Transforms.Image;
using System.Drawing;
using WeatherRecognition;
Crear objetos
Cree el
MLContextobjeto .var context = new MLContext();Cree un
IDataViewcon una nueva lista vacíaStopSignInput.var data = context.Data.LoadFromEnumerable(new List<StopSignInput>());Para mantener la coherencia, guarde las imágenes predichas en la ruta de acceso del ensamblado.
var root = new FileInfo(typeof(Program).Assembly.Location); var assemblyFolderPath = root.Directory.FullName;
Creación de la canalización
Con el objeto IDataView vacío creado, la canalización se puede construir para realizar las predicciones de cualquier imagen nueva. La canalización consta de varios pasos:
Cambie el tamaño de las imágenes entrantes.
La imagen que se envía al modelo para la predicción suele tener una relación de aspecto diferente a las imágenes con las que se entrenó el modelo. Para mantener la imagen coherente con las predicciones precisas, cambie el tamaño de la imagen a 320x320. Para ello, use el
ResizeImagesmétodo y establezca comoimageColumnNamenombre de laStopSignInput.Imagepropiedad .var pipeline = context.Transforms.ResizeImages(resizing: ImageResizingEstimator.ResizingKind.Fill, outputColumnName: "image_tensor", imageWidth: ImageSettings.imageWidth, imageHeight: ImageSettings.imageHeight, inputColumnName: nameof(StopSignInput.Image))Extraiga los píxeles de la imagen.
Una vez que se ha cambiado el tamaño de la imagen, debe extraer los píxeles de la imagen. Aneja el método
ExtractPixelsa la canalización y especifica el nombre de la columna para direccionar los píxeles utilizando el parámetrooutputColumnName..Append(context.Transforms.ExtractPixels(outputColumnName: "image_tensor"))Aplique el modelo ONNX a la imagen para realizar una predicción. Esto toma algunos parámetros:
- modelFile : ruta de acceso al archivo de modelo ONNX
- outputColumnNames : matriz de cadenas que contiene los nombres de todos los nombres de columna de salida, que se pueden encontrar al analizar el modelo ONNX en Netron.
- inputColumnNames : matriz de cadenas que contiene los nombres de todos los nombres de la columna de entrada, que también se pueden encontrar al analizar el modelo ONNX en Netron.
.Append(context.Transforms.ApplyOnnxModel(outputColumnNames: new string[] { "detected_boxes", "detected_scores", "detected_classes" }, inputColumnNames: new string[] { "image_tensor" }, modelFile: "./Model/model.onnx"));
Ajustar el modelo
Ahora que ha definido una canalización, puede usarla para compilar el modelo de ML.NET. Use el Fit método en la canalización y pase el vacío IDataView.
var model = pipeline.Fit(data);
A continuación, para realizar predicciones, use el modelo para crear un motor de predicción. Se trata de un método genérico, por lo que toma las StopSignInput clases y StopSignPrediction que se crearon anteriormente.
var predictionEngine = context.Model.CreatePredictionEngine<StopSignInput, StopSignPrediction>(model);
Extracción de las etiquetas
Para asignar las salidas del modelo a sus etiquetas, debe extraer las etiquetas proporcionadas por Custom Vision. Estas etiquetas se encuentran en el archivo labels.txt que se incluyó en el archivo ZIP con el modelo ONNX.
Llame al ReadAllLines método para leer todas las etiquetas del archivo.
var labels = File.ReadAllLines("./model/labels.txt");
Predicción en una imagen de prueba
Ahora puede usar el modelo para predecir imágenes nuevas. En el proyecto, hay una carpeta de prueba que puede usar para realizar predicciones. Esta carpeta contiene dos imágenes aleatorias con una señal de stop desde Unsplash. Una imagen tiene una señal de stop, mientras que la otra tiene dos señales de stop. Use el GetFiles método para leer las rutas de acceso de archivo de las imágenes del directorio.
var testFiles = Directory.GetFiles("./test");
Recorra las rutas de acceso de archivo para realizar una predicción utilizando el modelo y obtenga el resultado.
Cree un
foreachbucle para recorrer las imágenes de prueba.Bitmap testImage; foreach (var image in testFiles) { }En el
foreachbucle, genere el nombre de la imagen prevista en función del nombre de la imagen de prueba original.var predictedImage = $"{Path.GetFileName(image)}-predicted.jpg";También en el
foreachbucle, cree unaFileStreamde la imagen y conviértela en unBitmap.using (var stream = new FileStream(image, FileMode.Open)) { testImage = (Bitmap)Image.FromStream(stream); }También en el bucle
foreach, llame al métodoPredictdel motor de predicción.var prediction = predictionEngine.Predict(new StopSignInput { Image = testImage });Con la predicción, puede obtener las cajas delimitadoras. Use el Chunk método para determinar cuántos objetos ha detectado el modelo. Para ello, tome el recuento de las cajas delimitadoras previstas y divida eso por el número de etiquetas que se predijeron. Por ejemplo, si tuviera tres objetos detectados en una imagen, habría 12 elementos en la
BoundingBoxesmatriz y tres etiquetas predichas. A continuación, elChunkmétodo le daría tres matrices de cuatro para representar los cuadros de límite para cada objeto.var boundingBoxes = prediction.BoundingBoxes.Chunk(prediction.BoundingBoxes.Count() / prediction.PredictedLabels.Count());A continuación, capture el ancho original y el alto de las imágenes usadas para la predicción.
var originalWidth = testImage.Width; var originalHeight = testImage.Height;Calcule dónde en la imagen dibujar las cajas. Para ello, cree un
forbucle basado en el recuento del fragmento de cajas delimitadoras.for (int i = 0; i < boundingBoxes.Count(); i++) { }Dentro del
forbucle, calcule la posición de las coordenadas x e y, así como el ancho y alto del cuadro que se va a dibujar en la imagen. Lo primero que debe hacer es obtener el conjunto de cuadros de límite mediante elElementAtmétodo .var boundingBox = boundingBoxes.ElementAt(i);Con la caja delimitadora actual, ahora puede calcular dónde dibujar la caja. Utilice el ancho de la imagen original para los elementos primer y tercer del cuadro delimitador, y el alto de la imagen original para los elementos segundo y cuarto.
var left = boundingBox[0] * originalWidth; var top = boundingBox[1] * originalHeight; var right = boundingBox[2] * originalWidth; var bottom = boundingBox[3] * originalHeight;Calcule el ancho y el alto del cuadro para dibujar alrededor del objeto detectado dentro de la imagen. Los elementos x e y son las variables
leftytopdel cálculo anterior. Use elMath.Absmétodo para obtener el valor absoluto de los cálculos de ancho y alto en caso de que sea negativo.var x = left; var y = top; var width = Math.Abs(right - left); var height = Math.Abs(top - bottom);A continuación, obtenga la etiqueta predicha de la matriz de etiquetas.
var label = labels[prediction.PredictedLabels[i]];Cree un gráfico basado en la imagen de prueba mediante el
Graphics.FromImagemétodo .using var graphics = Graphics.FromImage(testImage);Dibuja sobre la imagen utilizando la información del cuadro delimitador. En primer lugar, dibuje el rectángulo alrededor de los objetos detectados utilizando el método
DrawRectangle, que emplea un objetoPenpara determinar el color y el ancho del rectángulo, y pase las variablesx,y,widthyheight.graphics.DrawRectangle(new Pen(Color.NavajoWhite, 8), x, y, width, height);A continuación, muestre la etiqueta predicha dentro del cuadro con el
DrawStringmétodo que toma la cadena para imprimir y unFontobjeto para determinar cómo dibujar la cadena y dónde colocarla.graphics.DrawString(label, new Font(FontFamily.Families[0], 18f), Brushes.NavajoWhite, x + 5, y + 5);Después del
forbucle, compruebe si el archivo previsto ya existe. Si lo hace, elimínelo. A continuación, guárdelo en la ruta de acceso definida para la salida.if (File.Exists(predictedImage)) { File.Delete(predictedImage); } testImage.Save(Path.Combine(assemblyFolderPath, predictedImage));
Pasos siguientes
Pruebe uno de los otros tutoriales de clasificación de imágenes: