Extract nodata values from metadata when possible

This commit is contained in:
Tim Schaub
2021-08-19 10:40:59 -06:00
parent 8954f001fa
commit 42970915ea
6 changed files with 59 additions and 12 deletions

View File

@@ -59,7 +59,7 @@ const map = new Map({
],
view: new View({
center: [1900000, 6100000],
zoom: 15,
zoom: 13,
minZoom: 10,
}),
});

View File

@@ -80,13 +80,11 @@ const map = new Map({
{
// visible red, band 1 in the style expression above
url: 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/2020/S2A_36QWD_20200701_0_L2A/B04.tif',
nodata: 0,
max: 10000,
},
{
// near infrared, band 2 in the style expression above
url: 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/2020/S2A_36QWD_20200701_0_L2A/B08.tif',
nodata: 0,
max: 10000,
},
],

View File

@@ -4,8 +4,7 @@ title: Cloud Optimized GeoTIFF (COG)
shortdesc: Rendering a COG as a tiled layer.
docs: >
Tiled data from a Cloud Optimized GeoTIFF (COG) can be rendered as a layer. In this
example, a single 3-band GeoTIFF is used to render RGB data. The `nodata` property is
used to avoid rendering pixels where all three bands are 0.
example, a single 3-band GeoTIFF is used to render RGB data.
tags: "cog"
---
<div id="map" class="map"></div>

View File

@@ -26,7 +26,6 @@ const map = new Map({
sources: [
{
url: 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/2020/S2A_36QWD_20200701_0_L2A/TCI.tif',
nodata: 0,
},
],
}),

View File

@@ -191,6 +191,12 @@ class GeoTIFFSource extends DataTile {
*/
this.samplesPerPixel_;
/**
* @type {Array<Array<number>>}
* @private
*/
this.nodataValues_;
/**
* @type {boolean}
* @private
@@ -249,6 +255,7 @@ class GeoTIFFSource extends DataTile {
let tileSizes;
let resolutions;
const samplesPerPixel = new Array(sources.length);
const nodataValues = new Array(sources.length);
let minZoom = 0;
const sourceCount = sources.length;
@@ -261,8 +268,14 @@ class GeoTIFFSource extends DataTile {
const sourceTileSizes = new Array(imageCount);
const sourceResolutions = new Array(imageCount);
nodataValues[sourceIndex] = new Array(imageCount);
for (let imageIndex = 0; imageIndex < imageCount; ++imageIndex) {
const image = images[imageIndex];
const nodataValue = image.getGDALNoData();
nodataValues[sourceIndex][imageIndex] =
nodataValue === null ? NaN : nodataValue;
const wantedSamples = this.sourceInfo_[sourceIndex].bands;
samplesPerPixel[sourceIndex] = wantedSamples
? wantedSamples.length
@@ -351,13 +364,39 @@ class GeoTIFFSource extends DataTile {
}
this.samplesPerPixel_ = samplesPerPixel;
const sourceInfo = this.sourceInfo_;
for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
if (sourceInfo[sourceIndex].nodata !== undefined) {
this.nodataValues_ = nodataValues;
// decide if we need to add an alpha band to handle nodata
outer: for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
// option 1: source is configured with a nodata value
if (this.sourceInfo_[sourceIndex].nodata !== undefined) {
this.addAlpha_ = true;
break;
}
const values = nodataValues[sourceIndex];
// option 2: check image metadata for limited bands
const bands = this.sourceInfo_[sourceIndex].bands;
if (bands) {
for (let i = 0; i < bands.length; ++i) {
if (!isNaN(values[bands[i]])) {
this.addAlpha_ = true;
break outer;
}
}
continue;
}
// option 3: check image metadata for all bands
for (let imageIndex = 0; imageIndex < values.length; ++imageIndex) {
if (!isNaN(values[imageIndex])) {
this.addAlpha_ = true;
break outer;
}
}
}
const additionalBands = this.addAlpha_ ? 1 : 0;
this.bandCount =
samplesPerPixel.reduce((accumulator, value) => {
@@ -410,6 +449,7 @@ class GeoTIFFSource extends DataTile {
const pixelCount = size[0] * size[1];
const dataLength = pixelCount * bandCount;
const nodataValues = this.nodataValues_;
return Promise.all(requests).then(function (sourceSamples) {
const data = new Uint8ClampedArray(dataLength);
@@ -430,8 +470,6 @@ class GeoTIFFSource extends DataTile {
const gain = 255 / (max - min);
const bias = -min * gain;
const nodata = source.nodata;
for (
let sampleIndex = 0;
sampleIndex < samplesPerPixel[sourceIndex];
@@ -444,6 +482,17 @@ class GeoTIFFSource extends DataTile {
if (!addAlpha) {
data[dataIndex] = value;
} else {
let nodata = source.nodata;
if (nodata === undefined) {
let bandIndex;
if (source.bands) {
bandIndex = source.bands[sampleIndex];
} else {
bandIndex = sampleIndex;
}
nodata = nodataValues[sourceIndex][bandIndex];
}
if (sourceValue !== nodata) {
transparent = false;
data[dataIndex] = value;

View File

@@ -25,7 +25,9 @@ describe('ol.source.GeoTIFF', function () {
it('configures itself from source metadata', function (done) {
source.on('change', () => {
expect(source.bandCount).to.be(3);
expect(source.addAlpha_).to.be(true);
expect(source.bandCount).to.be(4);
expect(source.nodataValues_).to.eql([[0]]);
expect(source.getTileGrid().getResolutions().length).to.be(1);
expect(source.projection.getCode()).to.be('EPSG:4326');
done();