Source code for cars.applications.resampling.resampling_wrappers

#!/usr/bin/env python
# coding: utf8
#
# Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
#
# This file is part of CARS
# (see https://github.com/CNES/cars).
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""
Resampling module:
contains functions used for epipolar resampling
"""

import copy

# Standard imports
import logging

# Third party imports
import numpy as np

# CARS imports
from cars.core import constants as cst
from cars.core import inputs
from cars.orchestrator.cluster.log_wrapper import cars_profile
from cars.pipelines.parameters import sensor_inputs_constants as sens_cst


@cars_profile(name="Get paths and bands", interval=0.5)
def get_paths_and_bands_from_image(sensor_image, required_bands=None):
    """
    Reformat file paths and bands required from each file to ease reading

    :param sensor_image: input configuration of an image
    :type sensor_image: dict
    :param required_bands: required bands for resampling
    :type required_bands: list
    """
    paths = {}
    if required_bands is None:
        # All bands are required bands
        required_bands = list(sensor_image["bands"].keys())
    for band in required_bands:
        file_path = sensor_image["bands"][band]["path"]
        band_id = sensor_image["bands"][band]["band"] + 1
        if file_path in paths:
            paths[file_path]["band_id"].append(band_id)
            paths[file_path]["band_name"].append(band)
        else:
            paths[file_path] = {"band_id": [band_id], "band_name": [band]}
    return paths


[docs] def get_path_and_values_from_classif(sensor_classif): """ Reformat file paths and bands required from each file to ease reading :param sensor_classif: input configuration of a classif :type sensor_image: dict """ paths = {sensor_classif["path"]: {"values": sensor_classif["values"]}} return paths
[docs] def get_sensors_bounds(sensor_image_left, sensor_image_right): """ Get bounds of sensor images Bounds: BoundingBox(left, bottom, right, top) :param sensor_image_left: left sensor :type sensor_image_left: dict :param sensor_image_right: right sensor :type sensor_image_right: dict :return: left image bounds, right image bounds :rtype: tuple(list, list) """ left_sensor_bounds = list( inputs.rasterio_get_bounds( sensor_image_left[sens_cst.INPUT_IMG]["bands"]["b0"]["path"], apply_resolution_sign=True, ) ) right_sensor_bounds = list( inputs.rasterio_get_bounds( sensor_image_right[sens_cst.INPUT_IMG]["bands"]["b0"]["path"], apply_resolution_sign=True, ) ) return left_sensor_bounds, right_sensor_bounds
[docs] def check_tiles_in_sensor( # pylint: disable=too-many-positional-arguments sensor_image_left, sensor_image_right, image_tiling, grid_left, grid_right, geom_plugin, ): """ Check if epipolar tiles will be used. A tile is not used if is outside sensor bounds :param sensor_image_left: left sensor :type sensor_image_left: dict :param sensor_image_right: right sensor :type sensor_image_right: dict :param image_tiling: epipolar tiling grid :type image_tiling: np.array :param grid_left: left epipolar grid :type grid_left: CarsDataset :param grid_right: right epipolar grid :type grid_right: CarsDataset :return: left in sensor, right in sensor :rtype: np.array(bool), np.array(bool) """ # Get sensor image bounds # BoundingBox: left, bottom, right, top: left_sensor_bounds, right_sensor_bounds = get_sensors_bounds( sensor_image_left, sensor_image_right ) # Get tile epipolar corners interpolation_margin = 20 # arbitrary # add margin tiling_grid = copy.copy(image_tiling) tiling_grid[:, :, 0] -= interpolation_margin tiling_grid[:, :, 1] += interpolation_margin tiling_grid[:, :, 2] -= interpolation_margin tiling_grid[:, :, 3] += interpolation_margin # Generate matches matches = np.empty((4 * tiling_grid.shape[0] * tiling_grid.shape[1], 2)) nb_row = tiling_grid.shape[0] for row in range(tiling_grid.shape[0]): for col in range(tiling_grid.shape[1]): y_min, y_max, x_min, x_max = tiling_grid[row, col] matches[ 4 * nb_row * col + 4 * row : 4 * nb_row * col + 4 * row + 4, : ] = np.array( [ [x_min, y_min], [x_min, y_max], [x_max, y_max], [x_max, y_min], ] ) # create artificial matches tiles_coords_as_matches = np.concatenate([matches, matches], axis=1) # Compute sensors positions # Transform to sensor coordinates ( sensor_pos_left, sensor_pos_right, ) = geom_plugin.matches_to_sensor_coords( grid_left, grid_right, tiles_coords_as_matches, cst.MATCHES_MODE, ) in_sensor_left_array = np.ones( (image_tiling.shape[0], image_tiling.shape[1]), dtype=bool ) in_sensor_right_array = np.ones( (image_tiling.shape[0], image_tiling.shape[1]), dtype=bool ) for row in range(tiling_grid.shape[0]): for col in range(tiling_grid.shape[1]): # Get sensors position for tile left_sensor_tile = sensor_pos_left[ 4 * nb_row * col + 4 * row : 4 * nb_row * col + 4 * row + 4, : ] right_sensor_tile = sensor_pos_right[ 4 * nb_row * col + 4 * row : 4 * nb_row * col + 4 * row + 4, : ] in_sensor_left, in_sensor_right = check_tile_inclusion( left_sensor_bounds, right_sensor_bounds, left_sensor_tile, right_sensor_tile, ) in_sensor_left_array[row, col] = in_sensor_left in_sensor_right_array[row, col] = in_sensor_right nb_tiles = tiling_grid.shape[0] * tiling_grid.shape[1] tiles_dumped_left = nb_tiles - np.sum(in_sensor_left_array) tiles_dumped_right = nb_tiles - np.sum(in_sensor_right_array) logging.info( "Number of left epipolar image tiles outside left sensor " "image and removed: {}".format(tiles_dumped_left) ) logging.info( "Number of right epipolar image tiles outside right sensor " "image and removed: {}".format(tiles_dumped_right) ) return in_sensor_left_array, in_sensor_right_array
[docs] def check_tile_inclusion( left_sensor_bounds, right_sensor_bounds, sensor_pos_left, sensor_pos_right, ): """ Check if tile is in sensor image :param left_sensor_bounds: bounds of left sensor :type left_sensor_bounds: list :param right_sensor_bounds: bounds of right sensor :type right_sensor_bounds: list :param sensor_pos_left: left sensor position :type sensor_pos_left: np.array :param sensor_pos_right: right sensor position :type sensor_pos_right: np.array :return: left tile in sensor image left, right tile in sensor image right :rtype: tuple(bool, bool) """ # check if outside of image # Do not use tile if the whole tile is outside sensor in_sensor_left = True if ( ( np.all( sensor_pos_left[:, 0] < min(left_sensor_bounds[0], left_sensor_bounds[2]) ) ) or ( np.all( sensor_pos_left[:, 0] > max(left_sensor_bounds[0], left_sensor_bounds[2]) ) ) or ( np.all( sensor_pos_left[:, 1] > max(left_sensor_bounds[1], left_sensor_bounds[3]) ) ) or ( np.all( sensor_pos_left[:, 1] < min(left_sensor_bounds[1], left_sensor_bounds[3]) ) ) ): in_sensor_left = False in_sensor_right = True if ( ( np.all( sensor_pos_right[:, 0] < min(right_sensor_bounds[0], right_sensor_bounds[2]) ) ) or ( np.all( sensor_pos_right[:, 0] > max(right_sensor_bounds[0], right_sensor_bounds[2]) ) ) or ( np.all( sensor_pos_right[:, 1] > max(right_sensor_bounds[1], right_sensor_bounds[3]) ) ) or ( np.all( sensor_pos_right[:, 1] < min(right_sensor_bounds[1], right_sensor_bounds[3]) ) ) ): in_sensor_right = False return in_sensor_left, in_sensor_right