def roll_and_pitch_from_world_to_image_correspondence(camera, correspondence): """ Computes the instantaneous roll and pitch of an image row from one gcp. Args: camera: instance of the ps.PushbroomCamera class correspondence: list [r, c, h, lon, lat] which defines a correpondence between the pixel (r, c) at row r and column c and the 3-space point whose geographic coordinates, in degrees, are (lon, lat) and height above the Earth, in meters, is h. Returns: roll and pitch values, in radians """ r, c, h, lon, lat = correspondence t = r * camera.instrument.dwell_time # time associated to the row # a: coordinates of the '3d image point' located on the image plane R = utils.elemental_rotation_3d('z', np.polyval(camera.poly_psi, t)) # yaw a = np.dot(R, camera.instrument.sight_vector(c)) # b: coordinates of the ground control point b = np.dot(camera.rotational_to_orbital(t).T, utils.geo_to_cartesian(lon, lat, h)) b += np.array([0, 0, camera.orbit.radius]) b /= np.linalg.norm(b) # compute the needed roll and pitch angles return roll_and_pitch_mapping_a_to_b(a, b)
def roll_and_pitch_from_world_to_image_correspondence(camera, correspondence): """ Computes the instantaneous roll and pitch of an image row from one gcp. Args: camera: instance of the ps.PushbroomCamera class correspondence: list [r, c, h, lon, lat] which defines a correpondence between the pixel (r, c) at row r and column c and the 3-space point whose geographic coordinates, in degrees, are (lon, lat) and height above the Earth, in meters, is h. Returns: roll and pitch values, in radians """ r, c, h, lon, lat = correspondence t = r * camera.instrument.dwell_time # time associated to the row # a: coordinates of the '3d image point' located on the image plane R = utils.elemental_rotation_3d('z', np.polyval(camera.poly_psi, t)) # yaw a = np.dot(R, camera.instrument.sight_vector(c)) # b: coordinates of the ground control point b = np.dot( camera.rotational_to_orbital(t).T, utils.geo_to_cartesian(lon, lat, h)) b += np.array([0, 0, camera.orbit.radius]) b /= np.linalg.norm(b) # compute the needed roll and pitch angles return roll_and_pitch_mapping_a_to_b(a, b)
def roll_and_pitch_mapping_a_to_b(a, b): """ Computes the roll and pitch needed to map a point on another, on a sphere. The two input points are given by their cartesian coordinates (x, y, z). The computed angles phi and psi are such that the rotation obtained by composing an elemental rotation of phi about the x-axis with an elemental rotation of psi about the new y-axis maps a to b. Args: a, b: two array-like objects of length 3. Returns: phi, psi: the two roll and pitch angles such that R_x(phi)R_y(psi)a = b. """ # checks that the input 3d points are on the same sphere np.testing.assert_allclose(np.linalg.norm(a), np.linalg.norm(b)) # compute the roll angle phi x = utils.solve_acos_plus_bsin_plus_c(b[1], b[2], -a[1]) # compute the pitch angle psi bb = np.dot(np.linalg.inv(utils.elemental_rotation_3d('x', x)), b) y = np.arctan2(bb[0], bb[2]) - np.arctan2(a[0], a[2]) # check that the composition of R_x(phi) and R_y(psi) maps a to b np.testing.assert_allclose(np.dot(utils.rotation_3d('xyz', x, y, 0), a), b) return x, y