【问题标题】:AR camera distance measurementAR相机测距
【发布时间】:2022-04-20 19:02:51
【问题描述】:

我有一个关于 AR(增强现实)的问题。

我想知道如何显示 AR 相机和目标对象之间的距离信息(如中心计...)。 (使用智能手机)

我可以在 Unity 中做到这一点吗?我应该使用 AR 基金会吗?和ARcore?代码怎么写?

我试图找到一些相关代码(如下),但它似乎就像在对象和对象之间打印信息,与“AR相机”无关......

var other : Transform;
if (other) {
    var dist = Vector3.Distance(other.position, transform.position);
    print ("Distance to other: " + dist);
}
 

再次感谢!

【问题讨论】:

    标签: unity3d augmented-reality arcore


    【解决方案1】:

    这里是 Unity 和 AR Foundation 4.1 的操作方法。 此示例脚本在深度纹理的中心打印深度(以米为单位)并适用于 ARCore 和 ARKit:

    using System;
    using System.Collections;
    using UnityEngine;
    using UnityEngine.Assertions;
    using UnityEngine.XR.ARFoundation;
    using UnityEngine.XR.ARSubsystems;
    
    
    public class GetDepthOfCenterPixel : MonoBehaviour {
        // assign this field in inspector
        [SerializeField] AROcclusionManager manager = null;
        
        
        IEnumerator Start() {
            while (ARSession.state < ARSessionState.SessionInitializing) {
                // manager.descriptor.supportsEnvironmentDepthImage will return a correct value if ARSession.state >= ARSessionState.SessionInitializing 
                yield return null;
            }
            
            if (!manager.descriptor.supportsEnvironmentDepthImage) {
                Debug.LogError("!manager.descriptor.supportsEnvironmentDepthImage");
                yield break;
            }
            
            while (true) {
                if (manager.TryAcquireEnvironmentDepthCpuImage(out var cpuImage) && cpuImage.valid) {
                    using (cpuImage) {
                        Assert.IsTrue(cpuImage.planeCount == 1);
                        var plane = cpuImage.GetPlane(0);
                        var dataLength = plane.data.Length;
                        var pixelStride = plane.pixelStride;
                        var rowStride = plane.rowStride;
                        Assert.AreEqual(0, dataLength % rowStride, "dataLength should be divisible by rowStride without a remainder");
                        Assert.AreEqual(0, rowStride % pixelStride, "rowStride should be divisible by pixelStride without a remainder");
    
                        var numOfRows = dataLength / rowStride;
                        var centerRowIndex = numOfRows / 2;
                        var centerPixelIndex = rowStride / (pixelStride * 2);
                        var centerPixelData = plane.data.GetSubArray(centerRowIndex * rowStride + centerPixelIndex * pixelStride, pixelStride);
                        var depthInMeters = convertPixelDataToDistanceInMeters(centerPixelData.ToArray(), cpuImage.format);
                        print($"depth texture size: ({cpuImage.width},{cpuImage.height}), pixelStride: {pixelStride}, rowStride: {rowStride}, pixel pos: ({centerPixelIndex}, {centerRowIndex}), depthInMeters of the center pixel: {depthInMeters}");
                    }
                }
                
                yield return null;
            }
        }
    
        float convertPixelDataToDistanceInMeters(byte[] data, XRCpuImage.Format format) {
            switch (format) {
                case XRCpuImage.Format.DepthUint16:
                    return BitConverter.ToUInt16(data, 0) / 1000f;
                case XRCpuImage.Format.DepthFloat32:
                    return BitConverter.ToSingle(data, 0);
                default:
                    throw new Exception($"Format not supported: {format}");
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      我也在研究 AR 深度图像,基本思路是:

      1. 获取图片使用API​​,一般为Depth16格式;
      2. 将图像分割为短缓冲区,因为 Depth16 表示每个像素为 16 位;
      3. 获取距离值,存储在每个shortbuffer的低13位中,可以通过(shortbuffer & 0x1ff)来实现,然后就可以得到每个像素点的距离,通常以毫米为单位.

      通过对所有像素进行此操作,您可以创建深度图像并将其存储为 jpg 或其他格式,以下是使用 AR Engine 获取距离的示例代码:

      try (Image depthImage = arFrame.acquireDepthImage()) {
              int imwidth = depthImage.getWidth();
              int imheight = depthImage.getHeight();
              Image.Plane plane = depthImage.getPlanes()[0];
              ShortBuffer shortDepthBuffer = plane.getBuffer().asShortBuffer();
              File sdCardFile = Environment.getExternalStorageDirectory();
              Log.i(TAG, "The storage path is " + sdCardFile);
              File file = new File(sdCardFile, "RawdepthImage.jpg");
      
              Bitmap disBitmap = Bitmap.createBitmap(imwidth, imheight, Bitmap.Config.RGB_565);
              for (int i = 0; i < imheight; i++) {
                  for (int j = 0; j < imwidth; j++) {
                      int index = (i * imwidth + j) ;
                      shortDepthBuffer.position(index);
                      short depthSample = shortDepthBuffer.get();
                      short depthRange = (short) (depthSample & 0x1FFF);
                      //If you only want the distance value, here it is
                      byte value = (byte) depthRange;
                byte value = (byte) depthRange ;
                      disBitmap.setPixel(j, i, Color.rgb(value, value, value));
                  }
              }
              //I rotate the image for a better view
              Matrix matrix = new Matrix();
              matrix.setRotate(90);
              Bitmap rotatedBitmap = Bitmap.createBitmap(disBitmap, 0, 0, imwidth, imheight, matrix, true);
      
              try {
                  FileOutputStream out = new FileOutputStream(file);
                  rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
                  out.flush();
                  out.close();
                  MainActivity.num++;
              } catch (Exception e) {
                  e.printStackTrace();
              }
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
      

      【讨论】:

        【解决方案3】:

        虽然答案很好,但对于这个问题来说,它们可能过于复杂和高级,这是关于 ARCamera 和另一个对象之间的距离,而不是关于像素的深度及其遮挡。

        transform.position 为您提供将脚本附加到的任何游戏对象在层次结构中的位置。因此,将脚本附加到 ARCamera 对象。显然,other 应该是目标对象。

        或者,您可以使用检查器变量或GetComponent获取对两个游戏对象的引用

        【讨论】:

          【解决方案4】:

          /光线投射应该在更新中/ Ray ray = new Ray(cam.transform.position, cam.transform.forward); if (Physics.Raycast(ray, out info, 50f, layerMaskAR))//50米检测范围bcs为50f { distanca.text = string.Format("{0}: {1:N2}m", info.collider.name, info.distance, 2); }

          这是 func 可以完成您需要的操作,它是 UI txt 元素上的 ofc 和层分配给对象/预制件。 int layerMaskAR = 1

          【讨论】:

          • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-30
          • 1970-01-01
          相关资源
          最近更新 更多