ML.NET 版本 API 类型 状态 应用程序类型 数据类型 场景 机器学习任务 算法
v1.5.0 动态API 最新 端到端应用 图像文件 对象检测 深度学习 ONNX: Tiny YOLOv2 & Custom Vision

问题

对象检测是计算机视觉中的经典问题之一:识别给定图像中包含哪些对象以及它们在图像中的位置。对于这些情况,您可以使用预先训练的模型,也可以训练自己的模型对自定义域特定的图像进行分类。默认情况下,此示例使用预先训练的模型,但是您也可以添加从Custom Vision导出的模型。

示例的工作原理

此示例由两个独立的应用程序组成:

  • 一个WPF Core 桌面应用程序呈现摄像头的实时流,使用ML.NET通过对象检测模型运行视频帧,并用标签绘制边界框,指示实时检测到的对象。

  • 一个允许用户上载或选择图像的ASP.NET Core Web应用。Web应用程序使用ML.NET通过一个对象检测模型运行图像,并用指示检测到的对象的标签绘制边界框。

Web应用程序显示右侧列出的图像,可以选择每个图像进行处理。一旦图像被处理,它将被绘制在屏幕的中间,每个检测到的对象周围都有标记的边界框,如下所示。


或者,您可以尝试上传自己的图片,如下所示。


ONNX

开放式神经网络交换即ONNX是一种表示深度学习模型的开放格式。使用ONNX,开发人员可以在最先进的工具之间移动模型,并选择最适合他们的组合。ONNX是由包括微软在内的众多合作伙伴共同开发和支持的。

预训练模型

有多个预先训练的模型用于识别图像中的多个对象。WPF appWeb app都默认使用从ONNX Model Zoo下载的预先训练好的模型Tiny YOLOv2; 一组经过预先训练的、最先进的ONNX格式模型。Tiny YOLOv2是一种用于目标检测的实时神经网络,用于检测20个不同的类,并在Pascal VOC数据集上进行训练。它由9个卷积层和6个最大池层组成,是更复杂的完整的YOLOv2网络的较小版本。

Custom Vision 模型

此示例默认使用上述预先训练的Tiny YOLOv2模型。不过,它也支持从微软Custom Vision导出的ONNX模型。

要使用自己的模型,请使用以下步骤

  1. 使用 Custom Vision 创建和训练物体探测器。要导出模型,请确保选择一个紧凑域,例如常规(紧凑)。要导出现有的对象检测器,请通过选择右上角的齿轮图标将域转换为紧凑型。在_ 设置 _中,选择一个紧凑的模型,保存并训练您的项目。

  2. 转到_性能选项卡导出模型。选择一个用紧凑域训练的迭代,将出现一个“导出”按钮。选择_导出、ONNX、ONNX1.2,然后选择导出。文件准备好后,选择“下载”按钮。

  3. 导出的是一个包含多个文件的zip文件,包括一些示例代码、标签列表和ONNX模型。将.zip文件放到OnnxObjectDetection项目中的OnnxModels文件夹中。

  4. 在解决方案资源管理器中,右键单击OnnxModels文件夹,然后选择_添加现有项_。选择刚添加的.zip文件。

  5. 在解决方案资源管理器中,从OnnxModels文件夹中选择.zip文件。更改文件的以下属性:

  • 生成操作 -> 内容

  • 复制到输出目录 -> 如果较新则复制

现在,当你生成和运行应用程序时,它将使用你的模型而不是Tiny YOLOv2模型。

模型输入和输出

为了解析ONNL模型的预测输出,我们需要了解输入和输出张量的格式(或形状)。为此,我们将首先使用Netron,一个用于神经网络和机器学习模型的GUI可视化工具,用于检查模型。

下面是一个例子,我们将看到使用Netron打开这个示例的Tiny YOLOv2模型:

从上面的输出中,我们可以看到Tiny YOLOv2模型具有以下输入/输出格式:

输入: 'image' 3x416x416

首先要注意的是,输入张量的名称是**'image'。稍后在定义评估管道的input**参数时,我们将需要这个名称。

我们还可以看到,输入张量的形状3x416x416。这说明传入模型的位图图像应该是416高x 416宽。“3”表示图像应为BGR格式;前3个“通道”分别是蓝色、绿色和红色。

输出: 'data' 125x13x13

与输入张量一样,我们可以看到输出名称是**'data'。同样,在定义评估管道的output**参数时,我们会注意到这一点。

我们还可以看到, 输出张量的形状125x13x13

125x13x13的“13x13”部分意味着图像被分成一个13x13的“单元格”网格(13列x 13行)。因为我们知道输入图像是416x416,所以我们可以推断出每个“单元”都是32高x 32宽(416/13=32)

   ├──────────────── 416 ─────────────────┤┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ ┬     416/13=32├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │          ┌──┐├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │          └──┘├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │         32x32├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │
13 ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ 416├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘ ┴13

那125呢?“125”告诉我们,对于每个网格单元,模型返回125个“通道”(或数据)作为该单个单元的预测输出。

要了解为什么有125个通道,我们首先需要了解该模型不能预测对象的任意边界框。相反,每个单元格负责预测5个预定的边界框。这5个框是根据以下每个anchor 框的偏移量计算得出的:

┌───────────────────┐
│       ┌───┐       │
│ ┌─────┼───┼─────┐ │
│ │  ┌──┼───┼──┐  │ │
│ │  │  │┌─┐│  │  │ │
│ │  │  │└─┘│  │  │ │
│ │  └──┼───┼──┘  │ │
│ └─────┼───┼─────┘ │
│       └───┘       │
└───────────────────┘

因此,对于每个单独的单元格,该模型返回5个预测(每个锚定一个,由上面的框形表示),每个预测包括以下25个参数:

  • 4个参数指示边界框的位置(x,y,宽度,高度)

  • 1个参数指示盒子的置信度得分(或客观性)

  • 20个类别的概率(每个类别一个概率分数,表明该对象是该类别的可能性)

5个盒子x 25个参数= 125个'通道'

注意,如果对模型进行训练以检测不同数量的类,则该值将不同。例如,仅能检测3个不同类的模型的输出格式为40x13x13:

  • (x,y,宽度,高度,客观性)+ 3个类别概率= 8个参数

  • 5个盒子 x 8个参数 = 40个'通道'

解决方案

此解决方案中的项目使用.NET Core 3.0。为了运行此示例,您必须安装.NET Core SDK 3.0。为此,请执行以下任一操作:

  1. 通过转到.NET Core 3.0下载页面手动安装SDK,并在“SDK”列中下载最新的“.NET Core安装程序”。

  2. 或者,如果您使用的是Visual Studio 2019,请转至: 工具>选项>环境>预览功能 ,然后选中以下复选框: 使用.NET Core SDK的预览

解决方案包含三个项目

  • OnnxObjectDetection是WPF应用程序和Web应用程序都使用的.NET Standard库。它包含用于通过模型运行图像并解析结果预测的大多数逻辑。该项目还包含ONNX模型文件。除了在图像/屏幕上绘制标签边界框之外,此项目包含下面的所有代码段。

  • OnnxObjectDetectionWeb 包含一个ASP.NET Core Web App,其中包含Razor UI页面API controller以处理和呈现图像。

  • OnnxObjectDetectionApp 包含一个.NET CORE WPF桌面应用程序,该应用程序使用OpenCvSharp从设备的网络摄像头捕获视频。

代码演练

该示例与getting-started object detection sample不同,在这里我们加载/处理在内存中的图像**,而入门示例从文件中加载图像。

创建一个类,该类定义将数据加载到IDataView中时要使用的数据模式。ML.NET支持图像的Bitmap类型,因此我们将指定以ImageTypeAttribute修饰的Bitmap属性,并传入通过[检查模型]](#model-input-and-output)得到的高度和宽度尺寸,如下所示。

public struct ImageSettings
{public const int imageHeight = 416;public const int imageWidth = 416;
}public class ImageInputData
{[ImageType(ImageSettings.imageHeight, ImageSettings.imageWidth)]public Bitmap Image { get; set; }
}

ML.NET: 配置模型

第一步是创建一个空的DataView,以获取配置模型时要使用的数据架构。

var dataView = _mlContext.Data.LoadFromEnumerable(new List<ImageInputData>());

第二步是定义评估器管道。通常在处理深度神经网络时,必须使图像适应网络所期望的格式。因此,下面的代码将调整图像的大小并对其进行变换(所有R、G、B通道的像素值都已标准化)。

var pipeline = mlContext.Transforms.ResizeImages(resizing: ImageResizingEstimator.ResizingKind.Fill, outputColumnName: onnxModel.ModelInput, imageWidth: ImageSettings.imageWidth, imageHeight: ImageSettings.imageHeight, inputColumnName: nameof(ImageInputData.Image)).Append(mlContext.Transforms.ExtractPixels(outputColumnName: onnxModel.ModelInput)).Append(mlContext.Transforms.ApplyOnnxModel(modelFile: onnxModel.ModelPath, outputColumnName: onnxModel.ModelOutput, inputColumnName: onnxModel.ModelInput));

接下来,我们将使用通过检查模型 得到的输入和输出张量名称来定义Tiny YOLOv2 Onnx模型的inputoutput参数。

public struct TinyYoloModelSettings
{public const string ModelInput = "image";public const string ModelOutput = "grid";
}

最后,通过拟合“DataView”来创建模型。

var model = pipeline.Fit(dataView);

加载模型并创建PredictionEngine

配置模型后,我们需要保存模型,加载保存的模型,创建一个PredictionEngine,然后将图像传递给引擎以使用模型检测对象。这是一个Web应用程序和WPF应用程序略有不同的地方。

Web应用程序使用一个PredictionEnginePool来高效地管理服务,并为服务提供一个PredictionEngine来进行预测。在内部,它进行了优化,以便在创建这些对象时,以最小的开销在Http请求之间缓存和共享对象依赖关系。

public ObjectDetectionService(PredictionEnginePool<ImageInputData, TinyYoloPrediction> predictionEngine)
{this.predictionEngine = predictionEngine;
}

WPF桌面应用程序创建一个PredictionEngine,并在本地缓存以用于每个帧预测。需要澄清的关键点是,实例化PredictionEngine的调用代码负责处理缓存(与PredictionEnginePool相比)。

public PredictionEngine<ImageInputData, TinyYoloPrediction> GetMlNetPredictionEngine()
{return mlModel.Model.CreatePredictionEngine<ImageInputData, TinyYoloPrediction>(mlModel);
}

检测图像中的对象

获取预测时,我们在PredictedLabels属性中得到一个大小为21125float数组。这是前面讨论过的模型的125x13x13输出。然后,我们使用OnnxOutputParser类解释并返回每个图像的多个边界框。同样,这些框被过滤,因此我们只检索到5个具有高置信度的框。

var labels = tinyYoloPredictionEngine?.Predict(imageInputData).PredictedLabels;
var boundingBoxes = outputParser.ParseOutputs(labels);
var filteredBoxes = outputParser.FilterBoundingBoxes(boundingBoxes, 5, 0.5f);

在图像中检测到的对象周围绘制边界框

最后一步是在对象周围绘制边界框。

Web应用程序使用Paint API将框直接绘制到图像上,并返回图像以在浏览器中显示。

var img = _objectDetectionService.DrawBoundingBox(imageFilePath);using (MemoryStream m = new MemoryStream())
{img.Save(m, img.RawFormat);byte[] imageBytes = m.ToArray();// Convert byte[] to Base64 Stringbase64String = Convert.ToBase64String(imageBytes);var result = new Result { imageString = base64String };return result;
}

另外,WPF应用程序在与流式视频播放重叠的Canvas 元素上绘制边界框。

DrawOverlays(filteredBoxes, WebCamImage.ActualHeight, WebCamImage.ActualWidth);WebCamCanvas.Children.Clear();foreach (var box in filteredBoxes)
{var objBox = new Rectangle {/* ... */ };var objDescription = new TextBlock {/* ... */ };var objDescriptionBackground = new Rectangle {/* ... */ };WebCamCanvas.Children.Add(objDescriptionBackground);WebCamCanvas.Children.Add(objDescription);WebCamCanvas.Children.Add(objBox);
}

关于准确性的说明

Tiny YOLOv2的精确度明显低于完整的YOLOv2模型,但是对于这个示例应用程序来说,Tiny版本已经足够了。

疑难解答(Web应用程序)

通过应用程序服务在Azure上部署此应用程序时,您可能会遇到一些常见问题。

  1. 应用程序返回5xx代码

  • 要在Azure门户中添加.NET Core 3.0支持,请选择相应应用程序服务的开发工具>扩展部分中的添加按钮。

  • 然后,从扩展列表中选择选择扩展并选择ASP.NET Core 3.0(x64)Runtime并接受法律条款,继续将扩展添加到应用程序服务。

  1. 部署应用程序后,您可能会得到5xx代码的一个原因是平台。web应用程序仅在64位体系结构上运行。在Azure中,更改设置>配置>常规设置菜单中相应应用程序服务中的平台设置。

  2. 部署应用程序后使用5xx代码的另一个原因是web应用程序的目标框架是.NET Core 3.0,它目前正在预览中。您可以将应用程序和引用的项目还原为.NET Core 2.x或向应用程序服务添加扩展。

  • 相对路径

    在本地和Azure上工作时,路径的工作方式略有不同。如果成功地部署了应用程序,但单击其中一个预加载的映像或上载自己的映像不起作用,请尝试更改相对路径。为此,在Controllers/ObjectDetectionController.cs文件中,更改构造函数中的_imagesTmpFolder的值。

    _imagesTmpFolder = CommonHelpers.GetAbsolutePath(@"ImagesTemp");
    

    Get操作中的imageFileRelativePath执行相同的操作。

    string imageFileRelativePath = @"assets" + url;
    

    或者,您可以根据环境(dev / prod)设置条件,是使用路径的本地版本还是Azure首选的版本。

ML.NET 示例:对象检测-ASP.NET Core Web和WPF桌面示例相关推荐

  1. 使用YOLO Core ML模型构建对象检测iOS应用(七)

    目录 在我们的应用程序中添加模型 在捕获的视频帧上运行目标检测 绘制边界框 实际应用 下一步? 总目录 将ONNX对象检测模型转换为iOS Core ML(一) 解码Core ML YOLO对象检测器 ...

  2. ASP.NET Core Web API下事件驱动型架构的实现(二):事件处理器中对象生命周期的管理

    在ASP.NET Core Web API下事件驱动型架构的实现(一):一个简单的实现中,我介绍了事件驱动型架构的一种简单的实现,并演示了一个完整的事件派发.订阅和处理的流程.这种实现太简单了,百十行 ...

  3. ASP .NET Core Web MVC系列教程二:添加控制器

    系列文章目录:ASP .NET Core Web MVC系列教程:使用ASP .NET Core创建MVC Web应用程序 上一个教程:ASP .NET Core Web MVC系列教程一:创建一个W ...

  4. 如何测试ASP.NET Core Web API

    在本文中,我们将研究如何测试你的ASP .NET Core 2.0 Web API解决方案.我们将了解使用单元测试进行内部测试,使用全新的ASP .NET Core的集成测试框架来进行外部测试. 本文 ...

  5. 针对ASP.NET Core Web API的先进架构

    \ 本点要点 \\ 与传统的ASP.NET相比,ASP.NET Core的新架构提供了一些好处\\t ASP.NET Core从一开始就包含对依赖注入的支持\\t 单一职责原则简化了实施和设计.\\t ...

  6. ASP.NET Core Web 支付功能接入 微信-扫码支付篇

    // 随着版本更迭,新版本可能无法完全适用,请参考仓库内的示例. 这篇文章将介绍ASP.NET Core中使用 开源项目 Payment(https://github.com/Essensoft/Pa ...

  7. 在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务

    在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务 https://procodeguide.com/programming/polly-in-aspnet-core ...

  8. ASP.NET Core Web API基于RESTFul APIs的集合结果过滤和分页

    译者荐语:如何在RESTFul APIs中进行集合结果分页?还是用客户端来拼接链接地址么? 原文来自互联网,由长沙DotNET技术社区[邹溪源]翻译.如译文侵犯您的版权,请联系小编,小编将在24小时内 ...

  9. 如何测试 ASP.NET Core Web API

    在本文中,我们将研究如何测试你的 ASP .NET Core 2.0 Web API 解决方案.我们将了解使用单元测试进行内部测试,使用全新的 ASP .NET Core 的集成测试框架来进行外部测试 ...

最新文章

  1. 关于visualizer的setEnabled()方法何时进行设置成false?
  2. 万字超强图文讲解 AQS 以及 ReentrantLock 应用
  3. win10系统下“从开始屏幕取消固定”无反应解决方法
  4. 算法与数据结构(快速排序)
  5. 巴斯光年探险阿里聚安全攻防挑战赛!决战12月28日!
  6. rtmp流\http流测试地址
  7. python bootstrap_Python-bootstrap
  8. CVPR2020 | 阿里结构感知3D目标检测,KITTI BEV 排行榜第一!
  9. 关于oracle with as用法
  10. C++/Qt文件写入读取速度比较
  11. LOIC安全测试工具
  12. 【Android】spinner下拉框样式修改
  13. 最近非常火的AI绘图(附操作方法)
  14. uni-app APP支付 uni.requestPayment APP微信支付
  15. Love To Be Loved By You
  16. 群晖Docker部署Microsoft SQL Server 2019
  17. 超文本传输协议http详解
  18. 用VC实现Html编辑器
  19. sql 日期时间格式转换
  20. 《Natural Language Processing with Python》读书笔记 001期

热门文章

  1. android视图工具,android studio的HierarchyViewer工具如何知道android屏幕的视图属性
  2. java 友元_C++ 友元函数 | 菜鸟教程
  3. Requests获取连接的IP地址
  4. Python——通过斐波那契数列来理解生成器
  5. php函数的初步使用
  6. BDB (Berkeley DB)简要数据库(转载)
  7. 深入浅出Mybatis系列(一)---Mybatis入门[转]
  8. slidingmenu能否实现菜单页在内容页上方,而不是把内容页挤到一边去????...
  9. 如何从USB运行Windows 8 Developer Preview
  10. 停止抱怨英语_停止抱怨垂直视频