Source code for cars.applications.dem_generation.dem_generation_tools

#!/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.
#
"""
this module contains tools for the dem generation
"""

import contextlib
import logging
import os

# Third party imports
import xdem
from rasterio.coords import BoundingBox


[docs]def fit_initial_elevation_on_dem_median( dem_to_fit_path: str, dem_ref_path: str, dem_out_path: str ): """ Coregistrates the two DEMs given then saves the result. The initial elevation will be cropped to reduce computation costs. Returns the transformation applied. :param dem_to_fit_path: Path to the dem to be fitted :type dem_to_fit_path: str :param dem_ref_path: Path to the dem to fit onto :type dem_ref_path: str :param dem_out_path: Path to save the resulting dem into :type dem_out_path: str :return: coregistration transformation applied :rtype: dict """ # suppress all outputs of xdem with open(os.devnull, "w", encoding="utf8") as devnull: with ( contextlib.redirect_stdout(devnull), contextlib.redirect_stderr(devnull), ): # load DEMs dem_to_fit = xdem.DEM(dem_to_fit_path) dem_ref = xdem.DEM(dem_ref_path) # get the crs needed to reproject the data crs_out = dem_ref.crs crs_metric = dem_ref.get_metric_crs() # Crop dem_to_fit with dem_ref to reduce # computation costs. bbox = dem_ref.bounds bbox = add_margin(bbox) dem_to_fit = dem_to_fit.crop(bbox).reproject(crs=crs_metric) # Reproject dem_ref to dem_to_fit resolution to reduce # computation costs dem_ref = dem_ref.reproject(dem_to_fit) bbox = dem_ref.bounds bbox = add_margin(bbox) coreg_pipeline = xdem.coreg.NuthKaab() try: # fit dem_to_fit onto dem_ref, crop it, then reproject it # set a random state to always get the same results fit_dem = ( coreg_pipeline.fit_and_apply( dem_ref, dem_to_fit, random_state=0 ) .crop(bbox) .reproject(crs=crs_out) ) # save the results fit_dem.save(dem_out_path) coreg_offsets = coreg_pipeline.meta["outputs"]["affine"] except (ValueError, AssertionError, TypeError): logging.warning( "xDEM coregistration failed. This can happen when sensor " "images are too small. No shift will be applied on DEM" ) coreg_offsets = None return coreg_offsets
[docs]def add_margin(bbox, ratio=1): """ Add margin to a bounding box :param bbox: input bounding box :type bbox: rasterio.coords.BoundingBox :param ratio: factor of bbox size to add to each side of bbox :type ratio: float :return: bounding box with margins :rtype: rasterio.coords.BoundingBox """ try: assert bbox.left < bbox.right assert bbox.bottom < bbox.top width = bbox.right - bbox.left height = bbox.top - bbox.bottom new_left = bbox.left - ratio * width new_right = bbox.right + ratio * width new_bottom = bbox.bottom - ratio * height new_top = bbox.top + ratio * height new_bbox = BoundingBox(new_left, new_bottom, new_right, new_top) except AssertionError: logging.warning("Bounding box {} cannot be read".format(bbox)) new_bbox = bbox return new_bbox