UnityPaul commited on
Commit
2e7d061
·
verified ·
1 Parent(s): 1ed5800

Upload 4 files

Browse files
Files changed (4) hide show
  1. README.md +9 -12
  2. RunBlazePalm.cs +72 -68
  3. info.js +1 -1
  4. palm_detection_lite.sentis +2 -2
README.md CHANGED
@@ -4,26 +4,23 @@ library_name: unity-sentis
4
  pipeline_tag: object-detection
5
  ---
6
 
7
- # Blaze Palm palm detector in Unity Sentis Format (Version 1.3.0-pre.3*)
8
- *Sentis files from 1.4.0 are not compatible with 1.3.0 and above and need to be recreated/downloaded
9
 
10
- This is the Blaze Palm model, part of the [MediaPipe hand detection](https://developers.google.com/mediapipe/solutions/vision/hand_landmarker) formatted to work in Unity Sentis 2023
11
 
12
  ## How to Use
13
  * Create a new scene in Unity 2023
14
- * Install package `com.unity.sentis` version `1.3.0-pre.3` from the package manager
15
- * Put the hand_detection_lite.sentis file in the Assets/StreamingAssets folder
16
- * Put a video in the Assets/StreamingAssets folder and set `videoName` variable to the video name
17
- * Create a RawImage and place it in your scene. Link to this image in the `previewUI` field.
18
- * Attach a sprite for the bounding box image to the `boundingBoxTexture` field
19
 
20
  ## Preview
21
  When you get it working you should see something like this:
22
 
23
- ![preview](blaze_palm_preview.png)
24
-
25
- ## Information
26
- This model may have some accuracy issues.
27
 
28
  ## Unity Sentis
29
  Sentis is the inference engine for Unity 2023. More information can be found [here](https://unity.com/products/sentis)
 
4
  pipeline_tag: object-detection
5
  ---
6
 
7
+ # Blaze Face face detector in Unity Sentis (Version 1.4.0-pre.3*)
8
+ *Version 1.3.0 sentis files are not compatible with 1.4.0 and will need to be recreated/downloaded
9
 
10
+ This is the [Blaze Face model](https://developers.google.com/mediapipe/solutions/vision/face_detector) formatted to work in Unity Sentis 2023
11
 
12
  ## How to Use
13
  * Create a new scene in Unity 2023
14
+ * Install `com.unity.sentis` version `1.4.0-pre.3` from the package manager
15
+ * Drag the blazeface.sentis file into the model asset field
16
+ * Put a video in the Assets/StreamingAssets folder and set _videoName variable to the video name
17
+ * Create a RawImage and place it in your scene. Link to this image in the _previewUI field.
18
+ * Attach a sprite or texture for the bounding box image to the BondingBoxSprite or BorderTexture field
19
 
20
  ## Preview
21
  When you get it working you should see something like this:
22
 
23
+ ![preview](blaze_preview.png)
 
 
 
24
 
25
  ## Unity Sentis
26
  Sentis is the inference engine for Unity 2023. More information can be found [here](https://unity.com/products/sentis)
RunBlazePalm.cs CHANGED
@@ -3,6 +3,7 @@ using Unity.Sentis;
3
  using UnityEngine.Video;
4
  using UnityEngine.UI;
5
  using Lays = Unity.Sentis.Layers;
 
6
 
7
  /*
8
  * Blaze Palm Inference
@@ -22,11 +23,13 @@ using Lays = Unity.Sentis.Layers;
22
 
23
  public class RunBlazePalm : MonoBehaviour
24
  {
 
25
  //Drag a link to a raw image here:
26
  public RawImage previewUI = null;
27
 
28
  // Put your bounding box sprite image here
29
- public Sprite boundingBoxTexture;
 
30
 
31
  // optional images for palm markers
32
  public Sprite[] markerTextures;
@@ -58,9 +61,6 @@ public class RunBlazePalm : MonoBehaviour
58
  //Holds image size
59
  int size;
60
 
61
- Ops ops;
62
- ITensorAllocator allocator;
63
-
64
  Model model;
65
 
66
  //webcam device name:
@@ -68,8 +68,8 @@ public class RunBlazePalm : MonoBehaviour
68
 
69
  bool closing = false;
70
 
71
- const string regressorsOutput = "Identity";
72
- const string classificatorsOutput = "Identity_1";
73
 
74
  public struct BoundingBox
75
  {
@@ -81,8 +81,6 @@ public class RunBlazePalm : MonoBehaviour
81
 
82
  void Start()
83
  {
84
- allocator = new TensorCachingAllocator();
85
-
86
  //(Note: if using a webcam on mobile get permissions here first)
87
 
88
  targetTexture = new RenderTexture(resolution.x, resolution.y, 0);
@@ -93,6 +91,13 @@ public class RunBlazePalm : MonoBehaviour
93
  SetupModel();
94
 
95
  SetupEngine();
 
 
 
 
 
 
 
96
  }
97
 
98
  void SetupInput()
@@ -179,6 +184,15 @@ public class RunBlazePalm : MonoBehaviour
179
  }
180
 
181
 
 
 
 
 
 
 
 
 
 
182
  void AddGrid(float[] offsets, int rows, int repeats, int cellWidth, ref int n)
183
  {
184
  for (int j = 0; j < repeats * rows * rows; j++)
@@ -189,51 +203,52 @@ public class RunBlazePalm : MonoBehaviour
189
  }
190
  }
191
 
192
- float[] GetGridBoxCoords()
193
- {
194
- var offsets = new float[2016 * 4];
195
- int n = 0;
196
- AddGrid(offsets, 24, 2, 8, ref n);
197
- AddGrid(offsets, 12, 6, 16, ref n);
198
- return offsets;
199
- }
200
 
201
  void SetupModel()
202
  {
203
  float[] offsets = GetGridBoxCoords();
204
 
205
- model = ModelLoader.Load(Application.streamingAssetsPath + "/palm_detection_lite.sentis");
 
206
 
207
  //We need to add extra layers to the model in order to aggregate the box predicions:
208
  size = model.inputs[0].shape.ToTensorShape()[2]; // Input tensor width (192)
209
 
210
- //set constants
211
- model.AddConstant(new Lays.Constant("0", new int[] { 0 }));
212
- model.AddConstant(new Lays.Constant("2", new int[] { 2 }));
213
- model.AddConstant(new Lays.Constant("4", new int[] { 4 }));
214
- model.AddConstant(new Lays.Constant("maxOutputBoxes", new int[] { maxOutputBoxes }));
215
- model.AddConstant(new Lays.Constant("iouThreshold", new float[] { iouThreshold }));
216
- model.AddConstant(new Lays.Constant("scoreThreshold", new float[] { scoreThreshold }));
217
- model.AddConstant(new Lays.Constant("offsets",
218
- new TensorFloat(new TensorShape(1, offsets.Length / 4, 4), offsets)
219
- ));
220
-
221
- //add layers
222
- model.AddLayer(new Lays.Slice("boxes", regressorsOutput, "0", "4", "2"));
223
- model.AddLayer(new Lays.Transpose("scores", classificatorsOutput, new int[] { 0, 2, 1 }));
224
- model.AddLayer(new Lays.Add("boxCoords", "boxes", "offsets"));
225
- model.AddOutput("boxCoords");
226
-
227
- model.AddLayer(new Lays.NonMaxSuppression("NMS", "boxCoords", "scores",
228
- "maxOutputBoxes", "iouThreshold", "scoreThreshold",
229
- centerPointBox: Lays.CenterPointBox.Center
230
- ));
231
- model.AddOutput("NMS");
 
 
 
 
 
 
 
 
 
232
  }
233
  public void SetupEngine()
234
  {
235
- worker = WorkerFactory.CreateWorker(backend, model);
236
- ops = WorkerFactory.CreateOps(backend, allocator);
237
  }
238
 
239
  void DrawPalms(TensorFloat index3, TensorFloat regressors, int NMAX, Vector2 scale)
@@ -243,12 +258,12 @@ public class RunBlazePalm : MonoBehaviour
243
  //Draw bounding box of the palm
244
  var box = new BoundingBox
245
  {
246
- centerX = index3[0, n, 0] * scale.x,
247
- centerY = index3[0, n, 1] * scale.y,
248
- width = index3[0, n, 2] * scale.x,
249
- height = index3[0, n, 3] * scale.y
250
  };
251
- DrawBox(box, boundingBoxTexture);
252
  if (regressors == null) continue;
253
 
254
  //Draw markers starts of fingers
@@ -256,12 +271,12 @@ public class RunBlazePalm : MonoBehaviour
256
  {
257
  var marker = new BoundingBox
258
  {
259
- centerX = box.centerX + (regressors[0, n, 4 + j * 2] - regressors[0, n, 0]) * scale.x,
260
- centerY = box.centerY + (regressors[0, n, 4 + j * 2 + 1] - regressors[0, n, 1]) * scale.y,
261
  width = 4f * scale.x,
262
  height = 4f * scale.y,
263
  };
264
- DrawBox(marker, j < markerTextures.Length ? markerTextures[j] : boundingBoxTexture);
265
  }
266
  }
267
  }
@@ -271,26 +286,15 @@ public class RunBlazePalm : MonoBehaviour
271
  var transform = new TextureTransform();
272
  transform.SetDimensions(size, size, 3);
273
  transform.SetTensorLayout(0, 3, 1, 2);
274
- using var image0 = TextureConverter.ToTensor(source, transform);
275
-
276
- // Pre-process the image to make input in range (-1..1)
277
- //using var image = ops.Mad(image0, 2f, -1f);
278
-
279
- worker.Execute(image0);
280
-
281
- using var boxCoords = worker.PeekOutput("boxCoords") as TensorFloat; //palm coords
282
- using var regressors = worker.PeekOutput(regressorsOutput) as TensorFloat; //contains markers
283
-
284
- var NMS = worker.PeekOutput("NMS") as TensorInt;
285
 
286
- using var boxCoords2 = boxCoords.ShallowReshape(boxCoords.shape.Unsqueeze(0)) as TensorFloat;
287
- using var output = ops.GatherND(boxCoords2, NMS, 0);
288
 
289
- using var regressors2 = regressors.ShallowReshape(regressors.shape.Unsqueeze(0)) as TensorFloat;
290
- using var markersOutput = ops.GatherND(regressors2, NMS, 0);
291
 
292
- output.MakeReadable();
293
- markersOutput.MakeReadable();
294
 
295
  ClearAnnotations();
296
 
@@ -327,9 +331,9 @@ public class RunBlazePalm : MonoBehaviour
327
 
328
  void CleanUp()
329
  {
 
 
330
  closing = true;
331
- ops?.Dispose();
332
- allocator?.Dispose();
333
  if (webcam) Destroy(webcam);
334
  if (video) Destroy(video);
335
  RenderTexture.active = null;
 
3
  using UnityEngine.Video;
4
  using UnityEngine.UI;
5
  using Lays = Unity.Sentis.Layers;
6
+ using FF = Unity.Sentis.Functional;
7
 
8
  /*
9
  * Blaze Palm Inference
 
23
 
24
  public class RunBlazePalm : MonoBehaviour
25
  {
26
+ public ModelAsset asset;
27
  //Drag a link to a raw image here:
28
  public RawImage previewUI = null;
29
 
30
  // Put your bounding box sprite image here
31
+ public Texture2D boundingBoxTexture;
32
+ public Sprite boundingBoxSprite;
33
 
34
  // optional images for palm markers
35
  public Sprite[] markerTextures;
 
61
  //Holds image size
62
  int size;
63
 
 
 
 
64
  Model model;
65
 
66
  //webcam device name:
 
68
 
69
  bool closing = false;
70
 
71
+
72
+ TensorFloat anchors, centersToCorners;
73
 
74
  public struct BoundingBox
75
  {
 
81
 
82
  void Start()
83
  {
 
 
84
  //(Note: if using a webcam on mobile get permissions here first)
85
 
86
  targetTexture = new RenderTexture(resolution.x, resolution.y, 0);
 
91
  SetupModel();
92
 
93
  SetupEngine();
94
+
95
+ if (boundingBoxSprite == null)
96
+ {
97
+ boundingBoxSprite = Sprite.Create(boundingBoxTexture,
98
+ new Rect(0, 0, boundingBoxTexture.width, boundingBoxTexture.height),
99
+ new Vector2(boundingBoxTexture.width / 2, boundingBoxTexture.height / 2));
100
+ }
101
  }
102
 
103
  void SetupInput()
 
184
  }
185
 
186
 
187
+
188
+ float[] GetGridBoxCoords()
189
+ {
190
+ var offsets = new float[2016 * 4];
191
+ int n = 0;
192
+ AddGrid(offsets, 24, 2, 8, ref n);
193
+ AddGrid(offsets, 12, 6, 16, ref n);
194
+ return offsets;
195
+ }
196
  void AddGrid(float[] offsets, int rows, int repeats, int cellWidth, ref int n)
197
  {
198
  for (int j = 0; j < repeats * rows * rows; j++)
 
203
  }
204
  }
205
 
 
 
 
 
 
 
 
 
206
 
207
  void SetupModel()
208
  {
209
  float[] offsets = GetGridBoxCoords();
210
 
211
+ model = ModelLoader.Load(asset);
212
+ //model = ModelLoader.Load(Application.streamingAssetsPath + "/palm_detection_lite.sentis");
213
 
214
  //We need to add extra layers to the model in order to aggregate the box predicions:
215
  size = model.inputs[0].shape.ToTensorShape()[2]; // Input tensor width (192)
216
 
217
+ anchors = new TensorFloat(new TensorShape(offsets.Length / 4, 4), offsets);
218
+
219
+ centersToCorners = new TensorFloat(new TensorShape(4, 4),
220
+ new float[]
221
+ {
222
+ 1, 0, 1, 0,
223
+ 0, 1, 0, 1,
224
+ -0.5f, 0, 0.5f, 0,
225
+ 0, -0.5f, 0, 0.5f
226
+ });
227
+
228
+ var model2 = Functional.Compile(
229
+ input =>
230
+ {
231
+ var outputs = model.Forward(input);
232
+ var regressors = outputs[1][0]; //shape=(2016,18)
233
+ var scores = outputs[0][0].Transpose(0, 1) - scoreThreshold; //shape=(1,2016)
234
+ var boxCoords = regressors[.., 0..4] + FunctionalTensor.FromTensor(anchors); //(2016,4)
235
+ var boxCorners = FF.MatMul(boxCoords, FunctionalTensor.FromTensor(centersToCorners));
236
+ var indices = FF.NMS(boxCoords, scores, iouThreshold); //shape=(N)
237
+ var indices2 = indices.Unsqueeze(-1).BroadcastTo(new int[] { 4 }); //shape=(N,4)
238
+ var output = FF.Gather(boxCoords, 0, indices2); //shape=(N,4)
239
+ var indices3 = indices.Unsqueeze(-1).BroadcastTo(new int[] { 18 }); //shape=(N,18)
240
+ var markersOutput = FF.Gather(regressors, 0, indices3); //shape=(N,18)
241
+ return (output, markersOutput);
242
+ },
243
+ InputDef.FromModel(model)[0]
244
+ );
245
+
246
+ worker = WorkerFactory.CreateWorker(backend, model2);
247
+
248
  }
249
  public void SetupEngine()
250
  {
251
+
 
252
  }
253
 
254
  void DrawPalms(TensorFloat index3, TensorFloat regressors, int NMAX, Vector2 scale)
 
258
  //Draw bounding box of the palm
259
  var box = new BoundingBox
260
  {
261
+ centerX = index3[n, 0] * scale.x,
262
+ centerY = index3[n, 1] * scale.y,
263
+ width = index3[n, 2] * scale.x,
264
+ height = index3[n, 3] * scale.y
265
  };
266
+ DrawBox(box, boundingBoxSprite);
267
  if (regressors == null) continue;
268
 
269
  //Draw markers starts of fingers
 
271
  {
272
  var marker = new BoundingBox
273
  {
274
+ centerX = box.centerX + (regressors[n, 4 + j * 2] - regressors[n, 0]) * scale.x,
275
+ centerY = box.centerY + (regressors[n, 4 + j * 2 + 1] - regressors[n, 1]) * scale.y,
276
  width = 4f * scale.x,
277
  height = 4f * scale.y,
278
  };
279
+ DrawBox(marker, j < markerTextures.Length ? markerTextures[j] : boundingBoxSprite);
280
  }
281
  }
282
  }
 
286
  var transform = new TextureTransform();
287
  transform.SetDimensions(size, size, 3);
288
  transform.SetTensorLayout(0, 3, 1, 2);
289
+ using var image = TextureConverter.ToTensor(source, transform);
 
 
 
 
 
 
 
 
 
 
290
 
291
+ worker.Execute(image);
 
292
 
293
+ var output = worker.PeekOutput("output_0") as TensorFloat;
294
+ var markersOutput = worker.PeekOutput("output_1") as TensorFloat;
295
 
296
+ output.CompleteOperationsAndDownload();
297
+ markersOutput.CompleteOperationsAndDownload();
298
 
299
  ClearAnnotations();
300
 
 
331
 
332
  void CleanUp()
333
  {
334
+ anchors?.Dispose();
335
+ centersToCorners?.Dispose();
336
  closing = true;
 
 
337
  if (webcam) Destroy(webcam);
338
  if (video) Destroy(video);
339
  RenderTexture.active = null;
info.js CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "version" : [
3
- "1.3.0-pre.3"
4
  ]
5
 
6
  }
 
1
  {
2
  "version" : [
3
+ "1.4.0-pre.3"
4
  ]
5
 
6
  }
palm_detection_lite.sentis CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:9d1746c58054f5419c994d8869e7945dd074d34bbedb27b518cb4d106447973b
3
- size 3953743
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1598c7c4afc1bfccab382c69e43aaf5c7b099fb4a35f77a8ad32014656b0f6e4
3
+ size 3892980