diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..de02313 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Python # +*.py[cod] +*$py.class + +# Distribution / packaging +.Python build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.whl +*.egg-info/ +.installed.cfg +*.egg +*.manifest +*.spec + diff --git a/docs/cli/hillshade.rst b/docs/cli/hillshade.rst index b1eb4a7..7823539 100644 --- a/docs/cli/hillshade.rst +++ b/docs/cli/hillshade.rst @@ -11,7 +11,7 @@ computes the shadows of the ground surface (buildings, trees, etc.). $ rastertools hillshade --help usage: rastertools hillshade [-h] --elevation ELEVATION --azimuth AZIMUTH - [--radius RADIUS] --resolution RESOLUTION + [--radius RADIUS] --resolution RESOLUTION [-o OUTPUT] [-ws WINDOW_SIZE] [-p {none,edge,maximum,mean,median,minimum,reflect,symmetric,wrap}] inputs [inputs ...] diff --git a/src/eolab/rastertools/cli/__init__.py b/src/eolab/rastertools/cli/__init__.py index 38c658f..50cf82d 100644 --- a/src/eolab/rastertools/cli/__init__.py +++ b/src/eolab/rastertools/cli/__init__.py @@ -69,4 +69,4 @@ def with_bands_arguments(parser): '--all', dest="all_bands", action="store_true", - help="Compute all bands") + help="Compute all bands") \ No newline at end of file diff --git a/src/eolab/rastertools/hillshade.py b/src/eolab/rastertools/hillshade.py index 6eaadb4..900816d 100644 --- a/src/eolab/rastertools/hillshade.py +++ b/src/eolab/rastertools/hillshade.py @@ -105,27 +105,31 @@ def process_file(self, inputfile: str) -> List[str]: outdir = Path(self.outputdir) output_image = outdir.joinpath(f"{utils.get_basename(inputfile)}-hillshade.tif") - if self.radius is None: - # compute the radius from data range - # radius represents the max distance of buildings that can create a hillshade - # considering the sun elevation. - wmax = None - wmin = None - with rasterio.open(inputfile) as src: - if src.count != 1: - raise ValueError("Invalid input file, it must contain a single band.") - for ji, window in src.block_windows(1): - data = src.read(1, masked=True, window=window) - wmax = max(wmax, float(data.max())) if wmax is not None else float(data.max()) - wmin = min(wmin, float(data.min())) if wmin is not None else float(data.min()) - - delta = int((wmax - wmin) / self.resolution) - radius = int(delta / np.tan(np.radians(self.elevation))) + # compute the radius from data range + # radius represents the max distance of buildings that can create a hillshade + # considering the sun elevation. + wmax = None + wmin = None + with rasterio.open(inputfile) as src: + if src.count != 1: + raise ValueError("Invalid input file, it must contain a single band.") + for ji, window in src.block_windows(1): + data = src.read(1, masked=True, window=window) + wmax = max(wmax, float(data.max())) if wmax is not None else float(data.max()) + wmin = min(wmin, float(data.min())) if wmin is not None else float(data.min()) + + delta = int((wmax - wmin) / self.resolution) + optimal_radius = int(delta / np.tan(np.radians(self.elevation))) + + if self.radius is None or optimal_radius <= self.radius: + self.radius = optimal_radius else: - radius = self.radius + _logger.warning(f"The optimal radius value is {optimal_radius} exceeding {self.radius} threshold. " + f"Oversized radius affects computation time and so radius is set to {self.radius}. " + "Result may miss some shadow pixels.") - if radius >= min(self.window_size) / 2: - raise ValueError(f"The radius (option --radius, value={radius}) must be strictly " + if self.radius >= min(self.window_size) / 2: + raise ValueError(f"The radius (option --radius, value={self.radius}) must be strictly " "less than half the size of the window (option --window_size, " f"value={min(self.window_size)})") @@ -143,7 +147,7 @@ def process_file(self, inputfile: str) -> List[str]: "elevation": self.elevation, "azimuth": self.azimuth, "resolution": self.resolution, - "radius": radius + "radius": self.radius } hillshade.configure(hillshade_conf) @@ -151,7 +155,7 @@ def process_file(self, inputfile: str) -> List[str]: compute_sliding( inputfile, output_image, hillshade, window_size=self.window_size, - window_overlap=radius, + window_overlap=self.radius, pad_mode=self.pad_mode) return [output_image.as_posix()]