【问题标题】:CoreLocation heading base on back camera (Augmented reality)基于后置摄像头的 CoreLocation 航向(增强现实)
【发布时间】:2013-07-28 19:53:09
【问题描述】:

我想创建一个增强现实视图,它将一个对象指向一个方向。但是,当您使用相机朝上时,CoreLocation 标题无法正常工作(例如,当您在一楼时,对着 20 层楼的顶部)。

它给出了相反的方向(可能是手机顶部指向的方向)。

我已经尝试了一些方法让它在相机指向的方向上工作,例如:

1,当设备方向> 45度时+180度(不够准确,突然方向偏离10~20度)

2,尝试使用 CMMotionManager 和以下教程中的公式进行计算。 http://www.loveelectronics.co.uk/Tutorials/13/tilt-compensated-compass-arduino-tutorial.

3,尝试使用 ios deviceMotion.magneticField 和 deviceMotion.gravity 从 android 模拟逻辑。

4、使用旋转矩阵(堆栈溢出中的一些其他帖子,但不准确)

    double heading = M_PI + atan2(self.altitudeData.rotationMatrix.m22, self.altitudeData.rotationMatrix.m12);
    heading = heading*180/M_PI;

我不知道我还能尝试什么来让它正确。我知道那里有一些应用程序(一些可以看到太阳和星星的应用程序)做得正确。

【问题讨论】:

    标签: ios augmented-reality magnetometer


    【解决方案1】:

    为了节省其他人的时间,这是 Chee 在 Swift 中的回答:

    import GLKit    
    
    func headingCorrectedForTilt() -> Float?{
            guard let motion = self.motionManager.deviceMotion else{
                return nil
            }
    
            let aspect = fabsf(Float(self.view.bounds.width / self.view.bounds.height))
            let projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(45.0), aspect, 0.1, 100)
    
    
            let r = motion.attitude.rotationMatrix
            let camFromIMU = GLKMatrix4Make(Float(r.m11), Float(r.m12), Float(r.m13), 0,
                               Float(r.m21), Float(r.m22), Float(r.m23), 0,
                               Float(r.m31), Float(r.m32), Float(r.m33), 0,
                               0,     0,     0,     1)
    
            let viewFromCam = GLKMatrix4Translate(GLKMatrix4Identity, 0, 0, 0);
            let imuFromModel = GLKMatrix4Identity
            let viewModel = GLKMatrix4Multiply(imuFromModel, GLKMatrix4Multiply(camFromIMU, viewFromCam))
            var isInvertible : Bool = false
            let modelView = GLKMatrix4Invert(viewModel, &isInvertible);
            var viewport = [Int32](count:4,repeatedValue: 0)
    
            viewport[0] = 0;
            viewport[1] = 0;
            viewport[2] = Int32(self.view.frame.size.width);
            viewport[3] = Int32(self.view.frame.size.height);
    
            var success: Bool = false
            let vector3 = GLKVector3Make(Float(self.view.frame.size.width)/2, Float(self.view.frame.size.height)/2, 1.0)
            let calculatedPoint = GLKMathUnproject(vector3, modelView, projectionMatrix, &viewport, &success)
    
            return success ? atan2f(-calculatedPoint.y, calculatedPoint.x) : nil
        }
    

    【讨论】:

      【解决方案2】:

      经过大量研究和测试。我最终使用 GLKit 进行计算,因为它也为我省去了很多麻烦。把它留在这里给碰巧遇到这个问题的人。

      首先,我使用 CMAttitudeReferenceFrameXTrueNorthZVertical 启动 CMMotionManager 设备运动更新。

      self.hasMotion = NO;
      CMMotionManager *cmmotionManager = [[CMMotionManager alloc] init];
      [cmmotionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical
                                                           toQueue:[[NSOperationQueue alloc] init]
                                                       withHandler:^ (CMDeviceMotion *motion, NSError *error) {
                                                           self.hasMotion = YES;
      
      
                                                       }];
      self.motionManager = cmmotionManager;
      

      根据我在网上找到的一些代码,使用 CoreMotion 旋转绘制一个 openGL 世界,并将其与从屏幕到 3D 世界的点混合:

      float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
      GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(45.0f), aspect, 0.1f, 100.0f);
      
      CMRotationMatrix r = self.motionManager.deviceMotion.attitude.rotationMatrix;
      GLKMatrix4 camFromIMU = GLKMatrix4Make(r.m11, r.m12, r.m13, 0,
                                             r.m21, r.m22, r.m23, 0,
                                             r.m31, r.m32, r.m33, 0,
                                             0,     0,     0,     1);
      
      GLKMatrix4 viewFromCam = GLKMatrix4Translate(GLKMatrix4Identity, 0, 0, 0);
      GLKMatrix4 imuFromModel = GLKMatrix4Identity;
      GLKMatrix4 viewModel = GLKMatrix4Multiply(imuFromModel, GLKMatrix4Multiply(camFromIMU, viewFromCam));
      bool isInvertible;
      GLKMatrix4 modelView = GLKMatrix4Invert(viewModel, &isInvertible);
      
      int viewport[4];
      viewport[0] = 0.0f;
      viewport[1] = 0.0f;
      viewport[2] = self.view.frame.size.width;
      viewport[3] = self.view.frame.size.height;
      
      bool success;
      //assume center of the view
      GLKVector3 vector3 = GLKVector3Make(self.view.frame.size.width/2, self.view.frame.size.height/2, 1.0);     
      GLKVector3 calculatedPoint = GLKMathUnproject(vector3, modelView, projectionMatrix, viewport, &success);
      if(success)
      {
          //CMAttitudeReferenceFrameXTrueNorthZVertical always point x to true north
          //with that, -y become east in 3D world
          float angleInRadian = atan2f(-calculatedPoint.y, calculatedPoint.x);
          return angleInRadian;
      }
      

      【讨论】:

      • 谢谢user2629068,通过这种方式一切都按预期工作。
      • 太棒了!网上有很多解决方案试图解决这个问题,但这是唯一一个可以正常工作的解决方案:)
      • 感谢这段代码很好地支持了我相机的轻微移动!但是,我的航向精度约为 10 度。有没有办法将此精度降低到较低的值(从而提高航向的正确性)?
      • 我也很难获得准确的结果。我使用与上述相同的方法,我的准确度在 10-20 左右。也很想知道是否有任何方法可以获得更准确的结果。
      • 当我使用GLKMathRadiansToDegreesangleInRadian 转换为度数时,我得到的值与CLHeading 非常不同。在 Pitch 0 处,当航向为 360 时,angleInRadian(转换为度数)为 -93。这可能是什么原因?
      猜你喜欢
      • 2016-04-24
      • 1970-01-01
      • 1970-01-01
      • 2011-09-24
      • 1970-01-01
      • 2011-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多