AR之道

AR Foudation案例解析(二) ------ Camer

2019-06-29  本文已影响6人  千喜Ya

一.环境

案例网址 : https://github.com/Unity-Technologies/arfoundation-samples.git
官方文档网址 : https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@2.2/api/UnityEngine.XR.ARFoundation.html
Unity版本 : 2019.3.0
SDK版本 :

二.案例解析

1.功能

该组件测试获取最新的相机图像并将其转换为RGBA格式。如果成功,它将在屏幕上以原始图像的形式显示图像,并显示有关图像的信息。
这对于需要从CPU上的相机图像访问原始像素的计算机视觉应用程序非常有用。 这与ARCameraBackground组件不同,后者可以有效地在屏幕上显示相机图像。
如果你只是想把相机的纹理渲染到屏幕上,使用ARCameraBackground,或者使用图形。创建一个gpu友好的渲染纹理。
在本例中,我们在CPU上获取摄像机图像数据,将其转换为RGBA格式,然后在屏幕上显示为raw图像纹理,以演示其工作情况。这是一个例子,不要简单地使用此技术在屏幕上呈现相机图像。

2.测试结果

测试手机 : 小米8SE


简单的截了一张图

测试结果 : 切换分辨率后, ARCameraBackground会卡住,然后我将手机横过来,发现ARCameraBackground会闪烁,但是右上角的画面还是正常的
我记得群里面有几个小伙伴有问过能否进行获取图像进行后处理一些操作,感觉可以用到这个案例

3.代码解析

using System;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

/// <summary>
/// 该组件测试获取最新的相机图像并将其转换为RGBA格式。如果成功,它将在屏幕上以原始图像的形式显示图像,并显示有关图像的信息。
/// 这对于需要从CPU上的相机图像访问原始像素的计算机视觉应用程序非常有用。
/// 
/// 这与ARCameraBackground组件不同,后者可以有效地在屏幕上显示相机图像。
/// 如果你只是想把相机的纹理渲染到屏幕上,使用ARCameraBackground,或者使用图形。创建一个gpu友好的渲染纹理。
/// 在本例中,我们在CPU上获取摄像机图像数据,将其转换为RGBA格式,
/// 然后在屏幕上显示为raw图像纹理,以演示其工作情况。这是一个例子;不要简单地使用此技术在屏幕上呈现相机图像。
/// </summary>
public class TestCameraImage : MonoBehaviour
{
    [SerializeField]
    [Tooltip("将产生帧事件的ARCameraManager。")]
    ARCameraManager m_CameraManager;

     /// <summary>
    /// 获取或者设置 <c>ARCameraManager</c>.
    /// </summary>
    public ARCameraManager cameraManager
    {
        get { return m_CameraManager; }
        set { m_CameraManager = value; }
    }

    [SerializeField]
    RawImage m_RawImage;

    /// <summary>
    /// The UI RawImage used to display the image on screen.
    /// </summary>
    public RawImage rawImage
    {
        get { return m_RawImage; }
        set { m_RawImage = value; }
    }

    [SerializeField]
    Text m_ImageInfo;

    /// <summary>
    /// 用于在屏幕上显示图像信息的UI文本。
    /// </summary>
    public Text imageInfo
    {
        get { return m_ImageInfo; }
        set { m_ImageInfo = value; }
    }

    void OnEnable()
    {
        if (m_CameraManager != null)
        {
            //注册获取XRCameraImage函数
            m_CameraManager.frameReceived += OnCameraFrameReceived;
        }
    }

    void OnDisable()
    {
        if (m_CameraManager != null)
        {
            m_CameraManager.frameReceived -= OnCameraFrameReceived;
        }
    }

    unsafe void OnCameraFrameReceived(ARCameraFrameEventArgs eventArgs)
    {
        //尝试获取最新的相机图像。如果这个方法成功,它获取一个必须被处理的本地资源(见下面)。
        XRCameraImage image;
        if (!cameraManager.TryGetLatestImage(out image))
        {
            return;
        }

        // 显示一些关于相机图像的信息
        m_ImageInfo.text = string.Format(
            "Image info:\n\twidth: {0}\n\theight: {1}\n\tplaneCount: {2}\n\ttimestamp: {3}\n\tformat: {4}",
            image.width, image.height, image.planeCount, image.timestamp, image.format);

        //一旦我们有了一个有效的XRCameraImage,我们就可以访问单独的图像“平面”(图像中的独立通道)。
        //XRCameraImage.GetPlane提供了对该数据的低开销访问。然后这个可以传递给 计算机视觉算法。
        //在这里,我们将摄像机图像转换为RGBA纹理并在屏幕上绘制。

        // 选择RGBA格式。看到XRCameraImage.FormatSupported用于受支持格式的完整列表。
        var format = TextureFormat.RGBA32;

        if (m_Texture == null || m_Texture.width != image.width || m_Texture.height != image.height)
        {
            m_Texture = new Texture2D(image.width, image.height, format, false);
        }

        // 将图像转换为格式,在Y轴上翻转图像。我们也可以得到一个子矩形,但我们会得到完整的图像。
        var conversionParams = new XRCameraImageConversionParams(image, format, CameraImageTransformation.MirrorY);

        // Texture2D允许我们直接写入原始纹理数据,这允许我们在不进行任何复制的情况下进行就地转换。
        var rawTextureData = m_Texture.GetRawTextureData<byte>();
        try
        {
            image.Convert(conversionParams, new IntPtr(rawTextureData.GetUnsafePtr()), rawTextureData.Length);
        }
        finally
        {
            // 我们必须在使用完XRCameraImage之后处理它,以避免泄漏本机资源。
            image.Dispose();
        }

        // 将更新后的纹理数据应用到我们的纹理中
        m_Texture.Apply();

        // 设置原始图像的纹理,以便我们可以可视化它。
        m_RawImage.texture = m_Texture;
    }

    Texture2D m_Texture;
}
上一篇下一篇

猜你喜欢

热点阅读