in common/src/main/java/org/apache/sedona/common/raster/RasterEditors.java [452:541]
public static GridCoverage2D normalizeAll(
GridCoverage2D rasterGeom,
double minLim,
double maxLim,
boolean normalizeAcrossBands,
Double noDataValue,
Double minValue,
Double maxValue) {
if (minLim > maxLim) {
throw new IllegalArgumentException("minLim cannot be greater than maxLim");
}
int numBands = rasterGeom.getNumSampleDimensions();
RenderedImage renderedImage = rasterGeom.getRenderedImage();
int rasterDataType = renderedImage.getSampleModel().getDataType();
double globalMin = minValue != null ? minValue : Double.MAX_VALUE;
double globalMax = maxValue != null ? maxValue : -Double.MAX_VALUE;
// Initialize arrays to store band-wise min and max values
double[] minValues = new double[numBands];
double[] maxValues = new double[numBands];
Arrays.fill(minValues, Double.MAX_VALUE);
Arrays.fill(maxValues, -Double.MAX_VALUE);
// Trigger safe mode if noDataValue is null - noDataValue is set to maxLim and data values are
// normalized to range [minLim, maxLim-1].
// This is done to prevent setting valid data as noDataValue.
double safetyTrigger = (noDataValue == null) ? 1 : 0;
// Compute global min and max values across all bands if necessary and not provided
if (minValue == null || maxValue == null) {
for (int bandIndex = 0; bandIndex < numBands; bandIndex++) {
double[] bandValues = bandAsArray(rasterGeom, bandIndex + 1);
double bandNoDataValue =
RasterUtils.getNoDataValue(rasterGeom.getSampleDimension(bandIndex));
if (noDataValue == null) {
noDataValue = maxLim;
}
for (double val : bandValues) {
if (val != bandNoDataValue) {
if (normalizeAcrossBands) {
globalMin = Math.min(globalMin, val);
globalMax = Math.max(globalMax, val);
} else {
minValues[bandIndex] = Math.min(minValues[bandIndex], val);
maxValues[bandIndex] = Math.max(maxValues[bandIndex], val);
}
}
}
}
} else {
globalMin = minValue;
globalMax = maxValue;
}
// Normalize each band
for (int bandIndex = 0; bandIndex < numBands; bandIndex++) {
double[] bandValues = bandAsArray(rasterGeom, bandIndex + 1);
double bandNoDataValue = RasterUtils.getNoDataValue(rasterGeom.getSampleDimension(bandIndex));
double currentMin =
normalizeAcrossBands ? globalMin : (minValue != null ? minValue : minValues[bandIndex]);
double currentMax =
normalizeAcrossBands ? globalMax : (maxValue != null ? maxValue : maxValues[bandIndex]);
if (Double.compare(currentMax, currentMin) == 0) {
Arrays.fill(bandValues, minLim);
} else {
for (int i = 0; i < bandValues.length; i++) {
if (bandValues[i] != bandNoDataValue) {
double normalizedValue =
minLim
+ ((bandValues[i] - currentMin) * (maxLim - safetyTrigger - minLim))
/ (currentMax - currentMin);
bandValues[i] = castRasterDataType(normalizedValue, rasterDataType);
} else {
bandValues[i] = noDataValue;
}
}
}
// Update the raster with the normalized band and noDataValue
rasterGeom = addBandFromArray(rasterGeom, bandValues, bandIndex + 1);
rasterGeom = RasterBandEditors.setBandNoDataValue(rasterGeom, bandIndex + 1, noDataValue);
}
return rasterGeom;
}