Skip to content

Commit 41d9a86

Browse files
committed
Bump to NatML 1.1.4
1 parent 60bba45 commit 41d9a86

File tree

15 files changed

+442
-368
lines changed

15 files changed

+442
-368
lines changed

Assembly-CSharp.csproj

Lines changed: 238 additions & 217 deletions
Large diffs are not rendered by default.

Assets/NanoDetDetection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* NanoDet
3-
* Copyright (c) 2022 NatML Inc. All Rights Reserved.
3+
* Copyright © 2023 NatML Inc. All Rights Reserved.
44
*/
55

66
namespace NatML.Examples.Visualizers {

Assets/NanoDetSample.cs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,24 @@ public sealed class NanoDetSample : MonoBehaviour {
2323
private NanoDetPredictor predictor;
2424

2525
private async void Start () {
26-
// Fetch the model data from NatML Hub
27-
modelData = await MLModelData.FromHub("@natsuite/nanodet");
28-
// Create the model
29-
model = new MLEdgeModel(modelData);
3026
// Create the NanoDet predictor
31-
predictor = new NanoDetPredictor(model, modelData.labels);
27+
predictor = await NanoDetPredictor.Create();
3228
// Listen for camera frames
33-
cameraManager.OnFrame.AddListener(OnCameraFrame);
29+
cameraManager.OnCameraFrame.AddListener(OnCameraFrame);
3430
}
3531

3632
private void OnCameraFrame (CameraFrame frame) {
37-
// Create input feature
38-
var feature = frame.feature;
39-
(feature.mean, feature.std) = modelData.normalization;
40-
feature.aspectMode = modelData.aspectMode;
4133
// Detect
42-
var detections = predictor.Predict(feature);
34+
var detections = predictor.Predict(frame);
4335
// Visualize
4436
visualizer.Render(detections);
4537
}
4638

47-
void OnDisable () => model?.Dispose(); // Dispose the model
39+
void OnDisable () {
40+
// Stop listening for camera frames
41+
cameraManager.OnCameraFrame.RemoveListener(OnCameraFrame);
42+
// Dispose the model
43+
model?.Dispose();
44+
}
4845
}
4946
}

Assets/NanoDetSample.unity

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ RenderSettings:
3838
m_ReflectionIntensity: 1
3939
m_CustomReflection: {fileID: 0}
4040
m_Sun: {fileID: 705507994}
41-
m_IndirectSpecularColor: {r: 0.44657838, g: 0.49641234, b: 0.57481676, a: 1}
41+
m_IndirectSpecularColor: {r: 0.4440765, g: 0.49331635, b: 0.57239074, a: 1}
4242
m_UseRadianceAmbientProbe: 0
4343
--- !u!157 &3
4444
LightmapSettings:
@@ -588,6 +588,7 @@ GameObject:
588588
- component: {fileID: 1627475241}
589589
- component: {fileID: 1627475243}
590590
- component: {fileID: 1627475242}
591+
- component: {fileID: 1627475244}
591592
m_Layer: 5
592593
m_Name: Preview
593594
m_TagString: Untagged
@@ -691,6 +692,25 @@ MonoBehaviour:
691692
m_EditorClassIdentifier:
692693
cameraManager: {fileID: 1924049083}
693694
viewMode: 0
695+
focusMode: 0
696+
exposureMode: 0
697+
zoomMode: 0
698+
OnPresent:
699+
m_PersistentCalls:
700+
m_Calls: []
701+
--- !u!114 &1627475244
702+
MonoBehaviour:
703+
m_ObjectHideFlags: 0
704+
m_CorrespondingSourceObject: {fileID: 0}
705+
m_PrefabInstance: {fileID: 0}
706+
m_PrefabAsset: {fileID: 0}
707+
m_GameObject: {fileID: 1627475237}
708+
m_Enabled: 1
709+
m_EditorHideFlags: 0
710+
m_Script: {fileID: 11500000, guid: d0b148fe25e99eb48b9724523833bab1, type: 3}
711+
m_Name:
712+
m_EditorClassIdentifier:
713+
m_Delegates: []
694714
--- !u!1 &1924049080
695715
GameObject:
696716
m_ObjectHideFlags: 0
@@ -750,12 +770,14 @@ MonoBehaviour:
750770
m_Script: {fileID: 11500000, guid: 98622613d505143a9a06b4b11b0a82cf, type: 3}
751771
m_Name:
752772
m_EditorClassIdentifier:
753-
resolution: 3
754-
capabilities: 1
773+
capabilities: 2
755774
playOnAwake: 1
775+
_facing: 0
776+
resolution: 3
777+
frameRate: 30
756778
focusMode: 0
757779
exposureMode: 0
758-
OnFrame:
780+
OnCameraFrame:
759781
m_PersistentCalls:
760782
m_Calls: []
761783
--- !u!1 &1934276594
@@ -788,6 +810,7 @@ MonoBehaviour:
788810
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
789811
m_Name:
790812
m_EditorClassIdentifier:
813+
m_SendPointerHoverToParent: 1
791814
m_HorizontalAxis: Horizontal
792815
m_VerticalAxis: Vertical
793816
m_SubmitButton: Submit

Assets/NanoDetVisualizer.cs

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace NatML.Examples.Visualizers {
88
using System.Collections.Generic;
99
using UnityEngine;
1010
using UnityEngine.UI;
11+
using NatML.Vision;
1112
using VideoKit.UI;
1213

1314
/// <summary>
@@ -21,29 +22,18 @@ public sealed class NanoDetVisualizer : MonoBehaviour {
2122

2223

2324
#region --Client API--
24-
/// <summary>
25-
/// Detection source image.
26-
/// </summary>
27-
public Texture2D image {
28-
get => rawImage.texture as Texture2D;
29-
set {
30-
rawImage.texture = value;
31-
aspectFitter.aspectRatio = (float)value.width / value.height;
32-
}
33-
}
34-
3525
/// <summary>
3626
/// Render a set of object detections.
3727
/// </summary>
3828
/// <param name="image">Image which detections are made on.</param>
3929
/// <param name="detections">Detections to render.</param>
40-
public void Render (params (Rect rect, string label, float score)[] detections) {
30+
public void Render (params NanoDetPredictor.Detection[] detections) {
4131
// Delete current
4232
foreach (var rect in currentRects)
4333
GameObject.Destroy(rect.gameObject);
4434
currentRects.Clear();
4535
// Render rects
46-
var imageRect = new Rect(0, 0, image.width, image.height);
36+
var imageRect = new Rect(0, 0, rawImage.texture.width, rawImage.texture.height);
4737
foreach (var detection in detections) {
4838
var rect = Instantiate(detectionPrefab, transform);
4939
rect.gameObject.SetActive(true);
@@ -56,13 +46,9 @@ public void Render (params (Rect rect, string label, float score)[] detections)
5646

5747
#region --Operations--
5848
private RawImage rawImage;
59-
private AspectRatioFitter aspectFitter;
6049
private readonly List<NanoDetDetection> currentRects = new List<NanoDetDetection>();
6150

62-
void Awake () {
63-
rawImage = GetComponent<RawImage>();
64-
aspectFitter = GetComponent<AspectRatioFitter>();
65-
}
51+
void Awake () => rawImage = GetComponent<RawImage>();
6652
#endregion
6753
}
6854
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
1+
## 1.0.1
2+
+ Added `NanoDetPredictor.Create` static method for creating the predictor.
3+
+ Added `NanoDetPredictor.Tag` constant string for model embedding.
4+
+ Removed `NanoDetPredictor` public constructor. Use the `Create` static method instead.
5+
+ Upgraded to NatML 1.1.4.
6+
17
## 1.0.0
28
+ First release.

Packages/ai.natml.vision.nanodet/README.md

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Add the following items to your Unity project's `Packages/manifest.json`:
1313
}
1414
],
1515
"dependencies": {
16-
"ai.natml.vision.nanodet": "1.0.0"
16+
"ai.natml.vision.nanodet": "1.0.1"
1717
}
1818
}
1919
```
@@ -22,36 +22,26 @@ Add the following items to your Unity project's `Packages/manifest.json`:
2222
## Detecting Objects in an Image
2323
First, create the NanoDet predictor:
2424
```csharp
25-
// Fetch the model data from NatML Hub
26-
var modelData = await MLModelData.FromHub("@natsuite/nanodet");
27-
// Deserialize the model
28-
var model = modelData.Deserialize();
2925
// Create the NanoDet predictor
30-
var predictor = new NanoDetPredictor(model, modelData.labels);
26+
var predictor = await NanoDetPredictor.Create();
3127
```
3228

3329
Then detect objects in the image:
3430
```csharp
3531
// Create image feature
3632
Texture2D image = ...;
37-
var imageFeature = new MLImageFeature(image);
38-
(imageFeature.mean, imageFeature.std) = modelData.normalization;
39-
imageFeature.aspectMode = modelData.aspectMode;
4033
// Detect objects
41-
(Rect rect, string label, float score)[] detections = predictor.Predict(imageFeature);
34+
NanoDetPredictor.Detection[] detections = predictor.Predict(image);
4235
```
43-
44-
> The detection rects are provided in normalized coordinates in range `[0.0, 1.0]`. The score is also normalized in range `[0.0, 1.0]`.
4536
___
4637

4738
## Requirements
4839
- Unity 2021.2+
4940

5041
## Quick Tips
51-
- Join the [NatML community on Discord](https://hub.natml.ai/community).
42+
- Join the [NatML community on Discord](https://natml.ai/community).
5243
- Discover more ML models on [NatML Hub](https://hub.natml.ai).
5344
- See the [NatML documentation](https://docs.natml.ai/unity).
54-
- Discuss [NatML on Unity Forums](https://forum.unity.com/threads/open-beta-natml-machine-learning-runtime.1109339/).
5545
- Contact us at [hi@natml.ai](mailto:hi@natml.ai).
5646

5747
Thank you very much!

Packages/ai.natml.vision.nanodet/Runtime/NanoDetPredictor.cs

Lines changed: 78 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
/*
22
* NanoDet
3-
* Copyright (c) 2022 NatML Inc. All Rights Reserved.
3+
* Copyright © 2023 NatML Inc. All Rights Reserved.
44
*/
55

66
namespace NatML.Vision {
77

88
using System;
99
using System.Collections.Generic;
1010
using System.Runtime.CompilerServices;
11+
using System.Threading.Tasks;
1112
using System.Linq;
1213
using UnityEngine;
1314
using NatML.Features;
@@ -19,41 +20,44 @@ namespace NatML.Vision {
1920
/// This predictor accepts an image feature and produces a list of detections.
2021
/// Each detection is comprised of a normalized rect, label, and detection score.
2122
/// </summary>
22-
public sealed class NanoDetPredictor : IMLPredictor<(Rect rect, string label, float score)[]> {
23+
public sealed class NanoDetPredictor : IMLPredictor<NanoDetPredictor.Detection[]> {
2324

24-
#region --Client API--
25+
#region --Types--
2526
/// <summary>
26-
/// Class labels.
27+
/// Detection.
2728
/// </summary>
28-
public readonly string[] labels;
29+
public struct Detection {
30+
31+
/// <summary>
32+
/// Normalized detection rect.
33+
/// </summary>
34+
public Rect rect;
35+
36+
/// <summary>
37+
/// Detection label.
38+
/// </summary>
39+
public string label;
40+
41+
/// <summary>
42+
/// Normalized detection score.
43+
/// </summary>
44+
public float score;
45+
}
46+
#endregion
47+
2948

49+
#region --Client API--
3050
/// <summary>
31-
/// Create the NanoDet predictor.
51+
/// Predictor tag.
3252
/// </summary>
33-
/// <param name="model">NanoDet ML model.</param>
34-
/// <param name="labels">Classification labels.</param>
35-
/// <param name="minScore">Minimum candidate score.</param>
36-
/// <param name="maxIoU">Maximum intersection-over-union score for overlap removal.</param>
37-
public NanoDetPredictor (MLModel model, string[] labels, float minScore = 0.35f, float maxIoU = 0.5f) {
38-
this.model = model as MLEdgeModel;
39-
this.labels = labels;
40-
this.minScore = minScore;
41-
this.maxIoU = maxIoU;
42-
this.inputType = model.inputs[0] as MLImageType;
43-
this.anchors8 = GenerateAnchors(inputType.width, inputType.height, 8);
44-
this.anchors16 = GenerateAnchors(inputType.width, inputType.height, 16);
45-
this.anchors32 = GenerateAnchors(inputType.width, inputType.height, 32);
46-
this.candidateBoxes = new List<Rect>();
47-
this.candidateScores = new List<float>();
48-
this.candidateLabels = new List<string>();
49-
}
53+
public const string Tag = "@natsuite/nanodet";
5054

5155
/// <summary>
5256
/// Detect objects in an image.
5357
/// </summary>
5458
/// <param name="inputs">Input image.</param>
5559
/// <returns>Detected objects.</returns>
56-
public unsafe (Rect rect, string label, float score)[] Predict (params MLFeature[] inputs) {
60+
public unsafe Detection[] Predict (params MLFeature[] inputs) {
5761
// Check
5862
if (inputs.Length != 1)
5963
throw new ArgumentException(@"NanoDet predictor expects a single feature", nameof(inputs));
@@ -63,6 +67,11 @@ public unsafe (Rect rect, string label, float score)[] Predict (params MLFeature
6367
var imageFeature = input as MLImageFeature;
6468
if (!imageType)
6569
throw new ArgumentException(@"NanoDet predictor expects an an array or image feature", nameof(inputs));
70+
// Preprocess
71+
if (imageFeature != null) {
72+
(imageFeature.mean, imageFeature.std) = model.normalization;
73+
imageFeature.aspectMode = model.aspectMode;
74+
}
6675
// Predict
6776
using var inputFeature = (input as IMLEdgeFeature).Create(inputType);
6877
using var outputFeatures = model.Predict(inputFeature);
@@ -118,16 +127,45 @@ public unsafe (Rect rect, string label, float score)[] Predict (params MLFeature
118127
// Add
119128
candidateBoxes.Add(box);
120129
candidateScores.Add(score);
121-
candidateLabels.Add(labels[label]);
130+
candidateLabels.Add(model.labels[label]);
122131
}
123132
}
124133
var keepIdx = MLImageFeature.NonMaxSuppression(candidateBoxes, candidateScores, maxIoU);
125-
var result = new List<(Rect, string, float)>();
126-
foreach (var idx in keepIdx)
127-
result.Add((candidateBoxes[idx], candidateLabels[idx], candidateScores[idx]));
134+
var result = new List<Detection>();
135+
foreach (var idx in keepIdx) {
136+
var detection = new Detection {
137+
rect = candidateBoxes[idx],
138+
label = candidateLabels[idx],
139+
score = candidateScores[idx]
140+
};
141+
result.Add(detection);
142+
}
128143
// Return
129144
return result.ToArray();
130145
}
146+
147+
/// <summary>
148+
/// Dispose the model and release resources.
149+
/// </summary>
150+
public void Dispose () => model.Dispose();
151+
152+
/// <summary>
153+
/// Create the NanoDet predictor.
154+
/// </summary>
155+
/// <param name="minScore">Minimum candidate score.</param>
156+
/// <param name="maxIoU">Maximum intersection-over-union score for overlap removal.</param>
157+
/// <param name="configuration">Edge model configuration.</param>
158+
/// <param name="accessKey">NatML access key.</param>
159+
public static async Task<NanoDetPredictor> Create (
160+
float minScore = 0.35f,
161+
float maxIoU = 0.5f,
162+
MLEdgeModel.Configuration configuration = null,
163+
string accessKey = null
164+
) {
165+
var model = await MLEdgeModel.Create(Tag, configuration, accessKey);
166+
var predictor = new NanoDetPredictor(model, minScore, maxIoU);
167+
return predictor;
168+
}
131169
#endregion
132170

133171

@@ -143,7 +181,18 @@ public unsafe (Rect rect, string label, float score)[] Predict (params MLFeature
143181
private readonly List<float> candidateScores;
144182
private readonly List<string> candidateLabels;
145183

146-
void IDisposable.Dispose () { } // Not used
184+
private NanoDetPredictor (MLModel model, float minScore, float maxIoU) {
185+
this.model = model as MLEdgeModel;
186+
this.minScore = minScore;
187+
this.maxIoU = maxIoU;
188+
this.inputType = model.inputs[0] as MLImageType;
189+
this.anchors8 = GenerateAnchors(inputType.width, inputType.height, 8);
190+
this.anchors16 = GenerateAnchors(inputType.width, inputType.height, 16);
191+
this.anchors32 = GenerateAnchors(inputType.width, inputType.height, 32);
192+
this.candidateBoxes = new List<Rect>();
193+
this.candidateScores = new List<float>();
194+
this.candidateLabels = new List<string>();
195+
}
147196

148197
private static Vector2[] GenerateAnchors (int width, int height, int stride) {
149198
var gridWidth = Mathf.FloorToInt((float)width / stride);

0 commit comments

Comments
 (0)