使用 Unity Sentis 和 Compute Shader 进行高效人脸识别

Unity sentis就是Unity barracuda的升级版,所以使用sentis人脸识别步骤基本和barracuda一致,详情参考我的《使用 Unity Barracuda 和 Compute Shader 进行高效人脸识别》使用 Unity Barracuda 和 Compute Shader 进行高效人脸识别-CSDN博客

注意:

需要注意的是 version-RFB-320.onnx 模型在sentis框架下的inputs输入值和barracuda有所不同,形状为(1,3,240,320),barracuda里是(1,240,320,3),图片输入的时候转换一下轴顺序即可。

代码:

using System;
using Unity.Mathematics;
using Unity.Sentis;
using UnityEngine;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine.Rendering;
using UnityEngine.UI;
using Unity.Sentis.Layers;
 

public class Ultraface  : MonoBehaviour 
{
    public ModelAsset modelAsset;
    public Model model; 
    private IWorker worker;

    private int inputTexWidth = 320, inputTexHeight = 240;
    private int OutputCount = 4420;
     
    public  struct Detection
    {
        public   float x1, y1, x2, y2;
        public   float score;
        public   float pad1, pad2, pad3; 
        public static int Size = 8 * sizeof(float); 
    }
    

    [SerializeField]private WebCamTexture webTex;


   
    
    public ComputeShader postprocess1;
    private RenderTexture scores;
    private RenderTexture boxes;
    private ComputeBuffer post1;
    
    public ComputeShader postprocess2;
    private ComputeBuffer post2;
    private ComputeBuffer counter;
   
    
    
    
    [SerializeField]  Shader _visualizer = null;
    Material _material;
    ComputeBuffer _drawArgs;
    [SerializeField] private Texture2D _texture;
    
    [SerializeField]  RawImage _previewUI = null;
    [SerializeField] private Texture2D dTexture;
    
    public void SetIndirectDrawCount(ComputeBuffer drawArgs)
        => ComputeBuffer.CopyCount( post2, drawArgs, sizeof(uint));

    private GPUComputeBackend gpu;
    
    
  
    private void Start()
    {
        InitWebCam();
        InitModel();
        InitBuffer();
          gpu = new GPUComputeBackend();
        _material = new Material(_visualizer);
        
        _drawArgs = new ComputeBuffer(4, sizeof(uint),
            ComputeBufferType.IndirectArguments);
        _drawArgs.SetData(new int [] {6, 0, 0, 0});
        _previewUI.texture = webTex;
     
    }

    private void Update()
    {
        RunModel(webTex,0.3f);
    
    }
 
    void OnRenderObject()
    {
        SetIndirectDrawCount(_drawArgs); 
        _material.SetFloat("_Threshold", 0.3f);
        _material.SetTexture("_Texture", _texture);
        _material.SetBuffer("_Detections", post2);
        _material.SetPass(_texture == null ? 0 : 1);
        Graphics.DrawProceduralIndirectNow(MeshTopology.Triangles, _drawArgs, 0);
    }
   


    void InitWebCam()
    {
        webTex = new WebCamTexture(1920, 1080,30);
        webTex.deviceName = WebCamTexture.devices[0].name;
        webTex.Play();
       
    }

    void InitModel()
    {
        model = ModelLoader.Load(modelAsset);
        
        worker = WorkerFactory.CreateWorker(BackendType.GPUCompute, model);
        
         
    }

    void InitBuffer()
    {
        
         scores = new RenderTexture(OutputCount / 20, 20, 0);
          
         boxes = new RenderTexture(OutputCount / 20, 20, 0, RenderTextureFormat.ARGBFloat); 
    
        post1 = new ComputeBuffer(512, Detection.Size);
        post2 = new ComputeBuffer(512, Detection.Size, ComputeBufferType.Append);
        counter = new ComputeBuffer(1, sizeof(uint), ComputeBufferType.Counter);
        
    }

  
      void RunModel(Texture source, float threshold)
    {
        using ( TensorFloat input = TextureConverter.ToTensor(source, 320, 240, 3) )
        {
        
           using  TensorFloat _2 = new TensorFloat(2f);
           using  TensorFloat _1 = new TensorFloat(1f);
           using  TensorFloat input1 = TensorFloat.AllocZeros(new TensorShape(1, 3, 240, 320));
           gpu.Mul(input,_2,input1);
        
     
           using   TensorFloat input2 = TensorFloat.AllocZeros(new TensorShape(1, 3, 240, 320));
           gpu.Sub(input1,_1,input2);
     
           worker.Execute( input2);

        }  
         using var s= worker.PeekOutput("scores") as TensorFloat;
         using var b= worker.PeekOutput("boxes")as TensorFloat;
          
         s.Reshape( new TensorShape(1, 221, 20,2));
         b.Reshape( new TensorShape(1, 221, 20,4));
         
         using  TensorFloat tagetT = TensorFloat.AllocZeros(new TensorShape(1, 2, 20,221)); 
         gpu.Transpose(s,tagetT,new int[] {0, 3, 1, 2}); 
         using   TensorFloat tagetT1 = TensorFloat.AllocZeros(new TensorShape(1, 4, 20,221)); 
         gpu.Transpose(b,tagetT1,new int[] {0, 3, 1, 2}); 
            
         scores = TextureConverter.ToTexture(tagetT, 221, 20, 2);  
         boxes  = TextureConverter.ToTexture(tagetT1 , 221, 20, 4); 
         
    
        
         post2.SetCounterValue(0);
         counter.SetCounterValue(0);
        
        
        
        postprocess1.SetTexture(0, "Scores",  scores);
        postprocess1.SetTexture(0, "Boxes", boxes);
        postprocess1.SetInts("InputSize", boxes.width,boxes.height);
        postprocess1.SetFloat("Threshold", threshold);
        postprocess1.SetBuffer(0, "Output",  post1);
        postprocess1.SetBuffer(0, "OutputCount",  counter);
        postprocess1.Dispatch (0, (boxes.width+7)/16,boxes.height/4,1);
        
      
        
        postprocess2.SetFloat ("Threshold", 0.5f);
        postprocess2.SetBuffer(0, "Input",  post1);
        postprocess2.SetBuffer(0, "InputCount",  counter);
        postprocess2.SetBuffer(0, "Output",  post2);
        postprocess2.Dispatch (0, 1, 1, 1); 
    
    }

  
    private void OnDestroy()
    {
        worker.Dispose(); 
        post1.Dispose();
        post2.Dispose();
        counter.Dispose();
        _drawArgs.Dispose();
        Destroy(webTex);
        Destroy(scores);
        Destroy(boxes);
        gpu.Dispose();
    }
}

猜你喜欢

转载自blog.csdn.net/m0_55632444/article/details/139185031