代码之家  ›  专栏  ›  技术社区  ›  Jordan Robinson

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

  •  5
  • Jordan Robinson  · 技术社区  · 6 年前

    通过使用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获取数据的方式,并且也没有真正深入到保存的细节。

    理想情况下,我想要的是一种从 Frame.CameraImage.AcquireCameraImageBytes() 在API中放入一个存储在磁盘上的jpg,通过Unity。

    使现代化

    此后,我主要通过在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. 你的 OnImage可用 应该有点像这样:

      /// <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 回复  |  直到 6 年前
        1
  •  6
  •   sonnyb Programmer    6 年前

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

    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

    此外,测试代码的性能是否足以满足您的应用程序。

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

    编辑#2:有关特定于ARCore的完整答案,请参阅问题帖子的更新。这里的评论可能也很有用-Jordan指定“主要部分是使用 computer vision sdk example here “。

        2
  •  1
  •   Lece    6 年前

    因为我不熟悉ARCore,所以我将保留这个通用的。

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