База заголовка CoreLocation на задней камере (Дополненная реальность)

Я хотел бы создать вид дополненной реальности, который будет указывать на объект в определенном направлении. Однако заголовок CoreLocation работает неправильно, когда вы смотрите вверх камерой (скажем, на верх 20-этажного здания, когда вы находитесь на первом этаже).

Он дает противоположное направление (возможно, направление, указываемое верхней частью телефона).

Я пробовал несколько способов заставить его работать в том направлении, в котором указывает камера, например:

1, +180 градусов, когда ориентация устройства> 45 градусов (недостаточно точно, внезапно направление уходит на 10-20 градусов)

2, попытка вычислить с помощью CMMotionManager с формулой из приведенного ниже руководства. http://www.loveelectronics.co.uk/Tutorials/13/tilt-compensated-compass-arduino-tutorial.

3, попытался смоделировать логику из Android с помощью ios deviceMotion.mintageField и deviceMotion.gravity.

4, используйте матрицу вращения (какой-то другой пост в переполнении стека, но не точный)

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

Я уже не понимаю, что еще я мог бы попытаться исправить. Я знаю, что есть некоторые приложения (некоторые приложения, которые могут видеть солнце и звезды), которые делают это правильно.


person Chee    schedule 29.07.2013    source источник


Ответы (2)


После долгих исследований и испытаний. В итоге я использовал GLKit для расчетов, так как это также избавляет меня от многих проблем. Просто оставьте это здесь для всех, кто случайно дойдет до этого вопроса.

Сначала я запустил обновления движения устройства CMMotionManager с помощью CMAttitudeReferenceFrameXTrueNorthZVertical.

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;

Из некоторых кодов, которые я нашел в Интернете, чтобы нарисовать мир openGL с помощью вращения CoreMotion и смешать его с получением точки с экрана в 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;
}
person Chee    schedule 16.08.2013
comment
спасибо user2629068, кстати все работает как положено. - person kokemomuke; 17.11.2014
comment
Здорово! В сети есть масса решений, которые пытаются решить эту проблему, но это единственное, что работает нормально :) - person roberto.buratti; 30.12.2014
comment
Спасибо за этот код, который очень хорошо поддерживает небольшие движения моей камеры! Однако у меня точность курса составляет примерно 10 градусов. Есть ли способ снизить эту точность до более низкого значения (следовательно, улучшить правильность заголовка)? - person Laurent Crivello; 13.01.2015
comment
У меня тоже есть проблемы с получением точного результата. Я использую тот же метод, что описан выше, и моя точность составляет около 10-20. Также хотелось бы услышать, есть ли способ получить более точный результат. - person Viktor Nilsson; 16.08.2015
comment
Когда я использую GLKMathRadiansToDegrees для преобразования angleInRadian в градусы, я получаю значение, которое сильно отличается от CLHeading. На шаге 0, когда курс равен 360, угол InRadian (преобразованный в градусы) равен -93. Что могло быть причиной этого? - person menawi; 20.09.2016
comment
@Chee Привет, у меня такая же задача: приведенный выше код будет работать с координатами GPS. У меня есть координаты пункта назначения из камеры. Я могу показать направление по этому коду? - person batMan007; 20.07.2018

Чтобы сэкономить время других, вот ответ Чи на 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
    }
person W.K.S    schedule 20.09.2016