LETG / madDog

Configuration Mviewer pour suivi littoral
2 stars 3 forks source link

[compare MNT] légende du résultat #121

Open mrouan opened 7 months ago

mrouan commented 7 months ago

Description

La légende du résultat de comparaison devrait être calculée de la manière suivante de -0,02m à 0,02m : blanc ou transparent du min à -0,02 : gamme de couleur allant du bleu foncé au vert clair par pas de 0,25 de 0,02 à max : gamme de couleur allant du jaune clair au rouge foncé par pas de 0,25

min et max étant les valeurs minimum et maximum du MNT issu du résultat de la comparaison

Gaetanbrl commented 7 months ago

Informations générales

Le type de données OpenLayers concerné est le WebGL (GeoTiff) : https://openlayers.org/en/latest/apidoc/module-ol_layer_WebGLTile-WebGLTileLayer.html

Il permet d'utiliser une source de couche OpenLayers GeoTIFF via la librairie GeoTiff.js : https://geotiffjs.github.io/

En prérequis, un workshop permet de cerner la création / affichage / rendu de ce type de couche () :

https://openlayers.org/workshop/en/cog/colormap.html

La réalisation d'un style semble donc utiliser les "expressionValue" Openlayers qui est une syntaxe spécifique à OpenLayers. Cette syntaxe permet de réaliser un style via un ensemble d'expression logique.

On peut notamment faire une classification selon une liste de valeur, des croisements (opérations) entre plusieurs bands d'un raster, etc. (voir les URLs pour plus d'informations).

Comment représenter une couche ?

Si le flux est un WMS, il est possible d'utiliser un SLD avec GeoServer. Dans notre cas, c'est le WPS qui retourne un TIFF directement.

La documentation OpenLayers pour le type WebGL ne semble pas permettre l'utilisation d'un SLD.

Nous avons donc testés de reprendre la liste des valeurs du SLD, et de l'appliquer dans une expressionValue OpenLayers afin de représenter le TIFF.

Voici un exemple pour réaliser une classification à partir de valeurs d'une bande d'un TIFF :

const bandValue = ['band', 1];
const layer = new ol.layer.WebGLTile({
    source: src,
    style: {
        color: [
            'case',
            // couleur si la valeur de band est == à -0
            ['==', bandValue, -0],
            ['color', 0, 0, 0, 0],
            // couleur si la valeur de band est <= à -4
            ['<=', bandValue, -4],
            ['color', 62,55,144, 1],
            ['<=', bandValue, -3.75],
            ['color', 164, 252, 60, 1],
            // valeurs par défaut
            ['color', 0, 0, 0, 1]
        ]
    }
})

Le résultat n'étant pas satisfaisant pour LETG, cette issue à été créée.

Il est donc demander de créer un code complexe qui nécessite de :

En l'état, rien n'est prévu dans OpenLayers pour cette réalisation déjà annoncée comme complexe. Il semble qu'il serait toutefois possible d'avoir ce type de rendu avec une opération d'interpolation disponible dans les expressionValue OpenLayers. Mais ce code nécessite l'ajout d'une librairie externe type colormap.js inspirée de la librairie maplotLibre.

Des essais ont au préalable était réalisés en dehors du mviewer et avec un TIFF issue de la comparaison de 2 MNT avec SAGA :

https://codesandbox.io/p/sandbox/cog-no-data-interpolate-forked-j2n8qz?file=%2Fmain.js

image

    new TileLayer({
      source: source,
      style: {
        color: [
          "interpolate",
          ["linear"],
          layer,
          // le nombre 40 correspond au nombre de couleurs différentes à obtenir par valeur
          // c'est le nombre de valeurs qui existent entre -4 et +6 à des pas de 0,25:
          // 10 / 0,25 = ~40
          ...getColorStops("jet", -4, 6, 40, false),
        ],
      },
    }),

La valeur "jet" correspond à la palette suivante dans colormap: image

Ce code peut sembler intéressant, et nécessite un test dans mviewer.

Réalisation dans mviewer

Pour être utilisable dans mviewer, il faut créer une extension colormap qui n'est pas disponible directement en tant que librairie buildée (type CDN). Il faut donc utiliser une extension type "module" et recopier la librairie (ce qui n'est pas très long).

Ensuite, un test peut être réalisé dans un customLayer avec un TIFF issue d'une comparaison de 2 MNT SAGA.

Analyse des premiers résultats :

Gaetanbrl commented 7 months ago

Je viens de tester avec un POC accessible ici :

https://codesandbox.io/p/devbox/range-colormap-tiff-openlayers-dyp4y3?file=%2Fmain.js%3A108%2C1

Pour voir en plein écran : image

Il permet de voir les valeurs obtenues sur le pixel et la palette associée sur la gauche pour vérification :

image

Gaetanbrl commented 7 months ago

En complément, le test précédent utilise des valeurs min et max (série de -4 à +6) pour définir le nombre de couleur.

J'ai regardé pour calculer de manière automatique les limites de ces valeurs (-4 et +6) à partir du raster. OpenLayers semble permettre de lire les METADATA d'un raster TIFF via la librairie GeoTIFF.js:

import {fromUrl as tiffFromUrl} from 'geotiff';

let g = await tiffFromUrl(url);
let img = await g.getImage();
let metadata = [];
for(let i = 0; i < img.getSamplesPerPixel(); i++) {
    metadata.push(img.getGDALMetadata(i));
}

Mais dans notre cas, aucune METADATA n'a été rajouté.

3 options s'offrent à nous :

@mrouan redis moi si ce n'est pas clair et ce qui te semble le plus intéressant. J'aime assez la 3è options. La seconde est la + rapide à mettre en oeuvre. La première comprend le plus d'incertitude sur le résultat final.

Dans tous les cas, je vais commencer à tester dans le mviewer pour voir le rendu avec l'exemple (POC) précédent afin d'avoir une idée du rendu / temps de réponse.

Gaetanbrl commented 7 months ago

Complément sur les résultats, les couleurs ne correspondent pas exactement au besoin suivant :

du min à -0,02 : gamme de couleur allant du bleu foncé au vert clair par pas de 0,25 de 0,02 à max : gamme de couleur allant du jaune clair au rouge foncé par pas de 0,25

Après réflexion, il ne faudrait pas utiliser qu'une palette de couleurs mais une concaténation de plusieurs palettes si c'est possible.

Pour rappel, les palettes de la librairies colormap sont disponibles ici et on a utilisé "jet" dans l'exemple précédent :

https://github.com/bpostlethwaite/colormap

Il faudrait alors faire correspondre ces cas :

Gaetanbrl commented 7 months ago

Je viens de mettre en place un test qui prend compte de mon dernier commentaire (en utilisant 2 palettes donc) : https://codesandbox.io/p/devbox/range-colormap-tiff-openlayers-dyp4y3?file=%2Fmain.js%3A135%2C4

Pour jongler entre cette version et la précédent, il est possible d'inverser le commentaire entre la ligne 113 et 114 :

      //...colorsBySteps("jet", valueMin, valueMax, steps, isTransparent, false),
      ...colorsFromManyRange(),

Les valeurs d'entrées peuvent être modifiées facilement en haut du fichier si besoin (et si le fichier est éditable par tous).

Quentin-RUAUD commented 1 week ago

lié à https://github.com/LETG/madDog/issues/97