Unity Barracuda やーる

# はじめに
けいじろう先生の[Unity Barracuda 関連レポジトリ](https://github.com/keijiro?tab=repositories&q=Barracuda&type=&language=&sort=)をやっていきます

# 開発環境
- Unity 2020.3.0f1
- [Windows 10 PC](https://twitter.com/sotongshi/status/1317758401946947591?s=20)

# [ニューラルネットで何でもできちゃう！？ Unity Barracudaで遊ぼう！ - Unityステーション](https://www.youtube.com/watch?v=5oKgj8q83ec)

### メモ
- ONNXに対応した推論ができる
- NNCam ウェブ会議でよく使う
- FaceMesh 
- UnityLabsのstyle-transfer 
- waifu2x アニメの超解像
- UltraFace 正面顔のみ
- BrazeFace 少人数高速
- TinyYOLOv2 物体検出

### ONNXのモデルリスト
- [ONNX公式のモデル](https://github.com/onnx/models)
- [PINTOさんのモデル](https://github.com/PINTO0309/PINTO_model_zoo)
- [axincのモデル](https://github.com/axinc-ai/ailia-models)

### MNIST
- ONNXをドラッグドロップしたら ONNX インポーター動く
- ONNXの中身見れる
- 画像をアタッチして再生、推論スコアが見れる（MNISTTest.cs）
- import Unity.Barracuda
- NNModelクラス
- Tensor 多次元配列
- 1,y,x,gray
- unity 上下反転
- inspectorにインプット、アウトプットの形見える
- ModelLoader CreateWorker
- worker.Execute(input)
- worker.PeekOutput
- SoftMax で 0~1に正規化したスコアを表示する
- forとGetPixelしていて遅い ここだけCPUで計算していて ModelのところがGPU、遅い
- TinyYoloV2を見たら工夫しているよ
- ComputeShaderで計算している
- Textureで参照
- NMS 重なった矩形を一つにするやつ、シェーダーで書いている！
- 検出から描画までGPUでやっている

# Body Tracking 
### [SelfieBarracuda](https://github.com/keijiro/SelfieBarracuda)
### [NNCam2](https://github.com/keijiro/NNCam2)
### [BodyPixBarracuda](https://github.com/keijiro/BodyPixBarracuda)

Unity2021.2.0b4 → Unity2020.3.0f1で動作確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/1fc8c9c1-e6f2-a703-aa4a-0f111afb07ff.png)

WebCamからも使える（50FPSくらい）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/02dad0d0-15a3-26b4-3001-7c168a02f9d6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/76116c65-b11e-bd1b-b4f8-8d53f29056dd.png)

### [NNCam](https://github.com/keijiro/NNCam)

# Object Detection
### [YoloV4TinyBarracuda](https://github.com/keijiro/YoloV4TinyBarracuda)

Unity2021.2.0b3 → Unity2020.3.0f1で動作確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/a458b5ee-a790-3f99-276f-197bb8fbc563.png)

WebCamからもできる（30FPSくらい）

### [TinyYOLOv2Barracuda](https://github.com/keijiro/TinyYOLOv2Barracuda)

# Line Detection

### [MlsdBarracuda](https://github.com/keijiro/MlsdBarracuda)

Unity2021.2.0a19 → Unity2020.3.0f1で動作確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/910fe3e5-374a-3e67-bf71-458ead8585d5.png)

Dummy ImageをNoneにしたらWebCameraが動く（50FPSくらい）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/154fb306-0824-063d-f9e4-2842a96482c3.png)

# Hand Tracking 
### [HandPoseBarracuda](https://github.com/keijiro/HandPoseBarracuda)

Unity2020.3.6f1 → Unity2020.3.0f1で動作確認

Dummy Imageなし WebCamが起動（45FPSくらい）

["HanCo_tester\rgb\0110\cam7\00000010.jpg"](https://lmb.informatik.uni-freiburg.de/resources/datasets/HanCo.en.html)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/33c1d137-fcbc-9600-efe0-2ffe486eb01b.png)

画像サイズが224×224と小さく、難しかったっぽい

### [BlazePalmBarracuda](https://github.com/keijiro/BlazePalmBarracuda)
### [HandLandmarkBarracuda](https://github.com/keijiro/HandLandmarkBarracuda)

# Face Tracking 
### [UltraFaceBarracuda](https://github.com/keijiro/UltraFaceBarracuda)
### [BlazeFaceBarracuda](https://github.com/keijiro/BlazeFaceBarracuda)
### [FaceMeshBarracuda](https://github.com/keijiro/FaceMeshBarracuda)
### [FaceLandmarkBarracuda](https://github.com/keijiro/FaceLandmarkBarracuda)

# Eye Tracking 
### [IrisBarracuda](https://github.com/keijiro/IrisBarracuda)

pad->concatに置換

# Super Resolution
### [Waifu2xBarracuda](https://github.com/keijiro/Waifu2xBarracuda)

# Handwritten Digit Recognition
### [MnistBarracudaGpu](https://github.com/keijiro/MnistBarracudaGpu)

Unity2020.3.14f1

### [MnistBarracuda](https://github.com/keijiro/MnistBarracuda)

Unity2020.3.14f1 → Unity2020.3.0f1で動作確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/90abc473-4025-f1da-ba9a-4f91c18c9e68.png)

~~~MnistTest.cs
using System.Linq;
using UnityEngine;
using Unity.Barracuda;
using UI = UnityEngine.UI;

sealed class MnistTest : MonoBehaviour
{
    public NNModel _model;
    public Texture2D _image;
    public UI.RawImage _imageView;
    public UI.Text _textView;

    void Start()
    {
        // Convert the input image into a 1x28x28x1 tensor.
        using var input = new Tensor(1, 28, 28, 1);

        for (var y = 0; y < 28; y++)
        {
            for (var x = 0; x < 28; x++)
            {
                var tx = x * _image.width  / 28;
                var ty = y * _image.height / 28;
                input[0, 27 - y, x, 0] = _image.GetPixel(tx, ty).grayscale;
            }
        }

        // Run the MNIST model.
        using var worker =
          ModelLoader.Load(_model).CreateWorker(WorkerFactory.Device.CPU);

        worker.Execute(input);

        // Inspect the output tensor.
        var output = worker.PeekOutput();

        var scores = Enumerable.Range(0, 10).
                     Select(i => output[0, 0, 0, i]).SoftMax().ToArray();

        // Show the results on the UI.
        _imageView.texture = _image;
        _textView.text = Enumerable.Range(0, 10).
                         Select(i => $"{i}: {scores[i]:0.00}").
                         Aggregate((t, s) => t + "\n" + s);
    }
}
~~~

~~~SoftMax.cs
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

static class SoftmaxLinqExtension
{
    public static IEnumerable<float> SoftMax(this IEnumerable<float> source)
    {
        var exp = source.Select(x => Mathf.Exp(x)).ToArray();
        var sum = exp.Sum();
        return exp.Select(x => x / sum);
    }
}
~~~

# Classify
### [TFClassify-Unity-Barracuda](https://github.com/keijiro/TFClassify-Unity-Barracuda)

# Depth Estimation
### [MiDaSV2BarracudaCpu](https://github.com/SatoshiRobatoFujimoto/MiDaSV2BarracudaCpu)

1．MnistBarracudaを参考に一から作ってみる

- Unity 2020.3.0f1
- Barracuda 2.1.0-preview
- Windows 10


2．Package Manager から https://github.com/Unity-Technologies/barracuda-release.git を指定し、インストールする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/02479347-ca7a-ac1a-edda-428bedf3d492.png)

3．プロジェクトはこんな感じでImageとDepthのRawImageを配置
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/481f926b-d8cb-c6b1-36fe-2985dfd2279f.png)

4．[MiDaS v2のONNXモデルをダウンロード](https://github.com/PINTO0309/PINTO_model_zoo/tree/main/081_MiDaS_v2)

download_256x256.shにGoogle Driveのリンクがあるのでそこからダウンロード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/9e284e18-cd08-8e27-3f44-bc1870853d63.png)

5．ダウンロードしたmodel_float32.onnxをプロジェクトビューにD&D。Inputs、Outputsのshape大事。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/69f24acf-3bc5-08c0-63cc-fd25c32f3309.png)

6．MiDaSTest.csを作成、GameObjectにAddComponent。必要なものをアタッチ。

~~~MiDaSTest.cs
using System.Linq;
using UnityEngine;
using Unity.Barracuda;
using UI = UnityEngine.UI; 

sealed class MiDaSTest : MonoBehaviour
{
    public NNModel _model;
    public Texture2D _image;
    public Texture2D _depth;
    public UI.RawImage _imageView;
    public UI.RawImage _depthView;

    void Start()
    {
        // Convert the input image into a 1x256x256x3 tensor.
        using var input = new Tensor(1, 256, 256, 3);

        for (var y = 0; y < 256; y++)
        {
            for (var x = 0; x < 256; x++)
            {
                var tx = x * _image.width  / 256;
                var ty = y * _image.height / 256;
                input[0, 255 - y, x, 0] = _image.GetPixel(tx, ty).r;
                input[0, 255 - y, x, 1] = _image.GetPixel(tx, ty).g;
                input[0, 255 - y, x, 2] = _image.GetPixel(tx, ty).b;
            }
        }

        // Run the MiDaS model.
        using var worker = ModelLoader.Load(_model).CreateWorker(WorkerFactory.Device.CPU);

        worker.Execute(input);

        // Inspect the output tensor.
        var output = worker.PeekOutput();

        // 1, 1, 256, 256
        Debug.Log(output);

        for (var y = 0; y < 256; y++){
            for (var x = 0; x < 256; x++){
                // Debug.Log(x+y*256);
                // Debug.Log(output[0,0,x,y]/1000.0f);
                var tx = x * _depth.width  / 256;
                var ty = y * _depth.height / 256;
                Color color = new Color(0.0f, 0.0f, output[0,0,x,255-y]/1000.0f);
                _depth.SetPixel(tx, ty, color);
            }
        }

        _depth.Apply();

        // Show the results on the UI.
        _imageView.texture = _image;
        _depthView.texture = _depth;

    }
}
~~~

7．実行結果
<blockquote class="twitter-tweet"><p lang="es" dir="ltr">MiDaS v2 Barracuda <a href="https://twitter.com/hashtag/Unity?src=hash&amp;ref_src=twsrc%5Etfw">#Unity</a> <a href="https://t.co/jdmyy2OawI">pic.twitter.com/jdmyy2OawI</a></p>&mdash; がちもとさん@熊本 (@sotongshi) <a href="https://twitter.com/sotongshi/status/1425478064343969796?ref_src=twsrc%5Etfw">August 11, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

8．ソースコードはここにあげました

https://github.com/SatoshiRobatoFujimoto/MiDaSV2BarracudaCpu

9．keijiro先生みたいにShaderでGPU化したい

# 参考文献
- [Keijiro Barracuda Repositories](https://github.com/keijiro?tab=repositories&q=Barracuda&type=&language=&sort=)
- [ニューラルネットで何でもできちゃう！？ Unity Barracudaで遊ぼう！ - Unityステーション](https://www.youtube.com/watch?v=5oKgj8q83ec)
- [Barracuda Style Transfer code sample.](https://github.com/UnityLabs/barracuda-style-transfer)
- [Supported ONNX operators](https://docs.unity3d.com/Packages/com.unity.barracuda@1.0/manual/SupportedOperators.html)
- [VSeeFace](https://www.vseeface.icu/)