Skip to content

Commit 81f21af

Browse files
C# create Object Detection sample using Onnx Model (dotnet#341)
* WIP: pushed sample for object detection * Removing object detection solution from master branch * Added a new sample i.e Scalable WEBAPI for Real time scenario in the repo. so added link for that sample in ReadME file in seperate table. * Working on Object Detection sample * pushed the code to interpret the scores of model and predict the objects in the image. * Created a sample object Detection using TinyYolo2 Onnx model * Adding the model file * Renamed the folder from TryOnnx to ObjectDetection. so this folder is created as copy. * added Build.Props file with version Ml.Net 1.0.0.-preview * Added ReadMe file and the images need for it. * Added the link for Object Detection sample in ReadMe page of launching page
1 parent f647bbd commit 81f21af

File tree

18 files changed

+612
-2
lines changed

18 files changed

+612
-2
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,13 @@ The official ML.NET samples are divided in multiple categories depending on the
148148
<td>
149149
<h4>TensorFlow(ML.NET Scoring) &nbsp;&nbsp;&nbsp;<a href="samples/csharp/getting-started/DeepLearning_ImageClassification_TensorFlow">C#</a> &nbsp; &nbsp; <a href="samples/fsharp/getting-started/DeepLearning_ImageClassification_TensorFlow">F#</a> &nbsp;&nbsp;&nbsp;<img src="images/app-type-getting-started.png" alt="Getting started icon"></h4>
150150
<h4>TensorFlow(ML.NET Estimator) &nbsp;&nbsp;&nbsp;<a href="samples/csharp/getting-started/DeepLearning_TensorFlowEstimator">C#</a> &nbsp; &nbsp; <a href="samples/fsharp/getting-started/DeepLearning_TensorFlowEstimator">F#</a> &nbsp;&nbsp;&nbsp;<img src="images/app-type-getting-started.png" alt="Getting started icon"></h4>
151-
<h4>Object detection Coming soon &nbsp;&nbsp;&nbsp;<img src="images/app-type-getting-started.png" alt="Getting started icon"></h4>
151+
<h4>Object detection &nbsp;&nbsp;&nbsp;<a href="samples/csharp/getting-started\DeepLearning_ObjectDetection_Onnx">C#</a> &nbsp; &nbsp;<img src="images/app-type-getting-started.png" alt="Getting started icon"></h4>
152152
<h4>Style Transfer Coming soon &nbsp;&nbsp;&nbsp;<img src="images/app-type-e2e.png" alt="End-to-end app icon"></h4>
153153
<h4>ONNX with ML.NET - Coming soon &nbsp;&nbsp;&nbsp;<img src="images/app-type-getting-started.png" alt="Getting started icon"></h4>
154154
</td>
155155
</tr>
156156
</table>
157-
157+
158158
**Real Time ML.Net Samples:** The below samples are created for real time scenarios like Scalable WebAPI services, Datasets stored in Database etc.
159159

160160
<table>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<Project>
2+
3+
<PropertyGroup>
4+
<MicrosoftMLVersion>1.0.0-preview</MicrosoftMLVersion>
5+
</PropertyGroup>
6+
7+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.28307.438
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObjectDetection", "ObjectDetectionConsoleApp\ObjectDetection.csproj", "{17EF43C6-7F74-4491-B894-AD14209C2B47}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{17EF43C6-7F74-4491-B894-AD14209C2B47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{17EF43C6-7F74-4491-B894-AD14209C2B47}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{17EF43C6-7F74-4491-B894-AD14209C2B47}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{17EF43C6-7F74-4491-B894-AD14209C2B47}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {BC2591CF-DDCB-45BA-9916-9E38D79561E9}
24+
EndGlobalSection
25+
EndGlobal
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using Microsoft.ML.Data;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.IO;
5+
using System.Linq;
6+
7+
namespace ObjectDetection
8+
{
9+
public class ImageNetData
10+
{
11+
[LoadColumn(0)]
12+
public string ImagePath;
13+
14+
[LoadColumn(1)]
15+
public string Label;
16+
17+
public static IEnumerable<ImageNetData> ReadFromCsv(string file, string folder)
18+
{
19+
return File.ReadAllLines(file)
20+
.Select(x => x.Split('\t'))
21+
.Select(x => new ImageNetData { ImagePath = Path.Combine(folder, x[0]), Label = x[1] } );
22+
}
23+
}
24+
25+
public class ImageNetDataProbability : ImageNetData
26+
{
27+
public string PredictedLabel;
28+
public float Probability { get; set; }
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using Microsoft.ML.Data;
2+
3+
namespace ObjectDetection
4+
{
5+
public class ImageNetPrediction
6+
{
7+
[ColumnName(OnnxModelScorer.TinyYoloModelSettings.ModelOutput)]
8+
public float[] PredictedLabels;
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp2.2</TargetFramework>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="Microsoft.ML" Version="$(MicrosoftMLVersion)" />
10+
<PackageReference Include="Microsoft.ML.ImageAnalytics" Version="$(MicrosoftMLVersion)" />
11+
<PackageReference Include="Microsoft.ML.OnnxTransformer" Version="0.12.0-preview" />
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<None Update="assets\images\dog2.jpg">
16+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
17+
</None>
18+
<None Update="assets\images\Intersection-Counts.jpg">
19+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
20+
</None>
21+
<None Update="assets\images\tags.tsv">
22+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
23+
</None>
24+
</ItemGroup>
25+
26+
<ItemGroup>
27+
<Folder Include="assets\Model\" />
28+
</ItemGroup>
29+
30+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Microsoft.ML;
5+
6+
namespace ObjectDetection
7+
{
8+
class OnnxModelScorer
9+
{
10+
private readonly string imagesLocation;
11+
private readonly string imagesFolder;
12+
private readonly string modelLocation;
13+
private readonly MLContext mlContext;
14+
15+
private IList<YoloBoundingBox> _boxes = new List<YoloBoundingBox>();
16+
private readonly YoloWinMlParser _parser = new YoloWinMlParser();
17+
18+
public OnnxModelScorer(string imagesLocation, string imagesFolder, string modelLocation)
19+
{
20+
this.imagesLocation = imagesLocation;
21+
this.imagesFolder = imagesFolder;
22+
this.modelLocation = modelLocation;
23+
mlContext = new MLContext();
24+
}
25+
26+
public struct ImageNetSettings
27+
{
28+
public const int imageHeight = 416;
29+
public const int imageWidth = 416;
30+
}
31+
32+
public struct TinyYoloModelSettings
33+
{
34+
// for checking TIny yolo2 Model input and output parameter names,
35+
//you can use tools like Netron,
36+
// which is installed by Visual Studio AI Tools
37+
38+
// input tensor name
39+
public const string ModelInput = "image";
40+
41+
// output tensor name
42+
public const string ModelOutput = "grid";
43+
}
44+
45+
public void Score()
46+
{
47+
var model = LoadModel(imagesFolder, modelLocation);
48+
49+
PredictDataUsingModel(imagesLocation, imagesFolder, model);
50+
}
51+
52+
private PredictionEngine<ImageNetData, ImageNetPrediction> LoadModel(string imagesFolder, string modelLocation)
53+
{
54+
Console.WriteLine("Read model");
55+
Console.WriteLine($"Model location: {modelLocation}");
56+
Console.WriteLine($"Images folder: {imagesFolder}");
57+
Console.WriteLine($"Default parameters: image size=({ImageNetSettings.imageWidth},{ImageNetSettings.imageHeight})");
58+
59+
var data = mlContext.Data.LoadFromTextFile<ImageNetData>(imagesLocation, hasHeader: true);
60+
61+
var pipeline = mlContext.Transforms.LoadImages(outputColumnName: "image", imageFolder: imagesFolder, inputColumnName: nameof(ImageNetData.ImagePath))
62+
.Append(mlContext.Transforms.ResizeImages(outputColumnName: "image", imageWidth: ImageNetSettings.imageWidth, imageHeight: ImageNetSettings.imageHeight, inputColumnName: "image"))
63+
.Append(mlContext.Transforms.ExtractPixels(outputColumnName: "image"))
64+
.Append(mlContext.Transforms.ApplyOnnxModel(modelFile: modelLocation, outputColumnNames: new[] { TinyYoloModelSettings.ModelOutput }, inputColumnNames: new[] { TinyYoloModelSettings.ModelInput }));
65+
66+
var model = pipeline.Fit(data);
67+
68+
var predictionEngine = mlContext.Model.CreatePredictionEngine<ImageNetData, ImageNetPrediction>(model);
69+
70+
return predictionEngine;
71+
}
72+
73+
protected void PredictDataUsingModel(string imagesLocation,
74+
string imagesFolder,
75+
PredictionEngine<ImageNetData, ImageNetPrediction> model)
76+
{
77+
Console.WriteLine($"Tags file location: {imagesLocation}");
78+
Console.WriteLine("");
79+
Console.WriteLine("=====Identify the objects in the images=====");
80+
Console.WriteLine("");
81+
82+
var testData = ImageNetData.ReadFromCsv(imagesLocation, imagesFolder);
83+
84+
foreach (var sample in testData)
85+
{
86+
var probs = model.Predict(sample).PredictedLabels;
87+
IList<YoloBoundingBox> boundingBoxes = _parser.ParseOutputs(probs);
88+
var filteredBoxes = _parser.NonMaxSuppress(boundingBoxes, 5, .5F);
89+
90+
Console.WriteLine(".....The objects in the image {0} are detected as below....", sample.Label);
91+
foreach (var box in filteredBoxes)
92+
{
93+
Console.WriteLine(box.Label + " and its Confidence score: " + box.Confidence);
94+
}
95+
Console.WriteLine("");
96+
}
97+
}
98+
}
99+
}
100+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
using System.IO;
3+
using System.IO.Compression;
4+
using System.Net;
5+
6+
namespace ObjectDetection
7+
{
8+
class Program
9+
{
10+
public static void Main()
11+
{
12+
var assetsRelativePath = @"../../../assets";
13+
string assetsPath = GetAbsolutePath(assetsRelativePath);
14+
var modelFilePath = Path.Combine(assetsPath, "Model", "TinyYolo2_model.onnx");
15+
var imagesFolder = Path.Combine(assetsPath,"images");
16+
var tagsTsv = Path.Combine(assetsPath,"images", "tags.tsv");
17+
18+
try
19+
{
20+
var modelScorer = new OnnxModelScorer(tagsTsv, imagesFolder, modelFilePath);
21+
modelScorer.Score();
22+
}
23+
catch (Exception ex)
24+
{
25+
Console.WriteLine(ex.Message);
26+
}
27+
28+
Console.WriteLine("========= End of Process..Hit any Key ========");
29+
Console.ReadLine();
30+
}
31+
32+
public static string GetAbsolutePath(string relativePath)
33+
{
34+
FileInfo _dataRoot = new FileInfo(typeof(Program).Assembly.Location);
35+
string assemblyFolderPath = _dataRoot.Directory.FullName;
36+
37+
string fullPath = Path.Combine(assemblyFolderPath, relativePath);
38+
39+
return fullPath;
40+
}
41+
}
42+
}
43+
44+
45+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Drawing;
2+
3+
namespace ObjectDetection
4+
{
5+
class YoloBoundingBox
6+
{
7+
8+
public string Label { get; set; }
9+
public float X { get; set; }
10+
public float Y { get; set; }
11+
12+
public float Height { get; set; }
13+
public float Width { get; set; }
14+
15+
public float Confidence { get; set; }
16+
17+
public RectangleF Rect
18+
{
19+
get { return new RectangleF(X, Y, Width, Height); }
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)