Given coordinates (lon, lat), altitude of UAV, and Euler angles of the camera (yaw, pitch, roll), how do I calculate the projection of points in a photograph using quaternions?
This is my function (angles in radians):
let alphaX = 2 * atan(36 / (2.0 * focalLength)
let alphaY = 2 * atan(24 / (2.0 * focalLength)
let dx = altitude * tan(alphaX / 2.0)
let dy = altitude * tan(alphaY / 2.0)
let v =
GLKVector3Make(dx, dy, altitude) // for top right corner
func quaternionMethod(v: GLKVector3, droneCoordinate: Coordinate, yaw: Float, pitch: Float, roll: Float) -> Coordinate {
let axisQuaternion = GLKQuaternionMakeWithVector3(v, 0)
let cy = cos(yaw / 2)
let cp = cos(pitch / 2)
let cr = cos(roll / 2)
let sy = sin(yaw / 2)
let sp = sin(pitch / 2)
let sr = sin(roll / 2)
let eulerQuaternion = GLKQuaternionMake(cr*cp*cy+sr*sp*sy,
sr*cp*cy+cr*sp*sy,
cr*sp*cy+sr*cp*sy,
cr*cp*sy+sr*sp*cy)
let eulerInvers = GLKQuaternionInvert(eulerQuaternion)
let r = GLKQuaternionMultiply(eulerQuaternion, axisQuaternion)
let rotatedQuaternion = GLKQuaternionMultiply(r, eulerInvers)
let rotatedVector = GLKQuaternionAxis(rotatedQuaternion)
let rotated = GLKVector3Multiply(rotatedVector, v)
var coordinate = droneCoordinate.addDistance(inMeters: Double(rotated.x), withBearingInRadians: Double.pi)
coordinate = coordinate.addDistance(inMeters: Double(rotated.y), withBearingInRadians: Double.pi/2)
return coordinate
}
I have taken a photo with a drone at an altitude of 100 m and a pitch angle of 40 degrees down from horizontal and yaw -88 degrees from north, at a ground control point in about the middle of the image. Marked on map with GCP.
My expected results when plotting the corner points of the image should be something like this:

Instead my result using the function above looks like this:

I suspect there is something wrong with the way I add the vector components to the initial drone coordinate after the rotation. I'm not sure what bearings to use. I suspect I also should add the z component of the vector, but at what angle?