Example #1
0
def prepare_imugps_Hyspex(processed_imugps_file, raw_imugps_file,
                          boresight_offsets, map_crs, boresight_options):
    """ Prepare Hyspex IMU and GPS data.

    Parameters
    ----------
    processed_imugps_file: str
        Processed IMUGPS filename.
    raw_imugps_file: str
        Raw IMUGPS filename.
    boresight_offsets: list of float
        Boresight offsets, [roll_offset, pitch_offset, heading_offset, altitude_offset].
    boresight_options: list of boolean
        Boresight offset options, true or false.
    map_crs: osr object
        Map coordinate system.
    """

    if os.path.exists(processed_imugps_file):
        logger.info('Write the IMU and GPS data to %s.' %
                    processed_imugps_file)
        return

    from Geography import define_wgs84_crs, get_grid_convergence

    # Load raw GPS & IMU data
    raw_imugps = np.loadtxt(raw_imugps_file)

    # Apply boresight offsets
    processed_imugps = np.zeros((raw_imugps.shape[0], 15))

    # Scan line index
    processed_imugps[:, 0] = raw_imugps[:, 0]

    # GPS & IMU
    wgs84_crs = define_wgs84_crs()
    transform = osr.CoordinateTransformation(wgs84_crs, map_crs)
    xyz = np.array(transform.TransformPoints(raw_imugps[:, 1:3]))
    processed_imugps[:, 1] = xyz[:, 0]  # Flight easting
    processed_imugps[:, 2] = xyz[:, 1]  # Flight northing
    processed_imugps[:, 3] = raw_imugps[:, 3]  # Flight altitude
    processed_imugps[:, 4] = raw_imugps[:, 4]  # Roll
    processed_imugps[:, 5] = raw_imugps[:, 5]  # Pitch
    processed_imugps[:, 6] = raw_imugps[:, 6]  # Heading
    del transform, xyz

    # Boresight offsets
    for i in range(len(boresight_options)):
        if boresight_options[i]:
            processed_imugps[:, 7 + i] = boresight_offsets[i]

    # Grid convergence
    grid_convergence = get_grid_convergence(raw_imugps[:, 1], raw_imugps[:, 2],
                                            map_crs)
    processed_imugps[:, 11] = grid_convergence

    # Longitude & latitude
    processed_imugps[:, 12] = raw_imugps[:, 1]  # Longitude
    processed_imugps[:, 13] = raw_imugps[:, 2]  # Latitude

    # Timestamp
    processed_imugps[:, 14] = raw_imugps[:, 7]

    # Write updated GPS & IMU data to file
    header = [
        'Map coordinate system = %s' % (map_crs.ExportToWkt()), 'Index    ' +
        'Map_X    Map_Y    Map_Z    Roll    Pitch    Heading    ' +
        'Roll_Offset    Pitch_Offset    Heading_Offset    Altitude_Offset    Grid_Convergence    '
        + 'Longitude    Latitude    ' + 'Timestamp'
    ]
    np.savetxt(
        processed_imugps_file,
        processed_imugps,
        header='\n'.join(header),
        fmt=
        '%d    %.3f    %.3f    %.3f    %.10f    %.10f    %.10f    %.10f    %.10f    %.10f    %.10f    %.10f    %.10f    %.10f    %.5f'
    )
    logger.info('Write the IMU and GPS data to %s.' % processed_imugps_file)
Example #2
0
def boresight_calibration(boresight_file, gcp_file, imugps_file,
                          sensor_model_file, dem_image_file,
                          boresight_options):
    """ Do boresight calibration.
    Arguments:
        boresight_file: str
            Boresight filename.
        gcp_file: str
            Ground control points filename.
        igm_image_file: str
            The IGM image filename.
        imugps_file: str
            The IMUGPS filename.
        sensor_model_file: str
            The sensor model filename.
        dem_image_file: str
            The DEM image filename.
        boresight_options: list of boolean
            Boresight offset options, true or false.
    """

    if os.path.exists(boresight_file):
        logger.info('Write boresight data to %s.' % boresight_file)
        return

    from osgeo import gdal, osr
    from Geography import define_wgs84_crs
    from scipy import optimize

    # Read IMU and GPS data.
    imugps = np.loadtxt(
        imugps_file
    )  # ID, X, Y, Z, R, P, H, Timestamp, Longitude, Latitude, Grid_Convergence, Roll...

    # Read sensor model data.
    sensor_model = np.loadtxt(sensor_model_file, skiprows=1)[:, 1:]

    # Read DEM data.
    ds = gdal.Open(dem_image_file, gdal.GA_ReadOnly)
    dem_image = ds.GetRasterBand(1).ReadAsArray()
    dem_geotransform = ds.GetGeoTransform()
    dem_prj = ds.GetProjection()
    ds = None

    # Read GCP data.
    gcp_data = np.loadtxt(
        gcp_file, comments=';')  # Longitude, Latitude, Image Column, Image Row

    # Convert gcp longitudes and latitudes to map x and y.
    wgs84_crs = define_wgs84_crs()
    map_crs = osr.SpatialReference()
    map_crs.ImportFromWkt(dem_prj)
    transform = osr.CoordinateTransformation(wgs84_crs, map_crs)
    gcp_xyz = np.array(transform.TransformPoints(gcp_data[:, :2]))
    del wgs84_crs, transform

    # Interpolate flight imu and xyz.
    lines = np.arange(imugps.shape[0])
    flight_xyz = np.zeros((gcp_data.shape[0], 3))
    flight_xyz[:, 0] = np.interp(gcp_data[:, 3] - 1, lines, imugps[:, 1])
    flight_xyz[:, 1] = np.interp(gcp_data[:, 3] - 1, lines, imugps[:, 2])
    flight_xyz[:, 2] = np.interp(gcp_data[:, 3] - 1, lines, imugps[:, 3])

    flight_imu = np.zeros((gcp_data.shape[0], 3))
    flight_imu[:, 0] = np.interp(gcp_data[:, 3] - 1, lines, imugps[:, 4])
    flight_imu[:, 1] = np.interp(gcp_data[:, 3] - 1, lines, imugps[:, 5])
    flight_imu[:, 2] = np.interp(gcp_data[:, 3] - 1, lines, imugps[:, 6])

    # Apply grid convergence.
    flight_imu[:, 2] = flight_imu[:, 2] - np.interp(gcp_data[:, 3] - 1, lines,
                                                    imugps[:, 11])
    del lines

    # Interpolate sensor model.
    samples = np.arange(sensor_model.shape[0])
    flight_sensor_model = np.zeros((gcp_data.shape[0], 2))
    flight_sensor_model[:, 0] = np.interp(gcp_data[:, 2] - 1, samples,
                                          sensor_model[:, 0])
    flight_sensor_model[:, 1] = np.interp(gcp_data[:, 2] - 1, samples,
                                          sensor_model[:, 1])
    del samples

    # Optimize.
    p = optimize.minimize(cost_fun, [0, 0, 0, 0],
                          method='L-BFGS-B',
                          args=(flight_xyz, flight_imu, flight_sensor_model,
                                dem_image,
                                [dem_geotransform[0],
                                 dem_geotransform[3]], dem_geotransform[1],
                                gcp_xyz, boresight_options))
    logger.info('Roll, pitch, heading and altitude offsets: %s, %s, %s, %s' %
                (p.x[0], p.x[1], p.x[2], p.x[3]))

    # Save offsets.
    imugps[:, 7] = p.x[0]
    imugps[:, 8] = p.x[1]
    imugps[:, 9] = p.x[2]
    imugps[:, 10] = p.x[3]
    header = [
        'Map coordinate system = %s' % (map_crs.ExportToWkt()),
        'Index    Map_X    Map_Y    Map_Z    Roll    Pitch    Heading    ' +
        'Roll_Offset    Pitch_Offset    Heading_Offset    Altitude_Offset    Grid_Convergence    '
        + 'Longitude    Latitude    Timestamp'
    ]
    np.savetxt(
        imugps_file,
        imugps,
        header='\n'.join(header),
        fmt=
        '%d    %.3f    %.3f    %.3f    %.10f    %.10f    %.10f    %.10f    %.10f    %.10f    %.10f    %.10f    %.10f    %.10f    %.5f'
    )

    # Estimate geometric correction accuracy.
    est_gcp_xyz = estimate_gcp_xyz(p.x, flight_xyz, flight_imu,
                                   flight_sensor_model, dem_image,
                                   [dem_geotransform[0], dem_geotransform[3]],
                                   dem_geotransform[1], boresight_options)
    boresight_data = np.zeros((gcp_data.shape[0], 10))
    boresight_data[:, 0] = np.arange(gcp_data.shape[0])
    boresight_data[:, 1] = gcp_data[:, 2]
    boresight_data[:, 2] = gcp_data[:, 3]
    boresight_data[:, 3] = gcp_xyz[:, 0]
    boresight_data[:, 4] = gcp_xyz[:, 1]
    boresight_data[:, 5] = est_gcp_xyz[:, 0]
    boresight_data[:, 6] = est_gcp_xyz[:, 1]
    boresight_data[:, 7] = gcp_xyz[:, 0] - est_gcp_xyz[:, 0]
    boresight_data[:, 8] = gcp_xyz[:, 1] - est_gcp_xyz[:, 1]
    boresight_data[:, 9] = np.sqrt(boresight_data[:, 7]**2 +
                                   boresight_data[:, 8]**2)
    header = [
        'Map coordinate system = %s' % (map_crs.ExportToWkt()),
        'Roll offset = %s' % (p.x[0]),
        'Pitch offset = %s' % (p.x[1]),
        'Heading offset = %s' % (p.x[2]),
        'Altitude offset = %s' % (p.x[3]),
        'Min RMS = %.4f' % (boresight_data[:, 9].min()),
        'Mean RMS = %.4f' % (boresight_data[:, 9].mean()),
        'Max RMS = %.4f' % (boresight_data[:, 9].max()),
        'Index    Image_X    Image_Y    Map_X    Map_Y    Predict_X    Predict_Y    Error_X    Error_Y    RMS'
    ]
    np.savetxt(
        boresight_file,
        boresight_data,
        header='\n'.join(header),
        fmt=
        '%d    %.3f    %.3f    %.3f    %.3f    %.3f    %.3f    %.3f    %.3f    %.3f'
    )
    logger.info('Boresight accuracy (min, mean, max): %.2f, %.2f, %2.f.' %
                (boresight_data[:, 9].min(), boresight_data[:, 9].mean(),
                 boresight_data[:, 9].max()))
    del boresight_data

    logger.info('Write boresight data to %s.' % boresight_file)