Source code for geefcc.sum_raster_bands
"""Summing raster bands.
See: https://github.com/mstrimas/gdal-summarize/blob/master/gdal-summarize.py
"""
from pathlib import Path
import numpy as np
from osgeo import gdal
from .misc import progress_bar, makeblock
[docs]
def sum_raster_bands(input_file, output_file="sum.tif",
blk_rows=128, verbose=True):
"""Sum the raster bands of a multi-band input file into a single
output band.
Reads the input raster file band by band in configurable block sizes to
manage memory usage, computes the pixel-wise sum across all bands, and
writes the result to a single-band GeoTIFF output file.
Parameters
----------
input_file : str or Path
Path to the input raster file containing several bands to be summed.
output_file : str or Path, optional
Path to the output GeoTIFF file with one band corresponding to the
sum of the input bands. Defaults to ``"sum.tif"``.
blk_rows : int, optional
Number of rows per processing block. Used to break large raster files
into several blocks of data that can be held in memory at one time.
Defaults to ``128``.
verbose : bool, optional
Whether to print progress messages during processing. Defaults to
``True``.
Returns
-------
None
The function writes results directly to ``output_file`` and does not
return a value.
Raises
------
RuntimeError
If ``input_file`` cannot be opened by GDAL or if the output raster
cannot be created.
Notes
-----
- The output raster is created with ``gdal.GDT_Byte`` data type, DEFLATE
compression, and BIGTIFF support enabled.
- A NoData value of ``255`` is assigned to the output band.
- If ``output_file`` already exists, it will be removed before the new
file is created.
- Band statistics are computed and flushed to disk after all blocks have
been processed.
Examples
--------
>>> sum_raster_bands(
... input_file="input_multiband.tif",
... output_file="sum.tif",
... blk_rows=256,
... verbose=True,
... )
"""
input_file = Path(input_file)
output_file = Path(output_file)
# Load input raster info
ds = gdal.Open(str(input_file)) # GDAL requires str
gt = ds.GetGeoTransform()
proj = ds.GetProjection()
ncol = ds.RasterXSize
nrow = ds.RasterYSize
nband = ds.RasterCount
# Create output raster file
driver = gdal.GetDriverByName("GTiff")
if output_file.is_file():
output_file.unlink()
ds_out = driver.Create(
str(output_file), # GDAL requires str
ncol, nrow, 1,
gdal.GDT_Byte,
["COMPRESS=DEFLATE", "BIGTIFF=YES"],
)
ds_out.SetGeoTransform(gt)
ds_out.SetProjection(proj)
band_out = ds_out.GetRasterBand(1)
band_out.SetNoDataValue(255)
band_out.SetDescription("fcc") # band name
# Make blocks
blockinfo = makeblock(input_file, blk_rows=blk_rows)
nblock = blockinfo[0]
nblock_x = blockinfo[1]
x = blockinfo[3]
y = blockinfo[4]
nx = blockinfo[5]
ny = blockinfo[6]
# Loop on blocks of data
for b in range(nblock):
# Progress bar
if verbose:
progress_bar(nblock, b + 1)
# Position in 1D-arrays
px = b % nblock_x
py = b // nblock_x
# Make stack to store data
stack = np.empty(shape=(nband, ny[py], nx[px]), dtype="b")
# Data for one block
for i in range(nband):
stack[i] = (ds.GetRasterBand(i + 1)
.ReadAsArray(x[px], y[py], nx[px], ny[py]))
# Compute sum
result = np.sum(stack, axis=0)
# Write data
band_out.WriteArray(result, x[px], y[py])
print("Compute statistics")
band_out.FlushCache() # Write cache data to disk
band_out.ComputeStatistics(False)
# Dereference driver
band_out = None
del ds_out
# End