def test_plyflatten(): # Test data f = data_path("input_ply/cloud.ply") raster, profile = s2p.rasterization.plyflatten_from_plyfiles_list( [f], resolution=0.4) test_raster = raster[:, :, 0] # keep only band with height # Expected data e = data_path("expected_output/plyflatten/dsm_40cm.tiff") with rasterio.open(e) as src: expected_raster = src.read(1) expected_crs = src.crs expected_transform = src.transform expected_is_tiled = src.is_tiled expected_nodata = src.nodata # Check that both rasters are equal pixel-wise within a tolerance assert np.allclose(test_raster, expected_raster, equal_nan=True) # Check that both images have the same CRS test_crs = rasterio.crs.CRS.from_proj4(profile['crs']) assert test_crs == expected_crs # Check that both images have the same transform test_transform = profile['transform'] assert np.allclose(test_transform, expected_transform) test_is_tiled = profile['tiled'] assert test_is_tiled == expected_is_tiled test_nodata = profile.get('nodata') if expected_nodata and math.isnan(expected_nodata): assert math.isnan(test_nodata) else: assert test_nodata == expected_nodata
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 test_matching(): """ """ computed = sift.keypoints_match(np.loadtxt(data_path('units/sift1.txt')), np.loadtxt(data_path('units/sift2.txt'))) expected = np.loadtxt( data_path('expected_output/units/unit_keypoints_match.txt')) assert_arrays_are_equal(computed, expected)
def test_matching(): """ Unit test for the function s2p.sift.keypoints_match. """ computed = sift.keypoints_match(np.loadtxt(data_path('units/sift1.txt')), np.loadtxt(data_path('units/sift2.txt'))) expected = np.loadtxt(data_path('expected_output/units/unit_keypoints_match.txt')) np.testing.assert_allclose(computed, expected, rtol=0.01, atol=0.1, verbose=True)
def test_image_keypoints(): """ Unit test for the function s2p.sift.image_keypoints. Right now it tests only the x, y, scale, orientation of keypoints, not the descriptors. """ computed = sift.image_keypoints(data_path('input_triplet/img_02.tif'), 100, 100, 200, 200) expected = np.loadtxt(data_path('expected_output/units/unit_image_keypoints.txt')) np.testing.assert_allclose(computed[:, :4], expected[:, :4], atol=1e-3)
def test_compute_disparity_map_timeout(timeout=1): """ Run a long call to compute_disparity_map to check that the timeout kills it. """ img = data_path(os.path.join("input_pair", "img_01.tif")) disp = data_path(os.path.join("testoutput", "d.tif")) mask = data_path(os.path.join("testoutput", "m.tif")) with pytest.raises(subprocess.TimeoutExpired): s2p.block_matching.compute_disparity_map(img, img, disp, mask, "mgm_multi", -100, 100, timeout)
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 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_compute_disparity_map_max_disp_range(max_disp_range=10): """ Run a call to compute_disparity_map with a small max_disp_range to check that an error is raised. """ img = data_path(os.path.join("input_pair", "img_01.tif")) disp = data_path(os.path.join("testoutput", "d.tif")) mask = data_path(os.path.join("testoutput", "m.tif")) with pytest.raises(s2p.block_matching.MaxDisparityRangeError): s2p.block_matching.compute_disparity_map(img, img, disp, mask, "mgm_multi", -100, 100, max_disp_range=max_disp_range)
def test_rectification_homographies(matches): """ Test for rectification.rectification_homographies(). """ x, y, w, h = 100, 100, 200, 200 H1, H2, F = s2p.rectification.rectification_homographies(matches, x, y, w, h) for variable, filename in zip([H1, H2, F], ['H1.txt', 'H2.txt', 'F.txt']): expected = np.loadtxt(data_path(os.path.join('expected_output', 'units', filename))) np.testing.assert_allclose(variable, expected, rtol=0.01, atol=1e-6, verbose=True)
def fixture_data(tmp_path): """ Copy the test data to a temporary directory """ img1 = data_path(os.path.join("input_pair", "img_01.tif")) with rasterio.open(img1) as f: rpc1 = rpcm.RPCModel(f.tags(ns="RPC")) shutil.copy(img1, tmp_path / "img_01.tif") img2 = data_path(os.path.join("input_pair", "img_02.tif")) with rasterio.open(img2) as f: rpc2 = rpcm.RPCModel(f.tags(ns="RPC")) shutil.copy(img2, tmp_path / "img_02.tif") config = data_path(os.path.join("input_pair", "config.json")) tmp_config = tmp_path / "config.json" shutil.copy(config, tmp_config) return tmp_config, tmp_path, rpc1, rpc2
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_disparity_to_ply(tmp_path, out_crs): """ Check that disparity_to_ply() functions correctly when given different out_crs parameters """ # Setup test data tile_dir = str(tmp_path / "tile_dir") shutil.copytree(data_path("input_triangulation"), tile_dir) # Initialize s2p's state config_file = data_path(os.path.join("input_pair", "config.json")) test_cfg = read_config_file(config_file) test_cfg["out_crs"] = out_crs build_cfg(test_cfg) tile = {"coordinates": [500, 150, 350, 350], "dir": tile_dir} disparity_to_ply(tile) _, comments = read_3d_point_cloud_from_ply( os.path.join(tile_dir, "cloud.ply")) expected_crs = out_crs or "epsg:32740" assert comments[-1] == "projection: CRS {}".format(expected_crs)
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 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)
def test_distributed_plyflatten(): config_file = data_path('input_triplet/config.json') print('Running end2end with distributed plyflatten dsm ...') test_cfg = s2p.read_config_file(config_file) s2p.main(test_cfg) outdir = test_cfg['out_dir'] computed = common.gdal_read_as_array_with_nans( os.path.join(outdir, 'dsm.tif')) print('Running plyflatten dsm reference ...') clouds_list = glob.glob( os.path.join(outdir, "tiles", "*", "*", "cloud.ply")) out_dsm = os.path.join(outdir, "dsm_ref.tif") res = test_cfg['dsm_resolution'] roi = None if 'utm_bbx' in test_cfg: bbx = test_cfg['utm_bbx'] global_xoff = bbx[0] global_yoff = bbx[3] global_xsize = int( np.ceil((bbx[1] - bbx[0]) / test_cfg['dsm_resolution'])) global_ysize = int( np.ceil((bbx[3] - bbx[2]) / test_cfg['dsm_resolution'])) roi = (global_xoff, global_yoff, global_xsize, global_ysize) raster, profile = s2p.rasterization.plyflatten_from_plyfiles_list( clouds_list, resolution=res, roi=roi) s2p.common.rasterio_write(out_dsm, raster[:, :, 0], profile=profile) expected = common.gdal_read_as_array_with_nans( os.path.join(outdir, 'dsm_ref.tif')) compare_dsm(computed, expected, 0, 0)
def test_distributed_plyflatten(): print('Running end2end with distributed plyflatten dsm ...') test_cfg = s2p.read_config_file(data_path('input_triplet/config.json')) s2p.main(test_cfg) outdir = test_cfg['out_dir'] computed = common.gdal_read_as_array_with_nans( os.path.join(outdir, 'dsm.tif')) print('Running plyflatten dsm reference ...') clouds_list = glob.glob( os.path.join(outdir, "tiles", "*", "*", "cloud.ply")) res = test_cfg['dsm_resolution'] roi = None raster, _ = plyflatten_from_plyfiles_list(clouds_list, resolution=res, roi=roi) expected = raster[:, :, 0] compare_dsm(computed, expected, 0, 0)
def test_end2end_triplet(): end2end(data_path('input_triplet/config.json'), data_path('expected_output/triplet/dsm.tif'), 0.05, 2)
@pytest.mark.parametrize( "use_srtm, exogenous_dem, exogenous_dem_geoid_mode, expected", [ ( False, None, True, (271.48531, 1.59019, 407.37861, 413.53010), ), ( True, None, True, (353.49632, 296.69818, 408.16015, 413.54849), ), (False, data_path(os.path.join("expected_output", "pair", "dsm.tif")), True, (356.65154, 308.01931, 408.19018, 413.54920)), ( False, data_path(os.path.join("expected_output", "pair", "dsm.tif")), False, (356.46596, 307.35347, 408.18841, 413.54916), ), ], ) def test_roi_process(use_srtm, exogenous_dem, exogenous_dem_geoid_mode, expected): """ Test for rpc_utils.roi_process(). """ rpc = rpcm.rpc_from_geotiff(
def fixture_matches(): matches = np.loadtxt( data_path(os.path.join('expected_output', 'units', 'unit_matches_from_rpc.txt')) ) return matches
def test_end2end_pair(): end2end(data_path('input_pair/config.json'), data_path('expected_output/pair/dsm.tif'), 0.025, 1)
def test_end2end_mosaic(): end2end_mosaic(data_path('input_triplet/config.json'), data_path('expected_output/triplet/height_map.tif'), 0.05, 2)
def test_image_keypoints(): """ """ kpts = sift.image_keypoints(data_path('input_triplet/img_02.tif'), 100, 100, 200, 200) ref_kpts = np.loadtxt( data_path('expected_output/units/unit_image_keypoints.txt')) test_set = set(map(tuple, kpts[:, 0:2])) ref_set = set(map(tuple, ref_kpts[:, 0:2])) print( str(kpts.shape[0] - len(test_set)) + " spatially redundant kpts found in test") print( str(ref_kpts.shape[0] - len(ref_set)) + " spatially redundant kpts found in ref") common_set = test_set.intersection(ref_set) print( str(len(test_set) - len(common_set)) + " kpts found in test but not in ref") print( str(len(ref_set) - len(common_set)) + " kpts found in ref but not in test") dist_tol = 0.01 nb_test_not_in_ref = 0 for i in range(kpts.shape[0]): found = False for j in range(ref_kpts.shape[0]): dist = np.linalg.norm(kpts[i, 0:1] - ref_kpts[j, 0:1]) if dist < dist_tol: found = True if not found: print("KeyPoint not found: " + str((kpts[i, 0:1]))) nb_test_not_in_ref += 1 print( str(nb_test_not_in_ref) + " test kpts have no spatially close match in ref") nb_ref_not_in_test = 0 for i in range(kpts.shape[0]): found = False for j in range(ref_kpts.shape[0]): dist = np.linalg.norm(kpts[i, 0:1] - ref_kpts[j, 0:1]) if dist < dist_tol: found = True if not found: print("KeyPoint not found: " + str((kpts[i, 0:1]))) nb_ref_not_in_test += 1 print( str(nb_ref_not_in_test) + " ref kpts have no spatially close match in test") np.testing.assert_equal(nb_ref_not_in_test, 0) np.testing.assert_equal(nb_test_not_in_ref, 0)