Serotina commited on
Commit
041b65b
·
1 Parent(s): 021a45a

Update .gitattributes

Browse files
Files changed (9) hide show
  1. .gitattributes +1 -0
  2. .gitignore +1 -0
  3. Border Texture.png +0 -0
  4. README.md +42 -0
  5. classes.txt +80 -0
  6. preview.png +0 -0
  7. yolo.cs +238 -0
  8. yolov8n.onnx +3 -0
  9. yolov8n.sentis +3 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ yolov8n.sentis filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ *.meta
Border Texture.png ADDED
README.md ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ pipeline_tag: object-detection
3
+ ---
4
+
5
+
6
+ # YOLOv8n validated for Unity Sentis (Version 1.4.0-pre.3*)
7
+
8
+ This is Yolov8n object detection example code for unity sentis, not real-time inference, for instance image.
9
+
10
+ ** this is almost same code with ref, but only for image. **
11
+
12
+ ref: https://huggingface.co/unity/sentis-YOLOv8n
13
+
14
+ [YOLOv8n](https://docs.ultralytics.com/models/yolov8/) is a real-time multi-object recognition model confirmed to run in Unity 2023.
15
+
16
+ ## How to Use
17
+ First get the package `com.unity.sentis` from the package manager.
18
+ You will also need the Unity UI package.
19
+
20
+ * Create a new scene in Unity 2023 or higher (include in Unity 6000).
21
+ * Install `com.unity.sentis` version `1.4.0-pre.3` from the package manager
22
+ * Add the c# script to the Main Camera.
23
+ * Create a Raw Image in the scene and link it as the `displayImage`
24
+ * Drag the yolov8n.sentis or yolov8n.onnx file into the model asset field
25
+ * Drag the classes.txt on to the labelAssets field
26
+ * Place a *.png image file in the Assets folder and drag onto Input Texture field
27
+ * 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
28
+
29
+
30
+ ## Preview
31
+ If working correctly you should see something like this:
32
+
33
+ ![preview](preview.png)
34
+
35
+ ## Information
36
+ The NMS selection will be improved in later versions of Sentis. Currently uses singular-class approach.
37
+
38
+ ## Unity Sentis
39
+ Unity Sentis is the inference engine that runs in Unity 3D. More information can be found at [here](https://unity.com/products/sentis)
40
+
41
+ ## License
42
+ The YOLO models use the GPLv3 license.
classes.txt ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ person
2
+ bicycle
3
+ car
4
+ motorbike
5
+ aeroplane
6
+ bus
7
+ train
8
+ truck
9
+ boat
10
+ traffic light
11
+ fire hydrant
12
+ stop sign
13
+ parking meter
14
+ bench
15
+ bird
16
+ cat
17
+ dog
18
+ horse
19
+ sheep
20
+ cow
21
+ elephant
22
+ bear
23
+ zebra
24
+ giraffe
25
+ backpack
26
+ umbrella
27
+ handbag
28
+ tie
29
+ suitcase
30
+ frisbee
31
+ skis
32
+ snowboard
33
+ sports ball
34
+ kite
35
+ baseball bat
36
+ baseball glove
37
+ skateboard
38
+ surfboard
39
+ tennis racket
40
+ bottle
41
+ wine glass
42
+ cup
43
+ fork
44
+ knife
45
+ spoon
46
+ bowl
47
+ banana
48
+ apple
49
+ sandwich
50
+ orange
51
+ broccoli
52
+ carrot
53
+ hot dog
54
+ pizza
55
+ donut
56
+ cake
57
+ chair
58
+ sofa
59
+ potted plant
60
+ bed
61
+ dining table
62
+ toilet
63
+ tv monitor
64
+ laptop
65
+ mouse
66
+ remote
67
+ keyboard
68
+ cell phone
69
+ microwave
70
+ oven
71
+ toaster
72
+ sink
73
+ refrigerator
74
+ book
75
+ clock
76
+ vase
77
+ scissors
78
+ teddy bear
79
+ hair drier
80
+ toothbrush
preview.png ADDED
yolo.cs ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System.Collections.Generic;
2
+ using Unity.Sentis;
3
+ using UnityEngine;
4
+ using UnityEngine.UI;
5
+ using UnityEngine.Video;
6
+ using FF = Unity.Sentis.Functional;
7
+
8
+ /*
9
+ * YOLOv8n Inference Script
10
+ * ========================
11
+ *
12
+ * This is YOLOv8n's Instance image version.
13
+ * Almost same code, but image. ref: https://huggingface.co/unity/sentis-YOLOv8n
14
+ *
15
+ * Place this script on the Main Camera.
16
+ *
17
+ * Place the yolob8n.sentis file in the asset folder and drag onto the asset field
18
+ * Place a *.png image file in the Assets folder and drag onto Input Texture field
19
+ * Create a RawImage in your scene and set it as the displayImage field
20
+ * Drag the classes.txt into the labelsAsset field
21
+ * Set Border Sprite to UIMask
22
+ * Add a reference to a sprite image for the bounding box and a font for the text
23
+ *
24
+ */
25
+ public class yolo : MonoBehaviour
26
+ {
27
+ public ModelAsset modelAsset;
28
+ public TextAsset labelsAsset;
29
+ public RawImage displayImage;
30
+ public Sprite borderSprite;
31
+ public Texture2D borderTexture;
32
+ public Texture2D inputTexture;
33
+ public Font font;
34
+
35
+ private Transform displayLocation;
36
+ private string[] labels;
37
+ private Model model;
38
+ private IWorker engine;
39
+ private RenderTexture targetRT;
40
+ private TensorFloat inputTensor;
41
+ private const BackendType backend = BackendType.GPUCompute;
42
+
43
+ // Image Size for model
44
+ private const int imageWidth = 640;
45
+ private const int imageHeight = 640;
46
+
47
+ List<GameObject> boxPool = new List<GameObject>();
48
+ TensorFloat centersToCorners;
49
+
50
+ [SerializeField, Range(0, 1)] float iouThreshold = 0.5f;
51
+ [SerializeField, Range(0, 1)] float scoreThreshold = 0.5f;
52
+ public struct BoundingBox
53
+ {
54
+ public float centerX;
55
+ public float centerY;
56
+ public float width;
57
+ public float height;
58
+ public string label;
59
+ }
60
+
61
+ void Start()
62
+ {
63
+ labels = labelsAsset.text.Split('\n');
64
+
65
+ // Load Model
66
+ LoadModel();
67
+
68
+ displayLocation = displayImage.transform;
69
+
70
+ SetupInput();
71
+
72
+ if (borderSprite == null)
73
+ {
74
+ borderSprite = Sprite.Create(borderTexture, new Rect(0, 0, borderTexture.width, borderTexture.height), new Vector2(borderTexture.width / 2, borderTexture.height / 2));
75
+ }
76
+
77
+ ExecuteML();
78
+ }
79
+
80
+ // Update is called once per frame
81
+
82
+ void LoadModel()
83
+ {
84
+
85
+ // Load model
86
+ var model1 = ModelLoader.Load(modelAsset);
87
+
88
+ centersToCorners = new TensorFloat(new TensorShape(4, 4),
89
+ new float[]
90
+ {
91
+ 1, 0, 1, 0,
92
+ 0, 1, 0, 1,
93
+ -0.5f, 0, 0.5f, 0,
94
+ 0, -0.5f, 0, 0.5f
95
+ });
96
+
97
+ //Here we transform the output of the model1 by feeding it through a Non-Max-Suppression layer.
98
+ var model2 = Functional.Compile(
99
+ input =>
100
+ {
101
+ var modelOutput = model1.Forward(input)[0];
102
+ var boxCoords = modelOutput[0, 0..4, ..].Transpose(0, 1); //shape=(8400,4)
103
+ var allScores = modelOutput[0, 4.., ..]; //shape=(80,8400)
104
+ var scores = FF.ReduceMax(allScores, 0) - scoreThreshold; //shape=(8400)
105
+ var classIDs = FF.ArgMax(allScores, 0); //shape=(8400)
106
+ var boxCorners = FF.MatMul(boxCoords, FunctionalTensor.FromTensor(centersToCorners));
107
+ var indices = FF.NMS(boxCorners, scores, iouThreshold); //shape=(N)
108
+ var indices2 = indices.Unsqueeze(-1).BroadcastTo(new int[] { 4 });//shape=(N,4)
109
+ var coords = FF.Gather(boxCoords, 0, indices2); //shape=(N,4)
110
+ var labelIDs = FF.Gather(classIDs, 0, indices); //shape=(N)
111
+ return (coords, labelIDs);
112
+ },
113
+ InputDef.FromModel(model1)[0]
114
+ );
115
+
116
+ //Create engine to run model
117
+ engine = WorkerFactory.CreateWorker(backend, model2);
118
+ }
119
+
120
+
121
+ void SetupInput()
122
+ {
123
+ inputTensor = TextureConverter.ToTensor(inputTexture, imageWidth, imageHeight);
124
+ }
125
+
126
+ public void ExecuteML()
127
+ {
128
+ displayImage.texture = inputTexture;
129
+
130
+ engine.Execute(inputTensor);
131
+
132
+ var output = engine.PeekOutput("output_0") as TensorFloat;
133
+ var labelIDs = engine.PeekOutput("output_1") as TensorInt;
134
+
135
+ output.CompleteOperationsAndDownload();
136
+ labelIDs.CompleteOperationsAndDownload();
137
+
138
+ float displayWidth = displayImage.rectTransform.rect.width;
139
+ float displayHeight = displayImage.rectTransform.rect.height;
140
+
141
+ float scaleX = displayWidth / imageWidth;
142
+ float scaleY = displayHeight / imageHeight;
143
+
144
+ int foundBoxes = output.shape[0];
145
+
146
+ //Draw the bounding boxes
147
+ for (int n = 0; n < foundBoxes; n++)
148
+ {
149
+ var box = new BoundingBox
150
+ {
151
+ centerX = output[n, 0] * scaleX - displayWidth / 2,
152
+ centerY = output[n, 1] * scaleY - displayHeight / 2,
153
+ width = output[n, 2] * scaleX,
154
+ height = output[n, 3] * scaleY,
155
+ label = labels[labelIDs[n]],
156
+ };
157
+
158
+ // It's for Debug
159
+ Debug.Log(box.label);
160
+
161
+ DrawBox(box, n, displayHeight * 0.05f);
162
+ }
163
+ }
164
+ public void DrawBox(BoundingBox box, int id, float fontSize)
165
+ {
166
+ //Create the bounding box graphic or get from pool
167
+ GameObject panel;
168
+ if (id < boxPool.Count)
169
+ {
170
+ panel = boxPool[id];
171
+ panel.SetActive(true);
172
+ }
173
+ else
174
+ {
175
+ panel = CreateNewBox(Color.yellow);
176
+ }
177
+ //Set box position
178
+ panel.transform.localPosition = new Vector3(box.centerX, -box.centerY);
179
+
180
+ //Set box size
181
+ RectTransform rt = panel.GetComponent<RectTransform>();
182
+ rt.sizeDelta = new Vector2(box.width, box.height);
183
+
184
+ //Set label text
185
+ var label = panel.GetComponentInChildren<Text>();
186
+ label.text = box.label;
187
+ label.fontSize = (int)fontSize;
188
+ }
189
+
190
+ public GameObject CreateNewBox(Color color)
191
+ {
192
+ //Create the box and set image
193
+
194
+ var panel = new GameObject("ObjectBox");
195
+ panel.AddComponent<CanvasRenderer>();
196
+ Image img = panel.AddComponent<Image>();
197
+ img.color = color;
198
+ img.sprite = borderSprite;
199
+ img.type = Image.Type.Sliced;
200
+ panel.transform.SetParent(displayLocation, false);
201
+
202
+ //Create the label
203
+
204
+ var text = new GameObject("ObjectLabel");
205
+ text.AddComponent<CanvasRenderer>();
206
+ text.transform.SetParent(panel.transform, false);
207
+ Text txt = text.AddComponent<Text>();
208
+ txt.font = font;
209
+ txt.color = color;
210
+ txt.fontSize = 40;
211
+ txt.horizontalOverflow = HorizontalWrapMode.Overflow;
212
+
213
+ RectTransform rt2 = text.GetComponent<RectTransform>();
214
+ rt2.offsetMin = new Vector2(20, rt2.offsetMin.y);
215
+ rt2.offsetMax = new Vector2(0, rt2.offsetMax.y);
216
+ rt2.offsetMin = new Vector2(rt2.offsetMin.x, 0);
217
+ rt2.offsetMax = new Vector2(rt2.offsetMax.x, 30);
218
+ rt2.anchorMin = new Vector2(0, 0);
219
+ rt2.anchorMax = new Vector2(1, 1);
220
+
221
+ boxPool.Add(panel);
222
+ return panel;
223
+ }
224
+
225
+ public void ClearAnnotations()
226
+ {
227
+ foreach (var box in boxPool)
228
+ {
229
+ box.SetActive(false);
230
+ }
231
+ }
232
+
233
+ private void OnDestroy()
234
+ {
235
+ centersToCorners?.Dispose();
236
+ engine?.Dispose();
237
+ }
238
+ }
yolov8n.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:15504f8b73630dd71768e776474262ba0d9fc472820601b1ac1528bdb6cfec95
3
+ size 12823637
yolov8n.sentis ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a6d067ead11259acbf633be97f7780ac1c1b68ef7a1851959c79254d940de9f3
3
+ size 12834372