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

时间:2018-03-30 18:13:07

标签: c# android unity3d arcore

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

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);
    }
    

2 个答案:

答案 0 :(得分:6)

在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。)请参阅TextureFormat上的Unity文档,以及它是否与ARCore的ImageFormatType兼容。

此外,测试代码是否足够适合您的应用程序。

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

编辑#2:有关ARCore的完整答案,请参阅问题帖子的更新。这里的评论也可能有用 - 约旦指出&#34;主要部分是使用computer vision sdk example here&#34;中的纹理阅读器。

答案 1 :(得分:1)

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

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