ARFoundation之路-图像跟踪

版权声明:Davidwang原创文章,严禁用于任何商业途径,授权后方可转载。

  图像跟踪技术,是指通过图像处理技术对摄像头中拍摄到的2D图像进行定位,并对其姿态进行跟踪的技术。图像跟踪技术的基础是图像识别,图像识别是指识别和检测出数字图像或视频中对象或特征的技术,图像识别技术是信息时代的一门重要技术,其产生目的是为了让计算机代替人类去处理大量的图形图像及真实物体信息,因而成为其他许多重要技术的基础。

(一)图像跟踪基本操作

  在ARFoundation中,图像跟踪系统依据参考图像为库的图像信息尝试在周围环境中检测到匹配的2D图像并跟踪之,在ARFoundation的图像跟踪处理中,有一些特定的术语如下表所示。

术语描述
参考图像(Reference Image)识别2D图像的过程实际是一个特征值对比的过程,ARFoundation将从摄像头中获取的图像信息与参考图像库的图像特征点信息进行对比,存储在参考图像库中的用于对比的图像就叫做参考图像。一旦对比成功,真实环境中的图像将与参考图像库的参考图像建立对应关系,每一个真实2D图像的姿态信息也一并被检测。
参考图像库(Reference Image Library)参考图像库用来存储一系列的参考图像用于对比,每一个图像跟踪程序都必须有一个参考图像库,但需要注意的是,参考图像库中存储的实际是参考图像的特征值信息而不是原始图像,这有助于提高对比速度与鲁棒性。参考图像库越大,图像对比就会越慢,建议参考图像库的图像不要超过1000张。
跟踪组件提供方(Provider)ARFoundation是架构在底层SDK图像跟踪API之上的,也即是说ARFoundation并不具体负责图像识别过程的算法,它只提供一个接口,具体图像识别由算法提供方提供。

  在ARFoundation中,图像跟踪的操作使用分成两步,第一步是建立一个参考图像库,第二步是在场景中挂载AR Tracked Image Manager组件,并将一个需要实例化的Prefab赋给其Tracked Image Prefab即可,下面我们来具体操作。

  按上述步骤,在Unity中新建一个工程,第一步建立一个参考图像库,首先在Project窗口中的ImageLib文件夹下点击鼠标右键并依次选择Create->XR->Reference Image Library新建一个参考图像库,并命名为RefImageLib,如下图所示。

在这里插入图片描述
  选择新建的RefImageLib参考图像库,在Inspector窗口中,点击“Add Image”添加参考图像,将参考图像拖到图像框中,如下图所示。

在这里插入图片描述
  在上图中,每一个参考图像除了图片信息外都有若干属性,其具体含义见下表。

属性描述
Name一个标识参考图像的名字,这个名字在做图像对比时没有作用,但在比对匹配成功后我们可以通过参考图像名字获知是哪个参考图像,参考图像名字是可以重复的,因为在跟踪时,跟踪系统还会给每一个参考图像一个referenceImage.guid值,这个值是唯一的。
Specify Size这是个可选值,为加速图像检测识别过程,一些底层SDK要求提供一个2D待检测图像的物理尺寸,所以如果要设置,这个值一定会是一个大于0的长宽值对,当一个值发生变化时,Unity会根据参考图像的比例自动调整另一个值。
Keep Texture at Runtime一个默认的纹理,这个纹理可以用于修改Prefab的外观。

  在完成上述工作之后,在Hierarchy窗口中选择AR Session Origin,并为其挂载AR Tracked Image Manager组件,将第一步制作的RefImageLib参考图像库拖到Reference Library属性中,并设置相应的Prefab,如下图所示。

在这里插入图片描述
  参考图像库也可以在运行时添加,但AR Tracked Image Manager一开始跟踪图像,参考图像库就不能为null。Max Number of Moving Images属性指定了最大的可跟踪的动态图像数,因为动态图像跟踪是一个非常消耗CPU性能的任务,过多的动态图像跟踪会导致应用卡顿。最后需要说明的是,动态图像跟踪与底层SDK的算法有非常大的关系,不同的底层对跟踪图像有不同的要求,对指定平台具体应用需要参阅该平台的SDK资料。ARFoundation目前不支持动态添加参考图像,这对很多图像跟踪类应用是比较大的限制。

  编译运行,效果如下图所示,在Android上进行测试,观察实例化的虚拟对象,发现模型在Y轴上旋转了180度,这个是在实例化时ARCore底层SDK导致的,为解决这个问题,在ARCore中实例化虚拟时需要在Y轴再旋转180度,但在ARFoundation中,实例化虚拟物体是由AR Tracked Image Manager自动完成的,无法干预,所以目前在ARFoundation中解决这个问题只有把模型进行180度旋转再使用。

在这里插入图片描述

(二)图像跟踪启用与禁用

  在ARFoundation中,实例化出来的虚拟对象并不会随着被跟踪物体的消失而消失,而是会继续停留在原来的位置上,这有时就会变得很不合适。而且,图像跟踪是一个非常消耗性能的操作,在不使用图像跟踪时一定要把图像跟踪功能关闭。参考平面检测功能的关闭与启用,类似的我们可以编写如下代码来控制图像跟踪的启用与禁用以及所跟踪对象的显示与隐藏。

    public Text m_TogglePlaneDetectionText;
    private ARTrackedImageManager mARTrackedImageManager;
    void Awake()
    {
        mARTrackedImageManager = GetComponent<ARTrackedImageManager>();
    }

    #region 启用与禁用图像跟踪
    public void ToggleImageTracking()
    {
        mARTrackedImageManager.enabled = !mARTrackedImageManager.enabled;

        string planeDetectionMessage = "";
        if (mARTrackedImageManager.enabled)
        {
            planeDetectionMessage = "禁用图像跟踪";
            SetAllImagesActive(true);
        }
        else
        {
            planeDetectionMessage = "启用图像跟踪";
            SetAllImagesActive(false);
        }

        if (m_TogglePlaneDetectionText != null)
            m_TogglePlaneDetectionText.text = planeDetectionMessage;
    }

    void SetAllImagesActive(bool value)
    {
        foreach (var img in mARTrackedImageManager.trackables)
            img.gameObject.SetActive(value);
    }
    #endregion

  与平面检测开启与关闭类似,我们使用一个按钮来控制,运行效果如下图所示。

在这里插入图片描述

(三)多图像跟踪

  在AR Tracked Image Manager组件中,有一个Tracked Image Prefab属性,这个属性即为需要实例化的虚拟对象。默认,ARFoundation是支持多图像跟踪的,如下图所示。
在这里插入图片描述
  但在AR应用运行时,只能有一个AR Tracked Image Manager组件运行(多个AR Tracked Image Manager组件会导致跟踪冲突),即只能设置一个Tracked Image Prefab,即不能实例化多个虚拟对象,这将极大的限制跟踪图像的实际应用,所以为了实例化多个虚拟对象,我们只能动态的修改Tracked Image Prefab属性。经过测试,我们发现在ARFoundation中,AR Tracked Image Manager组件在trackedImagesChanged事件触发之前就已经实例化了虚拟对象,因此我们的解决思路是:在AR Tracked Image Manager组件Tracked Image Prefab中设置第一个需要实例化的Prefab,然后在trackedImagesChanged事件里捕捉到图像added操作,更改Tracked Image Prefab为下一个需要实例化的Prefab,这样来达到动态调整虚拟对象的目的。如正常设置Tracked Image Prefab为Spider Prefab,在检测到Spider图像后,我们将Tracked Image Prefab修改为Cat Prefab,这样,再检测到Cat图像后就会实例化Cat Prefab了。具体代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;

public class MultiImageTracking : MonoBehaviour
{
    ARTrackedImageManager ImgTrackedmanager;
    public GameObject[] ObjectPrefabs;

    private void Awake()
    {
        ImgTrackedmanager = GetComponent<ARTrackedImageManager>();
    }


    private void OnEnable()
    {
        ImgTrackedmanager.trackedImagesChanged += OnTrackedImagesChanged;
    }
    void OnDisable()
    {
        ImgTrackedmanager.trackedImagesChanged -= OnTrackedImagesChanged;
    }
    void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        foreach (var trackedImage in eventArgs.added)
        {
            OnImagesChanged(trackedImage.referenceImage.name);
        }
       // foreach (var trackedImage in eventArgs.updated)
       // {
       //     OnImagesChanged(trackedImage.referenceImage.name);
       // }
    }

    private void OnImagesChanged(string referenceImageName)
    {
        if (referenceImageName == "Spider")
        {           
            ImgTrackedmanager.trackedImagePrefab = ObjectPrefabs[1];
            Debug.Log("Tracked Name is .." + referenceImageName);
            Debug.Log("Prefab Name is .." + ImgTrackedmanager.trackedImagePrefab.name);
        }
        if (referenceImageName == "Cat")
        {
            ImgTrackedmanager.trackedImagePrefab = ObjectPrefabs[0];
        }
    }
}

  编译运行,效果如下图所示。
在这里插入图片描述
在这里插入图片描述

  读者可能已经看到,这种方式其实有个很大的弊端,即必须要按顺序检测图像,因为我们无法在用户检测图像之前预测用户可能会检测的2D图像。为解决这个问题,就不能让AR Tracked Image Manager组件实例化对象,而由我们自己负责虚拟对象的实例化。将AR Tracked Image Manager组件下的Tracked Image Prefab属性清空,为MultiImageTracking脚本的ObjectPrefabs数组赋上相应的值,并编写如下代码。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;

public class MultiImageTracking : MonoBehaviour
{
    ARTrackedImageManager ImgTrackedmanager;
    public GameObject[] ObjectPrefabs;

    private void Awake()
    {
        ImgTrackedmanager = GetComponent<ARTrackedImageManager>();
    }

    private void OnEnable()
    {
        ImgTrackedmanager.trackedImagesChanged += OnTrackedImagesChanged;
    }
    void OnDisable()
    {
        ImgTrackedmanager.trackedImagesChanged -= OnTrackedImagesChanged;
    }
    void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        foreach (var trackedImage in eventArgs.added)
        {
            OnImagesChanged(trackedImage);
        }
       // foreach (var trackedImage in eventArgs.updated)
       // {
       //     OnImagesChanged(trackedImage.referenceImage.name);
       // }
    }

    private void OnImagesChanged(ARTrackedImage referenceImage)
    {
        if (referenceImage.referenceImage.name == "Spider")
        {
            Instantiate(ObjectPrefabs[0], referenceImage.transform);
        }
        if (referenceImage.referenceImage.name == "Cat")
        {
            Instantiate(ObjectPrefabs[1], referenceImage.transform);
        }
    }
}

  在上述代码中,我们根据参考图像的名字在被检测图像的位置实例化虚拟对象,实现了我们的要求,不再要求用户按顺序扫描图像。但现在又有一个新问题,我们不可能使用if-else或者switch-case语句遍历所有可能的模型,因此我们改用动态加载模型的方式,编写代码如下。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;

public class MultiImageTracking : MonoBehaviour
{
    ARTrackedImageManager ImgTrackedManager;
    private Dictionary<string, GameObject> mPrefabs =  new Dictionary<string, GameObject>();

    private void Awake()
    {
        ImgTrackedManager = GetComponent<ARTrackedImageManager>();
    }

    void Start()
    {        
        mPrefabs.Add("Cat", Resources.Load("Cat") as GameObject);
        mPrefabs.Add("Spider", Resources.Load("Spider") as GameObject);
    }

    private void OnEnable()
    {
        ImgTrackedManager.trackedImagesChanged += OnTrackedImagesChanged;
    }
    void OnDisable()
    {
        ImgTrackedManager.trackedImagesChanged -= OnTrackedImagesChanged;
    }
    void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        foreach (var trackedImage in eventArgs.added)
        {
            OnImagesChanged(trackedImage);
        }
       // foreach (var trackedImage in eventArgs.updated)
       // {
       //     OnImagesChanged(trackedImage.referenceImage.name);
       // }
    }

    private void OnImagesChanged(ARTrackedImage referenceImage)
    {
        Debug.Log("Image name:"+ referenceImage.referenceImage.name);
        Instantiate(mPrefabs[referenceImage.referenceImage.name], referenceImage.transform);
    }
}

  为了实现代码所描述功能,我们还要完成两项工作,第一项工作是将Prefabs放到Resources文件夹中方便动态加载,第二项工作是保证mPrefabs中的key与RefImageLib参考图像库中的参考图像名一致。至此,我们已实现自由的多图像多模型功能。

  • 17
    点赞
  • 98
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 103
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 103
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_DavidWang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值