【问题标题】:Save AcquireCameraImageBytes() from Unity ARCore to storage as an image将 Unity ARCore 中的 AcquireCameraImageBytes() 保存为图像存储
【发布时间】:2018-03-30 18:13:06
【问题描述】:

使用 unity 和新的 1.1 版 ARCore,API 公开了一些获取相机信息的新方法。但是,例如,我找不到任何将其作为 jpg 文件保存到本地存储的好例子。

ARCore 示例有一个很好的示例来检索相机数据,然后在此处对其进行处理:https://github.com/google-ar/arcore-unity-sdk/blob/master/Assets/GoogleARCore/Examples/ComputerVision/Scripts/ComputerVisionController.cs#L212 并且在该类中有一些检索相机数据的示例,但没有关于保存该数据的内容。

我见过这个:How to take & save picture / screenshot using Unity ARCore SDK?,它使用较旧的 API 方式获取数据,也没有真正详细介绍保存。

我最理想的是通过 Unity 将 API 中 Frame.CameraImage.AcquireCameraImageBytes() 中的数据转换为存储在磁盘上的 jpg。

更新

从那以后,我主要通过在 ARCore github 页面上挖掘这个问题:https://github.com/google-ar/arcore-unity-sdk/issues/72#issuecomment-355134812 并在下面修改 Sonny 的答案,所以它被接受是公平的。

如果其他人尝试这样做,我必须执行以下步骤:

  1. 向 Start 方法添加回调以在图像可用时运行 OnImageAvailable 方法:

    public void Start()
    {
        TextureReaderComponent.OnImageAvailableCallback += OnImageAvailable;
    }
    
  2. 将 TextureReader(来自 SDK 提供的计算机视觉示例)添加到您的相机和脚本中

  3. 您的OnImageAvailable 应该看起来像这样:

    /// <summary>
    /// Handles a new CPU image.
    /// </summary>
    /// <param name="format">The format of the image.</param>
    /// <param name="width">Width of the image, in pixels.</param>
    /// <param name="height">Height of the image, in pixels.</param>
    /// <param name="pixelBuffer">Pointer to raw image buffer.</param>
    /// <param name="bufferSize">The size of the image buffer, in bytes.</param>
    private void OnImageAvailable(TextureReaderApi.ImageFormatType format, int width, int height, IntPtr pixelBuffer, int bufferSize)
    {
        if (m_TextureToRender == null || m_EdgeImage == null || m_ImageWidth != width || m_ImageHeight != height)
        {
            m_TextureToRender = new Texture2D(width, height, TextureFormat.RGBA32, false, false);
            m_EdgeImage = new byte[width * height * 4];
            m_ImageWidth = width;
            m_ImageHeight = height;
        }
    
        System.Runtime.InteropServices.Marshal.Copy(pixelBuffer, m_EdgeImage, 0, bufferSize);
    
        // Update the rendering texture with the sampled image.
        m_TextureToRender.LoadRawTextureData(m_EdgeImage);
        m_TextureToRender.Apply();
    
        var encodedJpg = m_TextureToRender.EncodeToJPG();
        var path = Application.persistentDataPath;
    
        File.WriteAllBytes(path + "/test.jpg", encodedJpg);
    }
    

【问题讨论】:

    标签: c# android unity3d arcore


    【解决方案1】:

    在 Unity 中,应该可以将原始图像数据加载到纹理中,然后使用 UnityEngine.ImageConversion.EncodeToJPG 将其保存为 JPG。示例代码:

    public class Example : MonoBehaviour
    {
        private Texture2D _texture;
        private TextureFormat _format = TextureFormat.RGBA32;
    
        private void Awake()
        {
            _texture = new Texture2D(width, height, _format, false);
        }
    
        private void Update()
        {
            using (var image = Frame.CameraImage.AcquireCameraImageBytes())
            {
                if (!image.IsAvailable) return;
    
                // Load the data into a texture 
                // (this is an expensive call, but it may be possible to optimize...)
                _texture.LoadRawTextureData(image);
                _texture.Apply();
            }
        }
    
        public void SaveImage()
        {
            var encodedJpg = _texture.EncodeToJPG();
            File.WriteAllBytes("test.jpg", encodedJpg)
        }
    }
    

    但是,我不确定 TextureFormat 是否对应于适用于 Frame.CameraImage.AcquireCameraImageBytes() 的格式。 (我熟悉 Unity 但不熟悉 ARCore。)请参阅 Unity 在 TextureFormat 上的文档,以及这是否与 ARCore 的 ImageFormatType 兼容。

    另外,测试代码对于您的应用程序是否足够性能。

    编辑:正如用户@Lece 解释的那样,使用File.WriteAllBytes 保存编码数据。我已经更新了上面的代码示例,因为我最初省略了该步骤。

    编辑 #2:有关 ARCore 的完整答案,请参阅问题帖子的更新。这里的 cmets 也可能有用 - Jordan 指出“主要部分是使用来自 computer vision sdk example here 的纹理读取器”。

    【讨论】:

    • 这很有帮助,我不得不从这里获取一些代码:github.com/google-ar/arcore-unity-sdk/issues/… 虽然它现在只是保存了一个黑色方块而不是数据。
    • 你的Texture2D能看到屏幕上的彩色图像吗?我想缩小问题是与AcquireCameraImageBytes() 步骤、LoadRawTextureData()Apply() 步骤还是最后的EncodeToJpg()WriteAllBytes() 步骤有关。
    • @JordanRobinson 你解决了黑色方块的问题吗?我也面临同样的问题。
    • @midnightcoffee 是的,如果您检查原始问题中的更新,这就是我所使用的,它修复了黑色方块,主要部分是使用计算机视觉 sdk 示例中的纹理阅读器:@ 987654325@
    • 是的,我已经复制粘贴了您的代码,但仍然出现黑色方块
    【解决方案2】:

    由于我不熟悉 ARCore,我将保持这个通用性。

    1. 使用LoadRawTextureData()Apply() 将字节数组加载到您的Texture2D
    2. 使用EncodeToJPG()对纹理进行编码
    3. File.WriteAllBytes(path + ".jpg", encodedBytes)保存编码数据

    【讨论】:

    • 我用我忘记的第三步更新了我自己的答案中的示例代码。谢谢。
    • @sonny 没问题。您在我完成打字之前提交了,但由于最后一个关键部分,我想我还是会发布它。这是相同的一般想法,所以一切都很好:)
    猜你喜欢
    • 1970-01-01
    • 2018-09-30
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    • 2017-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多