def test_matches_on_rpc_roi(): """ Unit test for the function sift.matches_on_rpc_roi. """ img1 = data_path('input_triplet/img_01.tif') img2 = data_path('input_triplet/img_02.tif') rpc1 = rpcm.rpc_from_geotiff(img1) rpc2 = rpcm.rpc_from_geotiff(img2) computed = sift.matches_on_rpc_roi(img1, img2, rpc1, rpc2, 100, 100, 200, 200, method='relative', sift_thresh=0.6, epipolar_threshold=10) expected = np.loadtxt( data_path('expected_output/units/matches_on_rpc_roi.txt')) np.testing.assert_allclose(computed, expected, rtol=0.01, atol=0.1, verbose=True)
def get_angles(ref_filename, sec_filename): ref_rpc = rpcm.rpc_from_geotiff(ref_filename) sec_rpc = rpcm.rpc_from_geotiff(sec_filename) width, height, pixel_dim = s2p.common.image_size_gdal(ref_filename) # get the rpc of the first image ref_image_rpc = rpcm.rpc_from_geotiff(ref_filename) # get the localization of the center of the image lon_center, lat_center = ref_image_rpc.localization( width // 2, height // 2, 0) ref_zenith, ref_azimut = ref_rpc.incidence_angles(lon_center, lat_center, z=0) sec_zenith, sec_azimut = sec_rpc.incidence_angles(lon_center, lat_center, z=0) ref_sec_angle = rpcm.angle_between_views(ref_filename, sec_filename, lon_center, lat_center, z=0) return ref_zenith, ref_azimut, sec_zenith, sec_azimut, ref_sec_angle
def test_matches_on_rpc_roi(): """ Test SIFT matching of two image ROIs. """ img1 = data_path('input_triplet/img_01.tif') img2 = data_path('input_triplet/img_02.tif') rpc1 = rpcm.rpc_from_geotiff(data_path('input_triplet/img_01.tif')) rpc2 = rpcm.rpc_from_geotiff(data_path('input_triplet/img_02.tif')) computed = s2p.sift.matches_on_rpc_roi(img1, img2, rpc1, rpc2, 100, 100, 200, 200) expected = np.loadtxt( data_path('expected_output/units/matches_on_rpc_roi.txt')) assert_arrays_are_equal(computed, expected)
def get_coordinates_with_config(tile, m, M): tile_cfg = s2p.read_config_file(os.path.join(tile, "config.json")) x = tile_cfg['roi']['x'] y = tile_cfg['roi']['y'] w = tile_cfg['roi']['w'] h = tile_cfg['roi']['h'] rpc = rpcm.rpc_from_geotiff(tile_cfg['images'][0]['img']) a = np.array([x, x, x, x, x+w, x+w, x+w, x+w]) b = np.array([y, y, y+h, y+h, y, y, y+h, y+h]) c = np.array([m, M, m, M, m, M, m, M]) lon, lat, __ = rpc.direct_estimate(a, b, c) out = list(common.bounding_box2D(np.vstack([lon, lat]).T)) out[2] += out[0] out[3] += out[1] latlon = [[out[0], out[3], 0], [out[2], out[3], 0], [out[2], out[1], 0], [out[0], out[1], 0], [out[0], out[3], 0]] return latlon
def vissat_meta_from_geotiff(image_filename): geotiff_meta = readGTIFFmeta(image_filename) rpc = rpcm.rpc_from_geotiff(image_filename) meta_dict = {} rpc_dict = {} rpc_dict['rowOff'] = rpc.row_offset rpc_dict['rowScale'] = rpc.row_scale rpc_dict['colOff'] = rpc.col_offset rpc_dict['colScale'] = rpc.col_scale rpc_dict['latOff'] = rpc.lat_offset rpc_dict['latScale'] = rpc.lat_scale rpc_dict['lonOff'] = rpc.lon_offset rpc_dict['lonScale'] = rpc.lon_scale rpc_dict['altOff'] = rpc.alt_offset rpc_dict['altScale'] = rpc.alt_scale # polynomial coefficients rpc_dict['rowNum'] = rpc.row_num rpc_dict['rowDen'] = rpc.row_den rpc_dict['colNum'] = rpc.col_num rpc_dict['colDen'] = rpc.col_den # width, height meta_dict['width'] = geotiff_meta[0]['width'] meta_dict['height'] = geotiff_meta[0]['height'] meta_dict['rpc'] = rpc_dict return meta_dict
def check_parameters(d): """ Check that the provided dictionary defines all mandatory s2p arguments. Args: d: python dictionary """ # verify that input files paths are defined if 'images' not in d or len(d['images']) < 2: print('ERROR: missing paths to input images') sys.exit(1) for img in d['images']: if not dict_has_keys(img, ['img']): print('ERROR: missing img paths for image', img) sys.exit(1) # read RPCs for img in d['images']: if 'rpc' in img: if isinstance(img['rpc'], str): # path to an RPC file img['rpcm'] = rpcm.rpc_from_rpc_file(img['rpc']) elif isinstance(img['rpc'], dict): # RPC dict in 'rpcm' format img['rpcm'] = rpcm.RPCModel(img['rpc'], dict_format='rpcm') else: raise NotImplementedError( 'rpc of type {} not supported'.format(type(img['rpc']))) else: img['rpcm'] = rpcm.rpc_from_geotiff(img['img']) # verify that an input ROI is defined if 'full_img' in d and d['full_img']: sz = common.image_size_gdal(d['images'][0]['img']) d['roi'] = {'x': 0, 'y': 0, 'w': sz[0], 'h': sz[1]} elif 'roi' in d and dict_has_keys(d['roi'], ['x', 'y', 'w', 'h']): pass elif 'roi_geojson' in d: ll_poly = geographiclib.read_lon_lat_poly_from_geojson( d['roi_geojson']) d['roi'] = rpc_utils.roi_process( d['images'][0]['rpcm'], ll_poly, use_srtm=d.get('use_srtm'), exogenous_dem=d.get('exogenous_dem'), exogenous_dem_geoid_mode=d.get('exogenous_dem_geoid_mode')) else: print('ERROR: missing or incomplete roi definition') sys.exit(1) # d['roi'] : all the values must be integers d['roi']['x'] = int(np.floor(d['roi']['x'])) d['roi']['y'] = int(np.floor(d['roi']['y'])) d['roi']['w'] = int(np.ceil(d['roi']['w'])) d['roi']['h'] = int(np.ceil(d['roi']['h'])) # warn about unknown parameters. The known parameters are those defined in # the global config.cfg dictionary, plus the mandatory 'images' and 'roi' for k in d.keys(): if k not in ['images', 'roi', 'roi_geojson']: if k not in cfg: print('WARNING: ignoring unknown parameter {}.'.format(k))
def fixture_images(): res = [] for i in [1, 2]: im = data_path(os.path.join('input_pair', 'img_0{}.tif'.format(i))) rpc = rpc_from_geotiff(im) res.append(im) res.append(rpc) return res
def test_matches_from_rpc(): """ Test for rpc_utils.matches_from_rpc(). """ r1 = rpcm.rpc_from_geotiff( data_path(os.path.join('input_pair', 'img_01.tif'))) r2 = rpcm.rpc_from_geotiff( data_path(os.path.join('input_pair', 'img_02.tif'))) test_matches = rpc_utils.matches_from_rpc(r1, r2, 100, 100, 200, 200, 5) expected_matches = np.loadtxt( data_path( os.path.join('expected_output', 'units', 'unit_matches_from_rpc.txt'))) np.testing.assert_equal(test_matches.shape[0], 125, verbose=True) np.testing.assert_allclose(test_matches, expected_matches, rtol=0.01, atol=0.1, verbose=True)
def test_roi_process(): """ Test for rpc_utils.roi_process(). """ rpc = rpcm.rpc_from_geotiff( data_path(os.path.join('input_pair', 'img_01.tif'))) ll_poly = np.asarray([[55.649517, -21.231542], [55.651502, -21.231542], [55.651502, -21.229672], [55.649517, -21.229672]]) computed = [ rpc_utils.roi_process(rpc, ll_poly)[k] for k in ['x', 'y', 'w', 'h'] ] expected = (271.48531909338635, 1.5901905457030807, 407.3786143153775, 413.5301010405019) np.testing.assert_allclose(computed, expected, atol=1e-3)
def try_rpcm(img, x, y): try: import rpcm except ImportError as e: print('Cannot import rpcm:', e) return try: rpc = rpcm.rpc_from_geotiff(img) import srtm4 z = srtm4.srtm4(rpc.lon_offset, rpc.lat_offset) lon, lat = rpc.localization(x, y, z) except Exception as e: print('Error while localization:', e) return return lon, lat
def rpc2map(img, imgx, imgy, imgz=0): """ generate 3D world coordinates from input image pixel coordinates using the RPC model See rpcm: https://github.com/cmla/rpcm/blob/master/rpcm/rpc_model.py for implementation Parameters ---------- img: str path to image file containing RPC in in gdal tags imgx,imgy,imgz: int/float Image x,y in pixel units, z: height in world coordinates Returns ---------- mx,my: np.arrays numpy arrays containing longitudes (mx) and latitudes (my) in geographic (EPSG:4326) coordinates """ rpc = rpc_from_geotiff(img) mx, my = rpc.localization(imgx, imgy, imgz) return mx, my
def crop_aoi(geotiff, aoi, z=0): """ Crop a geographic AOI in a georeferenced image using its RPC functions. Args: geotiff (string): path or url to the input GeoTIFF image file aoi (geojson.Polygon): GeoJSON polygon representing the AOI z (float, optional): base altitude with respect to WGS84 ellipsoid (0 by default) Return: crop (array): numpy array containing the cropped image x, y, w, h (ints): image coordinates of the crop. x, y are the coordinates of the top-left corner, while w, h are the dimensions of the crop. """ x, y, w, h = bounding_box_of_projected_aoi(rpcm.rpc_from_geotiff(geotiff), aoi, z) with rasterio.open(geotiff, 'r') as src: crop = src.read(window=((y, y + h), (x, x + w)), boundless=True).squeeze() return crop, x, y
def lon_lat_image_footprint(image, z=0): """ Compute the longitude, latitude footprint of an image using its RPC model. Args: image (str): path or url to a GeoTIFF file z (float): altitude (in meters above the WGS84 ellipsoid) used to convert the image corners pixel coordinates into longitude, latitude Returns: geojson.Polygon object containing the image footprint polygon """ rpc = rpcm.rpc_from_geotiff(image) with rasterio.open(image, 'r') as src: h, w = src.shape coords = [] for x, y, z in zip([0, w, w, 0], [0, 0, h, h], [z, z, z, z]): lon, lat = rpc.localization(x, y, z) coords.append([lon, lat]) return geojson.Polygon([coords])
def utm_zone(rpc, x, y, w, h): """ Compute the UTM zone where the ROI probably falls (or close to its border). Args: rpc: instance of the rpcm.RPCModel class, or path to a GeoTIFF file x, y, w, h: four integers defining a rectangular region of interest (ROI) in the image. (x, y) is the top-left corner, and (w, h) are the dimensions of the rectangle. Returns: a string of the form '18N' or '18S' where 18 is the utm zone identificator. """ # read rpc file if not isinstance(rpc, rpcm.RPCModel): rpc = rpcm.rpc_from_geotiff(rpc) # determine lat lon of the center of the roi, assuming median altitude lon, lat = rpc.localization(x + .5 * w, y + .5 * h, rpc.alt_offset)[:2] return geographiclib.compute_utm_zone(lon, lat)
def test_roi_process(use_srtm, exogenous_dem, exogenous_dem_geoid_mode, expected): """ Test for rpc_utils.roi_process(). """ rpc = rpcm.rpc_from_geotiff( data_path(os.path.join("input_pair", "img_01.tif"))) ll_poly = np.asarray([ [55.649517, -21.231542], [55.651502, -21.231542], [55.651502, -21.229672], [55.649517, -21.229672], ]) output = rpc_utils.roi_process( rpc, ll_poly, use_srtm=use_srtm, exogenous_dem=exogenous_dem, exogenous_dem_geoid_mode=exogenous_dem_geoid_mode, ) computed = [output[k] for k in ["x", "y", "w", "h"]] np.testing.assert_allclose(computed, expected, atol=1e-3)
common.run('gdal_translate -of VRT -a_ullr 0 0 %d %d %s %s' % (w, h, in_img_file, tmp_vrt)) common.run(('gdalwarp -co RPB=NO -co PROFILE=GeoTIFF -r %s -co "BIGTIFF=IF_NEEDED" -co "TILED=YES" -ovr NONE -overwrite -to SRC_METHOD=NO_GEOTRANSFORM -to DST_METHOD=NO_GEOTRANSFORM -tr' ' %d %d %s %s') % (filt, scale_x, scale_y, tmp_vrt, out_img_file)) try: # Remove aux files if any os.remove(out_img_file + ".aux.xml") except OSError: pass # Clean tmp vrt file os.remove(tmp_vrt) print("Done") # generate rpc file print("Generating {} ...".format(out_rcp_file)) r = rpcm.rpc_from_geotiff(in_img_file) r.linScale /= scale_y r.linOff /= scale_y r.colScale /= scale_x r.colOff /= scale_x r.write(out_rcp_file) print("Done") sys.exit(0)
'/home/agomez/Documents/iie/satelite/DATA/IARPA_DATA/ground_truth/mvs3d_gt_crop_05.tif' ] #output_dir = '/home/agomez/Documents/iie/satelite/DATA/IARPA_DATA/cropped' # Near in time images output_dir = '/media/agomez/SeagateGoFlex750GB/SATELITE/DATA/IARPA_DATA/cropped' # Far in time images keys = [2, 12, 20, 26, 33, 43] output_dir = '/media/agomez/SeagateGoFlex750GB/SATELITE/DATA/IARPA_DATA/cropped_far_in_time' for k in keys: image_filename = image_filenames_dict[k] rpc = rpcm.rpc_from_geotiff(image_filename) print(k, image_filename) _, image_name = os.path.split(image_filename) image_acquisition_date_string = image_name[16:29] for mvs3d_gt_crop_filename in mvs3d_gt_crop_filename_list: gt_filename = mvs3d_gt_crop_filename _, gt_name = os.path.split(gt_filename) gt_name_no_extension, _ = os.path.splitext(gt_name) gt_cropped_data_dir = os.path.join(output_dir, gt_name_no_extension) if not os.path.isdir(gt_cropped_data_dir): os.makedirs(gt_cropped_data_dir) # get aoi from gt
def aoi_info_from_geotiff_gt(ref_filename, gt_filename, padding=0.0, height_guard=[-5, +5]): ''' aoi_from_gt Returns an aoi from an image and a gt padding: relative to the size the gt region (e.g. 0.1 adds a 10% of the extension of the region on the four boundaries) ''' # get the dimensions of the first image width, height, pixel_dim = s2p.common.image_size_gdal(ref_filename) # get the rpc of the first image ref_image_rpc = rpcm.rpc_from_geotiff(ref_filename) # get the localization of the center of the image lon_center, lat_center = ref_image_rpc.localization( width // 2, height // 2, 0) zone_number = utm.latlon_to_zone_number(lat_center, lon_center) zone_letter = utm.latitude_to_zone_letter(lat_center) # Build the AOI of the GT ------------------------------ gt_metadata = readGTIFFmeta(gt_filename) bounding_box = gt_metadata[1] gt_min_easting = bounding_box.left gt_max_easting = bounding_box.right gt_min_northing = bounding_box.bottom gt_max_northing = bounding_box.top # padding gt_easting_extension = gt_max_easting - gt_min_easting gt_northing_extension = gt_max_northing - gt_min_northing gt_min_easting -= padding * gt_easting_extension gt_max_easting += padding * gt_easting_extension gt_min_northing -= padding * gt_northing_extension gt_max_northing += padding * gt_northing_extension # update the extension gt_easting_extension = gt_max_easting - gt_min_easting gt_northing_extension = gt_max_northing - gt_min_northing # convert easting, northing to lon,lat gt_min_lat, gt_min_lon = utm.to_latlon(gt_min_easting, gt_min_northing, zone_number, zone_letter) gt_max_lat, gt_max_lon = utm.to_latlon(gt_max_easting, gt_max_northing, zone_number, zone_letter) zone_hemisphere = 'N' if gt_min_lat > 0 else 'S' aoi = { 'coordinates': [[[gt_min_lon, gt_min_lat], [gt_min_lon, gt_max_lat], [gt_max_lon, gt_max_lat], [gt_max_lon, gt_min_lat], [gt_min_lon, gt_min_lat]]], 'type': 'Polygon' } utm_bbx = [ gt_min_easting, gt_max_easting, gt_min_northing, gt_max_northing ] lonlat_bbx = [gt_min_lon, gt_max_lon, gt_min_lat, gt_max_lat] # get min and max height from the gt image gt = s2p.common.gdal_read_as_array_with_nans(gt_filename) min_height, max_height = robust_image_min_max(gt) # add height guard min_height += height_guard[0] max_height += height_guard[1] return aoi, min_height, max_height, zone_hemisphere, zone_letter, zone_number, utm_bbx, lonlat_bbx
def check_parameters(d): """ Check that the provided dictionary defines all mandatory s2p arguments. Args: d: python dictionary """ # verify that input files paths are defined if 'images' not in d or len(d['images']) < 2: print('ERROR: missing paths to input images') sys.exit(1) for img in d['images']: if not dict_has_keys(img, ['img']): print('ERROR: missing img paths for image', img) sys.exit(1) # read RPCs for img in d['images']: if 'rpc' in img: if isinstance(img['rpc'], str): # path to an RPC file img['rpcm'] = rpcm.rpc_from_rpc_file(img['rpc']) elif isinstance(img['rpc'], dict): # RPC dict in 'rpcm' format img['rpcm'] = rpcm.RPCModel(img['rpc'], dict_format='rpcm') else: raise NotImplementedError( 'rpc of type {} not supported'.format(type(img['rpc']))) else: img['rpcm'] = rpcm.rpc_from_geotiff(img['img']) # verify that roi or path to preview file are defined if 'full_img' in d and d['full_img']: sz = common.image_size_gdal(d['images'][0]['img']) d['roi'] = {'x': 0, 'y': 0, 'w': sz[0], 'h': sz[1]} elif 'roi' in d and dict_has_keys(d['roi'], ['x', 'y', 'w', 'h']): pass elif 'roi_utm' in d and dict_has_keys( d['roi_utm'], ['utm_band', 'hemisphere', 'x', 'y', 'w', 'h']): d['roi'] = rpc_utils.utm_roi_to_img_roi(d['images'][0]['rpcm'], d['roi_utm'], d.get('use_srtm')) elif 'roi_kml' in d: # this call defines cfg['utm_zone'] and cfg['utm_bbx'] as side effects d['roi'] = rpc_utils.kml_roi_process(d['images'][0]['rpcm'], d['roi_kml'], d.get('utm_zone'), d.get('use_srtm')) elif 'roi_geojson' in d: # this call defines cfg['utm_zone'] and cfg['utm_bbx'] as side effects d['roi'] = rpc_utils.geojson_roi_process(d['images'][0]['rpcm'], d['roi_geojson'], d.get('utm_zone'), d.get('use_srtm')) else: print('ERROR: missing or incomplete roi definition') sys.exit(1) # d['roi'] : all the values must be integers d['roi']['x'] = int(np.floor(d['roi']['x'])) d['roi']['y'] = int(np.floor(d['roi']['y'])) d['roi']['w'] = int(np.ceil(d['roi']['w'])) d['roi']['h'] = int(np.ceil(d['roi']['h'])) # warn about unknown parameters. The known parameters are those defined in # the global config.cfg dictionary, plus the mandatory 'images' and 'roi' or # 'roi_utm' for k in d.keys(): if k not in [ 'images', 'roi', 'roi_kml', 'roi_geojson', 'roi_utm', 'utm_zone' ]: if k not in cfg: print('WARNING: ignoring unknown parameter {}.'.format(k))