alexsuvorov commited on
Commit
2e7f9cc
·
1 Parent(s): d8735e9

Update script to Sentis 2.1.2

Browse files
Files changed (6) hide show
  1. yolov8n.onnx → Models/yolov8n.onnx +2 -2
  2. README.md +11 -14
  3. RunYOLO8n.cs +44 -62
  4. info.js +0 -5
  5. info.json +11 -2
  6. yolov8n.sentis +0 -3
yolov8n.onnx → Models/yolov8n.onnx RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:00113c3ec2b9fd39142b2adb82c0f67d694eb2856413e14b37602d77eddfea08
3
- size 6434150
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:341ad75c98ff88775c63e899e7cbbf497c13161e3393b95b620a6cab65052811
3
+ size 6435893
README.md CHANGED
@@ -2,24 +2,21 @@
2
  library_name: unity-sentis
3
  pipeline_tag: object-detection
4
  ---
5
- # YOLOv8n validated for Unity Sentis (Version 1.4.0-pre.3*)
6
- *Version 1.3.0 sentis files are not compatible with 1.4.0 and will need to be recreated/downloaded
7
 
8
- [YOLOv8n](https://docs.ultralytics.com/models/yolov8/) is a real-time multi-object recognition model confirmed to run in Unity 2023.
9
 
10
  ## How to Use
11
- First get the package `com.unity.sentis` from the package manager.
12
- You will also need the Unity UI package.
13
-
14
- * Create a new scene in Unity 2023.
15
- * Install `com.unity.sentis` version `1.4.0-pre.3` from the package manager
16
- * Add the c# script to the Main Camera.
17
- * Create a Raw Image in the scene and link it as the `displayImage`
18
- * Drag the yolov8n.sentis file into the model asset field
19
- * Drag the classes.txt on to the labelAssets field
20
- * Put a video file in the Assets/StreamingAssets folder and set the name of videoName to the filename in the script
21
- * Set the fields for the bounding box texture sprite (you can [create your own one](https://docs.unity3d.com/Manual/9SliceSprites.html) using a transparent texture or use an inbuilt one) and the font
22
 
 
 
 
 
 
 
 
 
 
23
 
24
  ## Preview
25
  If working correctly you should see something like this:
 
2
  library_name: unity-sentis
3
  pipeline_tag: object-detection
4
  ---
5
+ # YOLOv8n validated for Unity Sentis (Version 2.1.2)
 
6
 
7
+ [YOLOv8n](https://docs.ultralytics.com/models/yolov8/) is a real-time multi-object recognition model confirmed to run in Unity 6000.
8
 
9
  ## How to Use
 
 
 
 
 
 
 
 
 
 
 
10
 
11
+ * Create a new scene in Unity 6000;
12
+ * Install `com.unity.sentis` version `2.1.2` from the package manager;
13
+ * Add the `RunYOLO8n.cs` script to the Main Camera;
14
+ * Drag the `Models/yolov8n.onnx` file into the `Model Asset` field;
15
+ * Drag the `classes.txt` file into the `Classes Asset` field;
16
+ * Create a `GameObject > UI > Raw Image` object in the scene, set its width and height to 640, and link it as the `Display Image` field;
17
+ * Drag the `Border Texture.png` file into the `Border Texture` field;
18
+ * Select an appropriate font in the `Font` field;
19
+ * Put a video file in the `Assets/StreamingAssets` folder and set the `Video Filename` field to the filename of the video.
20
 
21
  ## Preview
22
  If working correctly you should see something like this:
RunYOLO8n.cs CHANGED
@@ -3,7 +3,6 @@ using Unity.Sentis;
3
  using UnityEngine;
4
  using UnityEngine.UI;
5
  using UnityEngine.Video;
6
- using Lays = Unity.Sentis.Layers;
7
  using System.IO;
8
  using FF = Unity.Sentis.Functional;
9
 
@@ -11,41 +10,37 @@ using FF = Unity.Sentis.Functional;
11
  * YOLOv8n Inference Script
12
  * ========================
13
  *
14
- * Place this script on the Main Camera.
15
- *
16
- * Place the yolob8n.sentis file in the asset folder and drag onto the asset field
17
- * Place a *.mp4 video file in the Assets/StreamingAssets folder
18
- * Create a RawImage in your scene and set it as the displayImage field
19
- * Drag the classes.txt into the labelsAsset field
20
- * Add a reference to a sprite image for the bounding box and a font for the text
21
  *
22
  */
23
 
24
-
25
  public class RunYOLO8n : MonoBehaviour
26
  {
27
- // Drag the yolov8n.sentis file here
28
- public ModelAsset asset;
29
- const string modelName = "yolov8n.sentis";
30
- // Change this to the name of the video you put in StreamingAssets folder:
31
- const string videoName = "giraffes.mp4";
32
- // Link the classes.txt here:
33
- public TextAsset labelsAsset;
34
- // Create a Raw Image in the scene and link it here:
35
  public RawImage displayImage;
36
- // Link to a bounding box sprite or texture here:
37
- public Sprite borderSprite;
38
  public Texture2D borderTexture;
39
- // Link to the font for the labels:
 
40
  public Font font;
41
 
 
 
 
42
  const BackendType backend = BackendType.GPUCompute;
43
 
44
  private Transform displayLocation;
45
- private IWorker engine;
46
  private string[] labels;
47
  private RenderTexture targetRT;
48
-
49
 
50
  //Image size for the model
51
  private const int imageWidth = 640;
@@ -60,9 +55,8 @@ public class RunYOLO8n : MonoBehaviour
60
 
61
  [SerializeField, Range(0, 1)] float iouThreshold = 0.5f;
62
  [SerializeField, Range(0, 1)] float scoreThreshold = 0.5f;
63
- int maxOutputBoxes = 64;
64
 
65
- TensorFloat centersToCorners;
66
  //bounding box data
67
  public struct BoundingBox
68
  {
@@ -80,7 +74,7 @@ public class RunYOLO8n : MonoBehaviour
80
  Screen.orientation = ScreenOrientation.LandscapeLeft;
81
 
82
  //Parse neural net labels
83
- labels = labelsAsset.text.Split('\n');
84
 
85
  LoadModel();
86
 
@@ -91,19 +85,15 @@ public class RunYOLO8n : MonoBehaviour
91
 
92
  SetupInput();
93
 
94
- if (borderSprite == null)
95
- {
96
- borderSprite = Sprite.Create(borderTexture, new Rect(0, 0, borderTexture.width, borderTexture.height), new Vector2(borderTexture.width / 2, borderTexture.height / 2));
97
- }
98
  }
99
  void LoadModel()
100
  {
101
 
102
  //Load model
103
- //var model1 = ModelLoader.Load(Path.Join(Application.streamingAssetsPath, modelName));
104
- var model1 = ModelLoader.Load(asset);
105
 
106
- centersToCorners = new TensorFloat(new TensorShape(4, 4),
107
  new float[]
108
  {
109
  1, 0, 1, 0,
@@ -113,26 +103,20 @@ public class RunYOLO8n : MonoBehaviour
113
  });
114
 
115
  //Here we transform the output of the model1 by feeding it through a Non-Max-Suppression layer.
116
- var model2 = Functional.Compile(
117
- input =>
118
- {
119
- var modelOutput = model1.Forward(input)[0];
120
- var boxCoords = modelOutput[0, 0..4, ..].Transpose(0, 1); //shape=(8400,4)
121
- var allScores = modelOutput[0, 4.., ..]; //shape=(80,8400)
122
- var scores = FF.ReduceMax(allScores, 0) - scoreThreshold; //shape=(8400)
123
- var classIDs = FF.ArgMax(allScores, 0); //shape=(8400)
124
- var boxCorners = FF.MatMul(boxCoords, FunctionalTensor.FromTensor(centersToCorners));
125
- var indices = FF.NMS(boxCorners, scores, iouThreshold); //shape=(N)
126
- var indices2 = indices.Unsqueeze(-1).BroadcastTo(new int[] { 4 });//shape=(N,4)
127
- var coords = FF.Gather(boxCoords, 0, indices2); //shape=(N,4)
128
- var labelIDs = FF.Gather(classIDs, 0, indices); //shape=(N)
129
- return (coords, labelIDs);
130
- },
131
- InputDef.FromModel(model1)[0]
132
- );
133
-
134
- //Create engine to run model
135
- engine = WorkerFactory.CreateWorker(backend, model2);
136
  }
137
 
138
  void SetupInput()
@@ -140,7 +124,7 @@ public class RunYOLO8n : MonoBehaviour
140
  video = gameObject.AddComponent<VideoPlayer>();
141
  video.renderMode = VideoRenderMode.APIOnly;
142
  video.source = VideoSource.Url;
143
- video.url = Path.Join(Application.streamingAssetsPath, videoName);
144
  video.isLooping = true;
145
  video.Play();
146
  }
@@ -167,14 +151,12 @@ public class RunYOLO8n : MonoBehaviour
167
  }
168
  else return;
169
 
170
- using var input = TextureConverter.ToTensor(targetRT, imageWidth, imageHeight, 3);
171
- engine.Execute(input);
172
-
173
- var output = engine.PeekOutput("output_0") as TensorFloat;
174
- var labelIDs = engine.PeekOutput("output_1") as TensorInt;
175
 
176
- output.CompleteOperationsAndDownload();
177
- labelIDs.CompleteOperationsAndDownload();
178
 
179
  float displayWidth = displayImage.rectTransform.rect.width;
180
  float displayHeight = displayImage.rectTransform.rect.height;
@@ -270,6 +252,6 @@ public class RunYOLO8n : MonoBehaviour
270
  private void OnDestroy()
271
  {
272
  centersToCorners?.Dispose();
273
- engine?.Dispose();
274
  }
275
- }
 
3
  using UnityEngine;
4
  using UnityEngine.UI;
5
  using UnityEngine.Video;
 
6
  using System.IO;
7
  using FF = Unity.Sentis.Functional;
8
 
 
10
  * YOLOv8n Inference Script
11
  * ========================
12
  *
13
+ * Place this script on the Main Camera and set the script parameters according to the tooltips.
 
 
 
 
 
 
14
  *
15
  */
16
 
 
17
  public class RunYOLO8n : MonoBehaviour
18
  {
19
+ [Tooltip("Drag a YOLO model .onnx file here")]
20
+ public ModelAsset modelAsset;
21
+
22
+ [Tooltip("Drag the classes.txt here")]
23
+ public TextAsset classesAsset;
24
+
25
+ [Tooltip("Create a Raw Image in the scene and link it here")]
 
26
  public RawImage displayImage;
27
+
28
+ [Tooltip("Drag a border box texture here")]
29
  public Texture2D borderTexture;
30
+
31
+ [Tooltip("Select an appropriate font for the labels")]
32
  public Font font;
33
 
34
+ [Tooltip("Change this to the name of the video you put in the Assets/StreamingAssets folder")]
35
+ public string videoFilename = "giraffes.mp4";
36
+
37
  const BackendType backend = BackendType.GPUCompute;
38
 
39
  private Transform displayLocation;
40
+ private Worker worker;
41
  private string[] labels;
42
  private RenderTexture targetRT;
43
+ private Sprite borderSprite;
44
 
45
  //Image size for the model
46
  private const int imageWidth = 640;
 
55
 
56
  [SerializeField, Range(0, 1)] float iouThreshold = 0.5f;
57
  [SerializeField, Range(0, 1)] float scoreThreshold = 0.5f;
 
58
 
59
+ Tensor<float> centersToCorners;
60
  //bounding box data
61
  public struct BoundingBox
62
  {
 
74
  Screen.orientation = ScreenOrientation.LandscapeLeft;
75
 
76
  //Parse neural net labels
77
+ labels = classesAsset.text.Split('\n');
78
 
79
  LoadModel();
80
 
 
85
 
86
  SetupInput();
87
 
88
+ borderSprite = Sprite.Create(borderTexture, new Rect(0, 0, borderTexture.width, borderTexture.height), new Vector2(borderTexture.width / 2, borderTexture.height / 2));
 
 
 
89
  }
90
  void LoadModel()
91
  {
92
 
93
  //Load model
94
+ var model1 = ModelLoader.Load(modelAsset);
 
95
 
96
+ centersToCorners = new Tensor<float>(new TensorShape(4, 4),
97
  new float[]
98
  {
99
  1, 0, 1, 0,
 
103
  });
104
 
105
  //Here we transform the output of the model1 by feeding it through a Non-Max-Suppression layer.
106
+ var graph = new FunctionalGraph();
107
+ var inputs = graph.AddInputs(model1);
108
+ var modelOutput = FF.Forward(model1, inputs)[0]; //shape=(1,84,8400)
109
+ var boxCoords = modelOutput[0, 0..4, ..].Transpose(0, 1); //shape=(8400,4)
110
+ var allScores = modelOutput[0, 4.., ..]; //shape=(80,8400)
111
+ var scores = FF.ReduceMax(allScores, 0); //shape=(8400)
112
+ var classIDs = FF.ArgMax(allScores, 0); //shape=(8400)
113
+ var boxCorners = FF.MatMul(boxCoords, FF.Constant(centersToCorners)); //shape=(8400,4)
114
+ var indices = FF.NMS(boxCorners, scores, iouThreshold, scoreThreshold); //shape=(N)
115
+ var coords = FF.IndexSelect(boxCoords, 0, indices); //shape=(N,4)
116
+ var labelIDs = FF.IndexSelect(classIDs, 0, indices); //shape=(N)
117
+
118
+ //Create worker to run model
119
+ worker = new Worker(graph.Compile(coords, labelIDs), backend);
 
 
 
 
 
 
120
  }
121
 
122
  void SetupInput()
 
124
  video = gameObject.AddComponent<VideoPlayer>();
125
  video.renderMode = VideoRenderMode.APIOnly;
126
  video.source = VideoSource.Url;
127
+ video.url = Path.Join(Application.streamingAssetsPath, videoFilename);
128
  video.isLooping = true;
129
  video.Play();
130
  }
 
151
  }
152
  else return;
153
 
154
+ using Tensor<float> inputTensor = new Tensor<float>(new TensorShape(1, 3, imageHeight, imageWidth));
155
+ TextureConverter.ToTensor(targetRT, inputTensor, default);
156
+ worker.Schedule(inputTensor);
 
 
157
 
158
+ using var output = (worker.PeekOutput("output_0") as Tensor<float>).ReadbackAndClone();
159
+ using var labelIDs = (worker.PeekOutput("output_1") as Tensor<int>).ReadbackAndClone();
160
 
161
  float displayWidth = displayImage.rectTransform.rect.width;
162
  float displayHeight = displayImage.rectTransform.rect.height;
 
252
  private void OnDestroy()
253
  {
254
  centersToCorners?.Dispose();
255
+ worker?.Dispose();
256
  }
257
+ }
info.js DELETED
@@ -1,5 +0,0 @@
1
- {
2
- "version" : [
3
- "1.4.0-pre.2"
4
- ]
5
- }
 
 
 
 
 
 
info.json CHANGED
@@ -1,5 +1,14 @@
1
  {
2
- "version" : [
3
- "1.3.0-pre.3"
 
 
 
 
 
 
 
 
 
4
  ]
5
  }
 
1
  {
2
+ "code": [
3
+ "RunYOLO8n.cs"
4
+ ],
5
+ "models": [
6
+ "yolov8n.onnx"
7
+ ],
8
+ "data": [
9
+ "classes.txt"
10
+ ],
11
+ "version": [
12
+ "2.1.2"
13
  ]
14
  }
yolov8n.sentis DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:72c2ccde7dedd160cd8b62907ff2fa06ffe594d4a0fe0d2b13eb270297ca455c
3
- size 12834028