diff --git a/cars/applications/resampling/resampling_tools.py b/cars/applications/resampling/resampling_tools.py index 5b1c20d5..520da208 100644 --- a/cars/applications/resampling/resampling_tools.py +++ b/cars/applications/resampling/resampling_tools.py @@ -310,13 +310,26 @@ def resample_image( oversampling = int(res_x) assert res_x == oversampling + grid_origin_x = grid_reader.transform[2] + grid_origin_y = grid_reader.transform[5] + assert grid_origin_x == grid_origin_y + grid_margin = -grid_origin_x / oversampling - 0.5 + assert grid_margin == int(grid_margin) + grid_margin = int(grid_margin) + # Convert resampled region to grid region with oversampling - grid_region = [ - math.floor(xmin / oversampling), - math.floor(ymin / oversampling), - math.ceil(xmax / oversampling), - math.ceil(ymax / oversampling), - ] + grid_region = np.array( + [ + math.floor(xmin / oversampling), + math.floor(ymin / oversampling), + math.ceil(xmax / oversampling), + math.ceil(ymax / oversampling), + ] + ) + # Out region of epipolar image + out_region = oversampling * grid_region + # Grid region + grid_region += grid_margin grid_window = Window.from_slices( (grid_region[1], grid_region[3] + 1), @@ -399,7 +412,6 @@ def resample_image( ).astype(int) # extract exact region - out_region = oversampling * np.array(grid_region) ext_region = block_region - out_region block_resamp = block_resamp[ ..., diff --git a/cars/core/geometry/shareloc_geometry.py b/cars/core/geometry/shareloc_geometry.py index f89f564c..5b6a0a94 100644 --- a/cars/core/geometry/shareloc_geometry.py +++ b/cars/core/geometry/shareloc_geometry.py @@ -63,6 +63,7 @@ def __init__( geoid=None, default_alt=None, pairs_for_roi=None, + rectification_grid_margin=0, ): super().__init__( geometry_plugin, @@ -75,6 +76,7 @@ def __init__( self.dem_roi = None self.roi_shareloc = None self.elevation = None + self.rectification_grid_margin = rectification_grid_margin # compute roi only when generating geometry object with dem # even if dem is None @@ -136,12 +138,15 @@ def get_roi(self, pairs_for_roi, epsg, margin=0.006): coords_list.extend(self.image_envelope(image1, geomodel1)) # Footprint of right image coords_list.extend(self.image_envelope(image2, geomodel2)) - # Epipolar extent + # Footprint of rectification grid (with margins) image1 = SharelocGeometry.load_image(image1) geomodel1 = self.load_geom_model(geomodel1) geomodel2 = self.load_geom_model(geomodel2) epipolar_extent = rectif.get_epipolar_extent( - image1, geomodel1, geomodel2 + image1, + geomodel1, + geomodel2, + grid_margin=self.rectification_grid_margin, ) lat_min, lon_min, lat_max, lon_max = list(epipolar_extent) coords_list.extend([(lon_min, lat_min), (lon_max, lat_max)]) @@ -380,6 +385,7 @@ def generate_epipolar_grids( shareloc_model2, self.elevation, epi_step=epipolar_step, + margin=self.rectification_grid_margin, ) # rearrange output to match the expected structure of CARS @@ -390,7 +396,10 @@ def generate_epipolar_grids( epipolar_size_x = int(np.floor(epipolar_size_x)) epipolar_size_y = int(np.floor(epipolar_size_y)) - origin = [0.0, 0.0] + origin = [ + float(-self.rectification_grid_margin * epipolar_step), + float(-self.rectification_grid_margin * epipolar_step), + ] spacing = [float(epipolar_step), float(epipolar_step)] # alt_to_disp_ratio does not consider image resolution diff --git a/cars/pipelines/parameters/sensor_inputs.py b/cars/pipelines/parameters/sensor_inputs.py index 51826c89..8b694ae2 100644 --- a/cars/pipelines/parameters/sensor_inputs.py +++ b/cars/pipelines/parameters/sensor_inputs.py @@ -246,7 +246,8 @@ def check_geometry_plugin(conf_inputs, conf_advanced, conf_geom_plugin): # Initialize the desired geometry plugin without elevation information geom_plugin_without_dem_and_geoid = ( AbstractGeometry( # pylint: disable=abstract-class-instantiated - conf_geom_plugin, default_alt=sens_cst.CARS_DEFAULT_ALT + conf_geom_plugin, + default_alt=sens_cst.CARS_DEFAULT_ALT, ) ) diff --git a/setup.cfg b/setup.cfg index b32166ed..ce445f96 100644 --- a/setup.cfg +++ b/setup.cfg @@ -82,7 +82,7 @@ install_requires = cars-resample==0.1.* cars-filter==0.1.* vlsift==0.1.* - shareloc==0.2.4 + shareloc==0.2.5 bulldozer-dtm==1.0.* package_dir = diff --git a/tests/core/geometry/test_shareloc_geometry.py b/tests/core/geometry/test_shareloc_geometry.py index fce889c7..a7d4651e 100644 --- a/tests/core/geometry/test_shareloc_geometry.py +++ b/tests/core/geometry/test_shareloc_geometry.py @@ -135,6 +135,29 @@ def test_get_roi(): ] np.testing.assert_allclose(roi, ref_roi) + # Add a 5 pixel margin on rectification grid + geo_plugin_with_margin_on_grid = ( + AbstractGeometry( # pylint: disable=abstract-class-instantiated + "SharelocGeometry", + dem=dem, + geoid=geoid, + rectification_grid_margin=5, + ) + ) + pairs_for_roi = [(sensor1, geomodel1, sensor2, geomodel2)] + roi = geo_plugin_with_margin_on_grid.get_roi( + pairs_for_roi, 4326, margin=0.005 + ) + ref_roi = [ + 44.198651, + 5.185954, + 44.21382, + 5.203201, + ] + # Returned ROI is the footprint of the rectification + # It takes into account the 5 pixels margin + np.testing.assert_allclose(roi, ref_roi) + @pytest.mark.unit_tests def test_sensors_arrangement_left_right(): diff --git a/tests/data/ref_output/classification_end2end_paca_aux_filling.tif b/tests/data/ref_output/classification_end2end_paca_aux_filling.tif index 78966e92..6e2b7ff3 100644 Binary files a/tests/data/ref_output/classification_end2end_paca_aux_filling.tif and b/tests/data/ref_output/classification_end2end_paca_aux_filling.tif differ diff --git a/tests/data/ref_output/classification_end2end_paca_aux_filling_0.tif b/tests/data/ref_output/classification_end2end_paca_aux_filling_0.tif index 590e8159..464b0196 100644 Binary files a/tests/data/ref_output/classification_end2end_paca_aux_filling_0.tif and b/tests/data/ref_output/classification_end2end_paca_aux_filling_0.tif differ diff --git a/tests/data/ref_output/classification_end2end_paca_aux_filling_1.tif b/tests/data/ref_output/classification_end2end_paca_aux_filling_1.tif index 78966e92..fbc6614f 100644 Binary files a/tests/data/ref_output/classification_end2end_paca_aux_filling_1.tif and b/tests/data/ref_output/classification_end2end_paca_aux_filling_1.tif differ diff --git a/tests/data/ref_output/classification_end2end_paca_aux_filling_2.tif b/tests/data/ref_output/classification_end2end_paca_aux_filling_2.tif index 590e8159..464b0196 100644 Binary files a/tests/data/ref_output/classification_end2end_paca_aux_filling_2.tif and b/tests/data/ref_output/classification_end2end_paca_aux_filling_2.tif differ diff --git a/tests/data/ref_output/color_end2end_paca_aux_filling.tif b/tests/data/ref_output/color_end2end_paca_aux_filling.tif index eb7d1303..ccf38a14 100644 Binary files a/tests/data/ref_output/color_end2end_paca_aux_filling.tif and b/tests/data/ref_output/color_end2end_paca_aux_filling.tif differ diff --git a/tests/data/ref_output/color_end2end_paca_aux_filling_0.tif b/tests/data/ref_output/color_end2end_paca_aux_filling_0.tif index 1715cb50..7de50522 100644 Binary files a/tests/data/ref_output/color_end2end_paca_aux_filling_0.tif and b/tests/data/ref_output/color_end2end_paca_aux_filling_0.tif differ diff --git a/tests/data/ref_output/color_end2end_paca_aux_filling_1.tif b/tests/data/ref_output/color_end2end_paca_aux_filling_1.tif index eb7d1303..166d7d05 100644 Binary files a/tests/data/ref_output/color_end2end_paca_aux_filling_1.tif and b/tests/data/ref_output/color_end2end_paca_aux_filling_1.tif differ diff --git a/tests/data/ref_output/color_end2end_paca_aux_filling_2.tif b/tests/data/ref_output/color_end2end_paca_aux_filling_2.tif index 1309610a..e9c40717 100644 Binary files a/tests/data/ref_output/color_end2end_paca_aux_filling_2.tif and b/tests/data/ref_output/color_end2end_paca_aux_filling_2.tif differ diff --git a/tests/data/ref_output/color_end2end_paca_matches_filling.tif b/tests/data/ref_output/color_end2end_paca_matches_filling.tif index 3bb2c4b8..40e2947f 100644 Binary files a/tests/data/ref_output/color_end2end_paca_matches_filling.tif and b/tests/data/ref_output/color_end2end_paca_matches_filling.tif differ diff --git a/tests/data/ref_output/color_end2end_ventoux_with_color.tif b/tests/data/ref_output/color_end2end_ventoux_with_color.tif index 11ec96ff..4169ccf5 100644 Binary files a/tests/data/ref_output/color_end2end_ventoux_with_color.tif and b/tests/data/ref_output/color_end2end_ventoux_with_color.tif differ diff --git a/tests/data/ref_output/dsm_end2end_paca_bulldozer.tif b/tests/data/ref_output/dsm_end2end_paca_bulldozer.tif index 22b326f7..d957c871 100644 Binary files a/tests/data/ref_output/dsm_end2end_paca_bulldozer.tif and b/tests/data/ref_output/dsm_end2end_paca_bulldozer.tif differ diff --git a/tests/data/ref_output/dsm_end2end_paca_matches_filling.tif b/tests/data/ref_output/dsm_end2end_paca_matches_filling.tif index f2e29be9..aa23e990 100644 Binary files a/tests/data/ref_output/dsm_end2end_paca_matches_filling.tif and b/tests/data/ref_output/dsm_end2end_paca_matches_filling.tif differ diff --git a/tests/data/ref_output/dsm_end2end_ventoux_with_color.tif b/tests/data/ref_output/dsm_end2end_ventoux_with_color.tif index 823ba19e..75b7fa66 100644 Binary files a/tests/data/ref_output/dsm_end2end_ventoux_with_color.tif and b/tests/data/ref_output/dsm_end2end_ventoux_with_color.tif differ diff --git a/tests/data/ref_output/mask_end2end_paca_bulldozer.tif b/tests/data/ref_output/mask_end2end_paca_bulldozer.tif index 42ba0b40..ea0eedb5 100644 Binary files a/tests/data/ref_output/mask_end2end_paca_bulldozer.tif and b/tests/data/ref_output/mask_end2end_paca_bulldozer.tif differ diff --git a/tests/data/ref_output/mask_end2end_paca_matches_filling.tif b/tests/data/ref_output/mask_end2end_paca_matches_filling.tif index ae201af7..d17b4f9c 100644 Binary files a/tests/data/ref_output/mask_end2end_paca_matches_filling.tif and b/tests/data/ref_output/mask_end2end_paca_matches_filling.tif differ diff --git a/tests/test_end2end.py b/tests/test_end2end.py index 81479a7d..80be2c3d 100644 --- a/tests/test_end2end.py +++ b/tests/test_end2end.py @@ -3265,6 +3265,15 @@ def test_end2end_ventoux_with_color(): input_config_sparse_res["output"].update(output_config) sparse_res_pipeline = default.DefaultPipeline(input_config_sparse_res) + + # Add a margin on recitification grid + # TODO change this when the new API with + # bicubic interpolator is implemented + geom_plugin_1 = sparse_res_pipeline.geom_plugin_with_dem_and_geoid + geom_plugin_2 = sparse_res_pipeline.geom_plugin_without_dem_and_geoid + geom_plugin_1.rectification_grid_margin = 5 + geom_plugin_2.rectification_grid_margin = 5 + sparse_res_pipeline.run() out_dir = input_config_sparse_res["output"]["directory"] @@ -3338,6 +3347,15 @@ def test_end2end_ventoux_with_color(): input_config_dense_dsm["output"]["product_level"] = ["dsm"] dense_dsm_pipeline = default.DefaultPipeline(input_config_dense_dsm) + + # Add a margin on recitification grid + # TODO change this when the new API with + # bicubic interpolator is implemented + geom_plugin_1 = dense_dsm_pipeline.geom_plugin_with_dem_and_geoid + geom_plugin_2 = dense_dsm_pipeline.geom_plugin_without_dem_and_geoid + geom_plugin_1.rectification_grid_margin = 5 + geom_plugin_2.rectification_grid_margin = 5 + dense_dsm_pipeline.run() out_dir = input_config_dense_dsm["output"]["directory"] @@ -4755,6 +4773,19 @@ def test_end2end_paca_with_mask(): dense_dsm_pipeline_bulldozer = default.DefaultPipeline( input_config_dense_dsm ) + + # Add a margin on recitification grid + # TODO change this when the new API with + # bicubic interpolator is implemented + geom_plugin_1 = ( + dense_dsm_pipeline_bulldozer.geom_plugin_with_dem_and_geoid + ) + geom_plugin_2 = ( + dense_dsm_pipeline_bulldozer.geom_plugin_without_dem_and_geoid + ) + geom_plugin_1.rectification_grid_margin = 5 + geom_plugin_2.rectification_grid_margin = 5 + dense_dsm_pipeline_bulldozer.run() out_dir = input_config_dense_dsm["output"]["directory"] @@ -4851,6 +4882,19 @@ def test_end2end_paca_with_mask(): dense_dsm_pipeline_matches = default.DefaultPipeline( input_config_dense_dsm ) + + # Add a margin on recitification grid + # TODO change this when the new API with + # bicubic interpolator is implemented + geom_plugin_1 = ( + dense_dsm_pipeline_matches.geom_plugin_with_dem_and_geoid + ) + geom_plugin_2 = ( + dense_dsm_pipeline_matches.geom_plugin_without_dem_and_geoid + ) + geom_plugin_1.rectification_grid_margin = 5 + geom_plugin_2.rectification_grid_margin = 5 + dense_dsm_pipeline_matches.run() # copy2(