在Unity上使用Sentis部署yolov8与添加NMS,并编译到手机上

本文介绍了如何在Unity中使用Sentis库对YOLOv8的ONNX模型进行改造,添加内置NMS层进行目标检测,以及在实际项目中处理和优化输出结果的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目地址

项目:https://github.com/212534/Unity-Sentis-YOLOv8

Demo apk:链接:https://pan.baidu.com/s/1agTZRhnCzgT5P5HtuUvgWQ?pwd=ydj7
提取码:ydj7
–来自百度网盘超级会员V5的分享

效果展示

这是在电脑上的测试,用的摄像头拍屏幕
在这里插入图片描述

安装Sentis

可以把Sentis看作Barracuda的升级版。
在Package里装com.unity.sentis
在这里插入图片描述
在这里插入图片描述

使用Sentis推理yolov8的onnx

这一部分比较简单,教程非常多

using System.Collections;
using System.Collections.Generic;
using Unity.Sentis;
using UnityEngine;
using Unity.Sentis.Layers;

public class Test: MonoBehaviour
{
   
    public ModelAsset modelAsset;
    private Model model;
    private IWorker worker;
    Ops ops;

    void Start()
    {
   
        model = ModelLoader.Load(modelAsset);
        worker = WorkerFactory.CreateWorker(BackendType.GPUCompute, model);
        ops = WorkerFactory.CreateOps(BackendType.GPUCompute, null);
    }

    public void Predict(WebCamTexture camImage) //我这里使用的是摄像头图像,你也可以用普通图片。
    {
   
        using Tensor inputImage = TextureConverter.ToTensor(camImage,width:640,height:640, channels: 3); //对输入的图像做处理

        var m_Inputs = new Dictionary<string, Tensor> 
        {
   
            {
   "images", inputImage }
        };

        worker.Execute(m_Inputs);//执行推理

        var output0 = worker.PeekOutput("output0") as TensorFloat;  //获取输出结果
        output0.MakeReadable(); //从GPU中取出数据,经过这一步之后就可以读取output0中的数据了
    }
}

直接把onnx文件拖上去就行了。
在这里插入图片描述

YOLOv8的输出格式

需要注意的是,yolov8的onnx的输出结果是一个1x84x8400的张量(当类别数不同时会有变化),具体含义可以参考这篇文章https://blog.csdn.net/yangkai6121/article/details/133843368
简单来讲,这里的8400是8400个预测框。而每个预测框包含以下信息:84 = 边界框预测4 + 数据集类别80
本文使用的yolov8是在coco数据集上训练的,包含80个类别,所以这里是4+80,具体情况与你的训练用的数据集类别有关。
1x84x8400这个输出很明显没法直接使用。所以需要加一个nms来后处理

NMS

yolo属于单阶段的目标检测算法,因此还要对预测框进行后处理。常见的做法是在Unity里用C#自己实现nms,但nms本身就是一个性能开销很大的后处理,自己用C#实现在性能上不划算。

如果是了解目标检测部署的同学,应该知道onnx在opset11及以上版本支持了内置nms层。那么理论上,只要在yolov8的检测头里把torch.ops.torchvision.nms加进去就可以导出自带nms层的ONNX模型。像下图一样
在这里插入图片描述
实际上经过测试,Sentis确实可以识别出onnx的内置nms层,但是会报错。
在这里插入图片描述
原因可能在于,Sentis内实现的nms层与torch.ops.torchvision.nms在input的shape上存在区别。
在这里插入图片描述
举例来讲,在python中对yolov8使用torch.ops.torchvision.nms时,它要求的boxes输入shape为8400x4,scores为8400.
但是Sentis实现的nms层要求的shape分别为,1x8400x4与1x1x8400。

使用Sentis给模型加入NMS层

既然torch.ops.torchvision.nms不能用,那我们可以在Unity里用代码把Sentis实现的nms层加到模型里。
先看一下Sentis中NonMaxSuppression()的输入参数。详细的可以看这里
https://docs.unity3d.com/Packages/com.unity.sentis@1.2/api/Unity.Sentis.Layers.NonMaxSuppression.html
在这里插入图片描述
大体来讲与torch.ops.torchvision.nms的输入参数比较一致。
我们需要解决的问题便是把yolov8输出的1x84x8400张量拆解为boxes与scores,也就是NonMaxSuppression()输入。而Sentis是支持在Unity中对模型结构进行修改的。

1.首先我们给模型加入三个新的输入,这也是NonMaxSuppression()所需要的输入。使用新增输入的形式设置这三个值,可以在程序运行时对它们动态修改。

		//Set input
        model.AddInput("maxOutputBoxesPerClass",DataType.Int, new SymbolicTensorShape(1)); //每个类别最多返回的边框数量。
        model.AddInput("iouThreshold",DataType.Float, new SymbolicTensorShape(1)); //iou阈值
        model.AddInput("scoreThreshold",DataType.Float, new SymbolicTensorShape(1)); //置信度阈值

2.对1x8400x4进行拆分。比较反人类的是,Sentis在添加层时,有些层的初始化只能输入字符串作为参数,这些字符串实际上是网络里的输出名,输入名,常量名等。所以这里要给模型加入几个常量。
我在注释里加入了每一层的shape变化,方便各位理解这个过程。如果你没搞过深度学习,不理解每一层的含义,可以去官方文档里看具体解释。
https://docs.unity3d.com/Packages/com.unity.sentis@1.2/api/Unity.Sentis.Layers.html

 		//Set constants   
        model.AddConstant(new Constant("0", new int[] {
    0 })
### UnitySentisYOLOv8 的集成概述 YOLOv8 是一种先进的目标检测算法,能够实时处理图像识别其中的目标对象[^4]。Sentis 提供了一种情感分析技术,可以用于识别人脸表情或其他情绪特征[^5]。而 Unity 则是一个强大的游戏引擎,支持多种跨平台应用开发,尤其是在虚拟现实 (VR) 和增强现实 (AR) 方面表现突出。 #### 1. **YOLOv8Unity 中的应用** 为了将 YOLOv8 集成到 Unity 工程中,通常需要借助中间层来桥接 C++ 或 Python 实现的模型推理功能 Unity 场景之间的交互。以下是常见的方法: - 使用 `TensorFlowSharp` 插件加载预训练好的 TensorFlow 模型,将其部署Unity 运行环境[^6]。 - 如果采用 ONNX 格式的 YOLOv8 模型,则可以通过 ML-Agents 或其他第三方库完成解析和预测操作[^7]。 ```csharp using UnityEngine; using TensorFlowLite; public class ObjectDetection : MonoBehaviour { private Interpreter _interpreter; void Start() { string modelPath = Application.dataPath + "/yolov8.tflite"; _interpreter = new Interpreter(modelPath); _interpreter.AllocateTensors(); } public float[] Predict(byte[] inputImageBytes){ // 输入数据预处理... var outputData = new float[...]; // 初始化输出张量大小 _interpreter.SetInputTensorData(inputImageBytes, ...); _interpreter.Invoke(); _interpreter.GetOutputTensorData(out outputData); return outputData; } } ``` #### 2. **Sentis API 接口调用** Sentis 主要提供基于 RESTful Web Service 的接口服务,开发者可以直接通过 HTTP 请求获取所需的情感分析结果。在 Unity 脚本里实现网络通信部分如下所示: ```csharp IEnumerator FetchEmotionAnalysis(string imageUrl){ WWWForm form = new WWWForm(); form.AddField("image_url",imageUrl); using(WWW www=new WWW("https://api.sentis.com/emotions",form)){ yield return www; if(!string.IsNullOrEmpty(www.error)) Debug.LogError($"Error:{www.error}"); else{ EmotionResponse response=JsonUtility.FromJson<EmotionResponse>(www.text); foreach(var emotion in response.emotions) Debug.Log($"{emotion.name}:{emotion.score}"); } } } [System.Serializable] struct EmotionResponse{ public EmotionItem[] emotions; } [System.Serializable] struct EmotionItem{ public string name; public double score; } ``` 此处需要注意的是实际 URL 及参数可能依据官方文档有所变化,请参照最新版本说明调整代码逻辑[^8]。 #### 3. **综合案例设计思路** 当试图把上述两者结合起来形成完整的解决方案时,可以从以下几个方面考虑架构规划: - 数据流管理:定义清晰的数据传输路径,确保摄像头捕获的画面既能传递给 YOLOv8 处理又能同步提交至 Sentis 平台评估; - UI 展示优化:利用 Canvas 组件搭建直观易懂的操作界面,向用户反馈当前状态以及最终结论; - 性能监控机制:引入帧率统计工具或者 GPU/CPU 占用情况监视器保障整体流畅度不受影响; --- ###
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值