【问题标题】:Hololens 2 & Unity - How to use the CameraToWorldMatrix to correct the position of a hologram?Hololens 2 & Unity - 如何使用 CameraToWorldMatrix 来校正全息图的位置?
【发布时间】:2020-11-04 21:16:31
【问题描述】:

我正在使用 Hololens 2 和 Unity 2019.4.6。

使用 PhotoCaptureFrame 类,我正在拍摄一张照片,对其进行分析以找到一个特定的标记,然后在标记所在的位置创建一个全息图。我的代码与 Unity 编辑器中的网络摄像头配合良好。但是在全息透镜上,全息图和标记之间存在偏移。

我尝试使用 cameraToWorld 矩阵(通过 photocaptureframe 类获得)来纠正它。如果我理解得很好,它代表了hololens相机和RGB相机(拍照的那个)之间的偏移量。

问题是:我不知道我是否很好地使用了这个矩阵,我的全息图位置总是很奇怪......我尝试使用这个教程:https://forum.unity.com/threads/holographic-photo-blending-with-photocapture.416023/ 结果也是错误的!实例化的四边形旋转并位于原始起点之后(当我启动应用程序时)。它不跟随相机。

我需要转换矩阵吗? 有人可以向我解释我做错了什么吗? 提前致谢!

获取矩阵的简单示例:CameraToWorld 矩阵和 Projection 矩阵的打印结果为 true,但是当您从另一个位置移动并拍照时,矩阵不会更新。

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Windows.WebCam;

public class HoloLensSnapshotTest : MonoBehaviour
{
    PhotoCapture m_PhotoCaptureObj;
    CameraParameters m_CameraParameters;
    bool m_CapturingPhoto = false;

    void Start()
    {
        Initialize();
    }


    [ContextMenu("TakePicture")]
    public void TakePicture() // called by button for now
    {
        if (m_CapturingPhoto)
        {
            return;
        }

        m_CapturingPhoto = true;
        Debug.Log("Taking picture...");
        m_PhotoCaptureObj.TakePhotoAsync(OnPhotoCaptured);
    }

    void Initialize()
    {
        Debug.Log("Initializing...");
        List<Resolution> resolutions = new List<Resolution>(PhotoCapture.SupportedResolutions);
        Resolution selectedResolution = resolutions[0];

        m_CameraParameters = new CameraParameters(WebCamMode.PhotoMode);
        m_CameraParameters.cameraResolutionWidth = selectedResolution.width;
        m_CameraParameters.cameraResolutionHeight = selectedResolution.height;
        m_CameraParameters.hologramOpacity = 0.0f;
        m_CameraParameters.pixelFormat = CapturePixelFormat.BGRA32;

        PhotoCapture.CreateAsync(false, OnCreatedPhotoCaptureObject);
    }

    void OnCreatedPhotoCaptureObject(PhotoCapture captureObject)
    {
        m_PhotoCaptureObj = captureObject;
        m_PhotoCaptureObj.StartPhotoModeAsync(m_CameraParameters, OnStartPhotoMode);
    }

    void OnStartPhotoMode(PhotoCapture.PhotoCaptureResult result)
    {
        m_CapturingPhoto = false;

        Debug.Log("Ready");
    }


    void OnPhotoCaptured(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
    {
        Matrix4x4 cameraToWorldMatrix;
        bool cameraToWorldMatrixResult = photoCaptureFrame.TryGetCameraToWorldMatrix(out cameraToWorldMatrix);

        Matrix4x4 projectionMatrix;
        bool projectionMatrixResult = photoCaptureFrame.TryGetProjectionMatrix(out projectionMatrix);

        Debug.Log("CamToWorld : " + Environment.NewLine + cameraToWorldMatrixResult + Environment.NewLine + $"{cameraToWorldMatrix.ToString()}");
        Debug.Log("Projection : " + Environment.NewLine + projectionMatrixResult + Environment.NewLine + $"{projectionMatrix.ToString()}");
        Debug.Log("Took picture!");

        m_CapturingPhoto = false;
    }
}

我的矩阵是: 相机走向世界:

0.00650   -0.99959  -0.02805    0.00211
-0.99965  -0.00577  -0.02588   -0.04999
0.02571    0.02821  -0.99927   -0.01216
0.00000    0.00000   0.00000    1.00000

投影:

-0.06754   1.52561   0.00000  0.00000
-2.71531  -0.12021   0.00000  0.00000
0.05028    0.01975  -1.00401 -0.20040
0.00000    0.00000   0.00000  1.00000

【问题讨论】:

    标签: c# unity3d augmented-reality hololens windows-mixed-reality


    【解决方案1】:

    实际上,在早期版本的 MR 文档中,它已经演示了如何使用着色器代码:mixed-reality-docs/locatable-camera.md 在相机图像上的特定 3d 位置查找或绘制。

    但是现在这部分文件已经被删除了。幸运的是,我在 Github 上找到了一个解决方案,在 Unity C# 中实现了相同的功能,只修改了几行代码:cameraToWorld.cs

    以下是来自解决方案的引用,您可以以编程方式将此数据存储在您的项目中。如果您有任何其他问题,请告诉我:

    void OnPhotoCaptured(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
    {
        Matrix4x4 cameraToWorldMatrix;
        photoCaptureFrame.TryGetCameraToWorldMatrix(out cameraToWorldMatrix);
        Matrix4x4 projectionMatrix;
        photoCaptureFrame.TryGetProjectionMatrix(out projectionMatrix);
    
    
        var imagePosZeroToOne = new Vector2(pixelPos.x / imageWidth, 1 - (pixelPos.y / imageHeight));
        var imagePosProjected = (imagePosZeroToOne * 2) - new Vector2(1, 1);    // -1 to 1 space
    
        var cameraSpacePos = UnProjectVector(projectionMatrix, new Vector3(imagePosProjected.x, imagePosProjected.y, 1));
        var worldSpaceCameraPos = cameraToWorldMatrix.MultiplyPoint(Vector3.zero);     // camera location in world space
        var worldSpaceBoxPos = cameraToWorldMatrix.MultiplyPoint(cameraSpacePos);   // ray point in world space
     
        RaycastHit hit;
        bool hitToMap = Physics.Raycast(worldSpaceCameraPos, worldSpaceBoxPos - worldSpaceCameraPos, out hit, 20, SpatialMappingManager.Instance.LayerMask);
    }
    
    public static Vector3 UnProjectVector(Matrix4x4 proj, Vector3 to)
    {
        Vector3 from = new Vector3(0, 0, 0);
        var axsX = proj.GetRow(0);
        var axsY = proj.GetRow(1);
        var axsZ = proj.GetRow(2);
        from.z = to.z / axsZ.z;
        from.y = (to.y - (from.z * axsY.z)) / axsY.y;
        from.x = (to.x - (from.z * axsX.z)) / axsX.x;
        return from;
    }
    

    【讨论】:

    • 嗨。谢谢您的回答。但是使用我的代码,我已经得到了一个 Vector3 代表我的标记的世界位置(基于我的相机位置)。它适用于简单的相机(如网络摄像头),所以我想我不需要投影矩阵,我只需要使用 cameraToWorldMatrix.MultiplyPoint()。但是我用这个功能得到的 Vector3 很奇怪,它在我的 hololens 的位置后面,当我启动应用程序时,当我进入房间时它没有更新。你知道为什么吗?
    • 我们正在尝试在 HoloLens 2 上重现您的问题,至少相同的代码在 HoloLens1 上运行良好。您能否分享一个 MVCE(stackoverflow.com/help/minimal-reproducible-example) 来演示您的代码逻辑?
    • 我用一个简单的例子编辑了我的问题,看看矩阵很奇怪。
    【解决方案2】:

    好消息,此问题已通过 2020 年 10 月 21 日的 Unity 2019.4.13f1 版本修复:

    https://unity3d.com/unity/qa/lts-releases?version=2019.4

    “XR:修复了在 HoloLens 2 上使用 PhotoCaptureFrame 时的旋转投影”

    谢谢, 内森

    【讨论】:

      猜你喜欢
      • 2018-01-16
      • 2022-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-12
      • 1970-01-01
      • 2021-07-07
      • 1970-01-01
      相关资源
      最近更新 更多