将 AcquireCameraImageBytes() 从 Unity ARCore 保存为图像存储

Save AcquireCameraImageBytes() from Unity ARCore to storage as an image

使用 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 并且在 class 中有一些检索相机数据的示例,但是没有什么可以保存该数据。

我看过这个: 它使用较旧的 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);
    }
    

在 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 的完整答案,请参阅问题 post 的更新。此处的评论也可能有用 - Jordan 指定 "the main part was to use the texture reader from the computer vision sdk example here".

由于我对 ARCore 不熟悉,所以我将保持通用。

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