Skip to content

Commit

Permalink
Update code to v5.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
dme-compunet committed Sep 15, 2024
1 parent d0bce48 commit 3b805a1
Show file tree
Hide file tree
Showing 107 changed files with 2,440 additions and 2,006 deletions.
74 changes: 43 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,69 +1,78 @@
# YOLOv8
# YoloV8

Use [YOLOv8](https://github.com/ultralytics/ultralytics) in real-time for object detection, instance segmentation, pose estimation and image classification, via [ONNX Runtime](https://github.com/microsoft/onnxruntime)
Integrate [YOLOv8](https://github.com/ultralytics/ultralytics) into your C# project for a variety of real-time tasks including object detection, instance segmentation, pose estimation and more, using ONNX Runtime.

# Install
# Features
- **YOLOv8 Tasks** 🌟 Support for all YOLOv8 tasks ([Detect](https://docs.ultralytics.com/tasks/detect), [Segment](https://docs.ultralytics.com/tasks/segment), [Classify](https://docs.ultralytics.com/tasks/classify), [Pose](https://docs.ultralytics.com/tasks/pose) and [OBB](https://docs.ultralytics.com/tasks/obb))
- **High Performance** 🚀 Various techniques and use of .NET features to maximize performance
- **Reduced Memory Usage** 🧠 By reusing memory blocks and reducing the pressure on the GC
- **Plotting Options** 📊 Plotting operations for preview of model results on the target image.
- **YOLOv10 Support** 🔧 Includes additional support for [YOLOv10](https://docs.ultralytics.com/models/yolov10)

The `YoloV8` project is available in two nuget packages: [YoloV8](https://www.nuget.org/packages/YoloV8) and [YoloV8.Gpu](https://www.nuget.org/packages/YoloV8.Gpu), if you use with CPU add the [YoloV8](https://www.nuget.org/packages/YoloV8) package reference to your project (contains reference to [Microsoft.ML.OnnxRuntime](https://www.nuget.org/packages/Microsoft.ML.OnnxRuntime) package)
# Installation
This project provides two NuGet packages:
- For CPU inference, use the package: [YoloV8](https://www.nuget.org/packages/YoloV8) (includes the [Microsoft.ML.OnnxRuntime](https://www.nuget.org/packages/Microsoft.ML.OnnxRuntime) package)
- For GPU inference, use the package: [YoloV8.Gpu](https://www.nuget.org/packages/YoloV8.Gpu) (includes the [Microsoft.ML.OnnxRuntime.Gpu](https://www.nuget.org/packages/Microsoft.ML.OnnxRuntime.Gpu) package)

```shell
dotnet add package YoloV8
```
# Usage

If you use with GPU you can add the [YoloV8.Gpu](https://www.nuget.org/packages/YoloV8.Gpu) package reference (contains reference to [Microsoft.ML.OnnxRuntime.Gpu](https://www.nuget.org/packages/Microsoft.ML.OnnxRuntime.Gpu) package)

```shell
dotnet add package YoloV8.Gpu
```

# Use

### Export the model from PyTorch to ONNX format:

Run this python code to export the model in ONNX format:
### 1. Export model to ONNX format:

For convert the pre-trained PyTorch model to ONNX format, run the following Python code:
```python
from ultralytics import YOLO

# Load a model
model = YOLO('path/to/best')
model = YOLO('path/to/best.pt')

# export the model to ONNX format
# Export the model to ONNX format
model.export(format='onnx')
```

### Use in exported model with C#:
### 2. Load the ONNX model with C#:

Add the `YoloV8` (or `YoloV8.Gpu`) package to your project:
```shell
dotnet add package YoloV8
```

Use the following C# code to load the model and run basic prediction:
```csharp
using Compunet.YoloV8;
using SixLabors.ImageSharp;

using var predictor = YoloV8Predictor.Create("path/to/model");
// Load the YOLOv8 predictor
using var predictor = new YoloPredictor("path/to/model.onnx");

var result = predictor.Detect("path/to/image");
// Run model
var result = predictor.Detect("path/to/image.jpg");
// or
var result = await predictor.DetectAsync("path/to/image");
var result = await predictor.DetectAsync("path/to/image.jpg");

// Write result summary to terminal
Console.WriteLine(result);
```

# Plotting

You can to plot the input image for preview the model prediction results, this code demonstrates how to perform a prediction, plot the results and save to file:
You can to plot the target image for preview the model results, this code demonstrates how to run a inference, plot the results on image and save to file:

```csharp
using Compunet.YoloV8;
using Compunet.YoloV8.Plotting;
using SixLabors.ImageSharp;

using var image = Image.Load("path/to/image");
// Load the YOLOv8 predictor
using var predictor = new YoloPredictor("path/to/model.onnx");

using var predictor = YoloV8Predictor.Create("path/to/model");
// Load the target image
using var image = Image.Load("path/to/image");

// Run model
var result = await predictor.PoseAsync(image);

// Create plotted image from model results
using var plotted = await result.PlotImageAsync(image);

// Write the plotted image to file
plotted.Save("./pose_demo.jpg")
```

Expand All @@ -74,12 +83,13 @@ using Compunet.YoloV8;
using Compunet.YoloV8.Plotting;
using SixLabors.ImageSharp;

// Load the YOLOv8 predictor
using var predictor = YoloV8Predictor.Create("path/to/model");

// Run model, plot predictions and write to file
predictor.PredictAndSaveAsync("path/to/image");
```

## Demo Images:
## Example Images:

#### Detection:

Expand All @@ -96,3 +106,5 @@ predictor.PredictAndSaveAsync("path/to/image");
# License

AGPL-3.0 License

**Important Note:** This project depends on ImageSharp, you should check the license details [here](https://github.com/SixLabors/ImageSharp/blob/main/LICENSE)
20 changes: 12 additions & 8 deletions Source/YoloV8.Demo/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@
using System.Diagnostics;

Console.WriteLine("Loading pose estimation model...");
using var posePredictor = YoloV8Predictor.Create("./models/yolov8n-pose-uint8.onnx");
using var posePredictor = new YoloPredictor("./models/yolov8n-pose-uint8.onnx");

Console.WriteLine("Loading detection model...");
using var detectPredictor = YoloV8Predictor.Create("./models/yolov8n-uint8.onnx");
using var detectPredictor = new YoloPredictor("./models/yolov8n-uint8.onnx");

Console.WriteLine("Loading segmentation model...");
using var segmentPredictor = YoloV8Predictor.Create("./models/yolov8n-seg-uint8.onnx");
using var segmentPredictor = new YoloPredictor("./models/yolov8n-seg-uint8.onnx");

Console.WriteLine("Loading classification model...");
using var classifyPredictor = YoloV8Predictor.Create("./models/yolov8n-cls-uint8.onnx");
using var classifyPredictor = new YoloPredictor("./models/yolov8n-cls-uint8.onnx");

Console.WriteLine();

await PredictAndSaveAsync(posePredictor, "bus.jpg");
await PredictAndSaveAsync(posePredictor, "sports.jpg");
Expand All @@ -34,15 +36,17 @@
});
}

static async Task PredictAndSaveAsync(YoloV8Predictor predictor, string image)
static async Task PredictAndSaveAsync(YoloPredictor predictor, string image)
{
var path = $"./images/{image}";
var task = predictor.Metadata.Task;

Console.WriteLine($"Running '{image}' (test: {task})...");

var result = await predictor.PredictAndSaveAsync(path);

Console.WriteLine();
Console.WriteLine($"Task: {predictor.Metadata.Task}");
Console.WriteLine($"Image: {image}");
Console.WriteLine($"Result: {result}");
Console.WriteLine($"Speed: {result.Speed}");

Console.WriteLine();
}
2 changes: 1 addition & 1 deletion Source/YoloV8.Demo/YoloV8.Demo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</ItemGroup>

<ItemGroup>
<None Include="..\Assets\**" CopyToOutputDirectory="PreserveNewest" />
<None Include="..\Assets\**" CopyToOutputDirectory="PreserveNewest" Visible="false" />
</ItemGroup>

</Project>
30 changes: 17 additions & 13 deletions Source/YoloV8.Tests/NonMaxSuppressionTests.cs
Original file line number Diff line number Diff line change
@@ -1,46 +1,50 @@
namespace YoloV8.Tests;
using Compunet.YoloV8.Parsing;

namespace YoloV8.Tests;

public class NonMaxSuppressionTests
{
[Fact]
public void NonMaxSuppressionBasicTest()
{
var classA = new YoloV8Class(0, "a");
var classB = new YoloV8Class(1, "b");
var nonMaxSuppression = new NonMaxSuppressionService();

var classA = new YoloName(0, "a");
var classB = new YoloName(1, "b");

IndexedBoundingBox[] boxes =
RawBoundingBox[] boxes =
[
new IndexedBoundingBox
new RawBoundingBox
{
Index = 0,
Class = classA,
Name = classA,
Bounds = new Rectangle(0, 0, 50, 50),
Confidence = .8f
},
new IndexedBoundingBox
new RawBoundingBox
{
Index = 1,
Class = classA,
Name = classA,
Bounds = new Rectangle(0, 0, 50, 50),
Confidence = .9f
},
new IndexedBoundingBox
new RawBoundingBox
{
Index = 2,
Class = classB,
Name = classB,
Bounds = new Rectangle(0, 0, 50, 50),
Confidence = .9f
},
new IndexedBoundingBox
new RawBoundingBox
{
Index = 3,
Class = classA,
Name = classA,
Bounds = new Rectangle(50, 50, 50, 50),
Confidence = .5f
},
];

var selected = NonMaxSuppressionHelper.Suppress(boxes, .5f);
var selected = nonMaxSuppression.Suppress(boxes.AsSpan(), .5f);

Assert.Equal([1, 2, 3], selected.Select(x => x.Index).Order());
}
Expand Down
18 changes: 9 additions & 9 deletions Source/YoloV8.Tests/Predictors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@

public static class Predictors
{
public static readonly YoloV8Predictor Pose = YoloV8Predictor.Create("./models/yolov8n-pose-uint8.onnx");
public static readonly YoloV8Predictor Detection = YoloV8Predictor.Create("./models/yolov8n-uint8.onnx");
public static readonly YoloV8Predictor Segmentation = YoloV8Predictor.Create("./models/yolov8n-seg-uint8.onnx");
public static readonly YoloV8Predictor Classification = YoloV8Predictor.Create("./models/yolov8n-cls-uint8.onnx");
public static readonly YoloPredictor Pose = new("./models/yolov8n-pose-uint8.onnx");
public static readonly YoloPredictor Detection = new("./models/yolov8n-uint8.onnx");
public static readonly YoloPredictor Segmentation = new("./models/yolov8n-seg-uint8.onnx");
public static readonly YoloPredictor Classification = new("./models/yolov8n-cls-uint8.onnx");

public static YoloV8Predictor GetPredictor(YoloV8Task task)
public static YoloPredictor GetPredictor(YoloTask task)
{
return task switch
{
YoloV8Task.Pose => Pose,
YoloV8Task.Detect => Detection,
YoloV8Task.Segment => Segmentation,
YoloV8Task.Classify => Classification,
YoloTask.Pose => Pose,
YoloTask.Detect => Detection,
YoloTask.Segment => Segmentation,
YoloTask.Classify => Classification,
_ => throw new InvalidEnumArgumentException()
};
}
Expand Down
6 changes: 3 additions & 3 deletions Source/YoloV8.Tests/Usings.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
global using Compunet.YoloV8;
global using Compunet.YoloV8.Metadata;
global using Compunet.YoloV8.Parsers;
global using Compunet.YoloV8.Utilities;
global using Compunet.YoloV8.Services;
global using SixLabors.ImageSharp;
global using System.ComponentModel;
global using Xunit;
global using Xunit;

Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
namespace YoloV8.Tests;

public class YoloV8Tests
public class YoloPredictorTests
{
[Theory]
[InlineData("bus.jpg", 3)]
[InlineData("sports.jpg", 3)]
public void PoseTest(string image, int count)
{
var predictor = Predictors.GetPredictor(YoloV8Task.Pose);
var predictor = Predictors.GetPredictor(YoloTask.Pose);

image = GetImagePath(image);

var result = predictor.Pose(image);

Assert.Equal(count, result.Boxes.Count());
Assert.Equal(count, result.Count);
}

[Theory]
[InlineData("bus.jpg", "person:3;bus:1")]
[InlineData("sports.jpg", "person:2;sports ball:1;baseball bat:1;baseball glove:2")]
public void DetectionTest(string image, string objects)
{
var predictor = Predictors.GetPredictor(YoloV8Task.Detect);
var predictor = Predictors.GetPredictor(YoloTask.Detect);

image = GetImagePath(image);

Expand All @@ -39,11 +39,11 @@ public void DetectionTest(string image, string objects)
list.Add((name, count));
}

Assert.Equal(list.Sum(x => x.count), result.Boxes.Length);
Assert.Equal(list.Sum(x => x.count), result.Count);

foreach (var (name, count) in list)
{
Assert.Equal(count, result.Boxes.Where(x => x.Class.Name == name).Count());
Assert.Equal(count, result.Where(x => x.Name.Name == name).Count());
}
}

Expand All @@ -53,21 +53,21 @@ public void DetectionTest(string image, string objects)
[InlineData("toaster.jpg", "toaster")]
public void ClassificationTest(string image, string label)
{
var predictor = Predictors.GetPredictor(YoloV8Task.Classify);
var predictor = Predictors.GetPredictor(YoloTask.Classify);

image = GetImagePath(image);

var result = predictor.Classify(image);

Assert.Equal(result.TopClass.Name.Name, label);
Assert.Equal(result[0].Name.Name, label);
}

[Theory]
[InlineData(YoloV8Task.Pose, 1, 640)]
[InlineData(YoloV8Task.Detect, 80, 640)]
[InlineData(YoloV8Task.Segment, 80, 640)]
[InlineData(YoloV8Task.Classify, 1000, 224)]
public void MetadataTest(YoloV8Task task, int classesCount, int imageSize)
[InlineData(YoloTask.Pose, 1, 640)]
[InlineData(YoloTask.Detect, 80, 640)]
[InlineData(YoloTask.Segment, 80, 640)]
[InlineData(YoloTask.Classify, 1000, 224)]
public void MetadataTest(YoloTask task, int classesCount, int imageSize)
{
var metadata = Predictors.GetPredictor(task).Metadata;

Expand All @@ -77,12 +77,12 @@ public void MetadataTest(YoloV8Task task, int classesCount, int imageSize)

Assert.Equal(task, metadata.Task);

Assert.Equal(1, metadata.Batch);
Assert.Equal(1, metadata.BatchSize);

Assert.Equal(imageSize, metadata.ImageSize.Width);
Assert.Equal(imageSize, metadata.ImageSize.Height);

Assert.Equal(classesCount, metadata.Names.Count);
Assert.Equal(classesCount, metadata.Names.Length);
}

private static string GetImagePath(string image)
Expand Down
2 changes: 1 addition & 1 deletion Source/YoloV8.Tests/YoloV8.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</ItemGroup>

<ItemGroup>
<None Include="..\Assets\**" CopyToOutputDirectory="PreserveNewest" />
<None Include="..\Assets\**" CopyToOutputDirectory="PreserveNewest" Visible="false" />
</ItemGroup>

<ItemGroup>
Expand Down
3 changes: 0 additions & 3 deletions Source/YoloV8/AssemblyAttributes.cs

This file was deleted.

Loading

0 comments on commit 3b805a1

Please sign in to comment.