Performances dans le calcul des statistiques raster dans PostGIS


9

J'essaie de calculer des statistiques raster (min, max, moyenne) pour chaque polygone dans une couche vectorielle en utilisant PostgreSQL / PostGIS.

Cette réponse GIS.SE décrit comment procéder, en calculant l'intersection entre le polygone et le raster, puis en calculant une moyenne pondérée: https://gis.stackexchange.com/a/19858/12420

J'utilise la requête suivante (où demest mon raster, topo_area_su_regionmon vecteur et toidun ID unique:

SELECT toid, Min((gv).val) As MinElevation, Max((gv).val) As MaxElevation, Sum(ST_Area((gv).geom) * (gv).val) / Sum(ST_Area((gv).geom)) as MeanElevation FROM (SELECT toid, ST_Intersection(rast, geom) AS gv FROM topo_area_su_region,dem WHERE ST_Intersects(rast, geom)) foo GROUP BY toid ORDER BY toid;

Cela fonctionne, mais c'est trop lent. Ma couche vectorielle a 2489k fonctionnalités, chacune prenant environ 90 ms à traiter - il faudrait des jours pour traiter la couche entière. La vitesse de calcul ne semble pas être significativement améliorée si je ne calcule que les min et max (ce qui évite les appels à ST_Area).

Si je fais un calcul similaire en utilisant Python (GDAL, NumPy et PIL), je peux réduire considérablement le temps qu'il faut pour traiter les données, si au lieu de vectoriser le raster (à l'aide de ST_Intersection), je pixellise le vecteur. Voir le code ici: https://gist.github.com/snorfalorpagus/7320167

Je n'ai pas vraiment besoin d'une moyenne pondérée - une approche "si ça touche, c'est dedans" est assez bonne - et je suis raisonnablement sûr que c'est ce qui ralentit les choses.

Question : Existe-t-il un moyen pour que PostGIS se comporte comme ça? c'est-à-dire pour renvoyer les valeurs de toutes les cellules du raster qu'un polygone touche, plutôt que l'intersection exacte.

Je suis très nouveau sur PostgreSQL / PostGIS, alors peut-être qu'il y a autre chose que je ne fais pas bien. J'utilise PostgreSQL 9.3.1 et PostGIS 2.1 sur Windows 7 (2,9 GHz i7, 8 Go de RAM) et j'ai peaufiné la configuration de la base de données comme suggéré ici: http://postgis.net/workshops/postgis-intro/tuning.html

entrez la description de l'image ici


1
J'ai édité ma réponse. J'ai oublié de dire que l'intersection dans ma réponse est moins précise.
Stefan

Réponses:


11

Vous avez raison, l'utilisation ST_Intersectionralentit sensiblement votre requête.

Au lieu de l'utiliser, ST_Intersectionil est préférable de découper ( ST_Clip) votre raster avec les polygones (vos champs) et de vider le résultat sous forme de polygones ( ST_DumpAsPolygons). Ainsi, chaque cellule raster sera convertie en un petit rectangle de polygone avec des valeurs distinctes.

Pour recevoir min, max ou moyenne des vidages, vous pouvez utiliser les mêmes instructions.

Cette requête devrait faire l'affaire:

SELECT 
    toid,
    Min((gv).val) As MinElevation,
    Max((gv).val) As MaxElevation,
    Sum(ST_Area((gv).geom) * (gv).val) / Sum(ST_Area((gv).geom)) as MeanElevation
FROM (
    SELECT 
        toid,
        ST_DumpAsPolygons(ST_Clip(rast, 1, geom, true)) AS gv
    FROM topo_area_su_region,dem 
        WHERE ST_Intersects(rast, geom)) AS foo 
            GROUP BY toid 
            ORDER BY toid;

Dans l'instruction, ST_Clipvous définissez le raster, la bande raster (= 1), le polygone et si le recadrage doit être VRAI ou FAUX.

En outre, vous pouvez utiliser avg((gv).val)pour calculer la valeur moyenne.

ÉDITER

Le résultat de votre approche est le plus exact, mais le plus lent. Les résultats de la combinaison de ST_Clipet ST_DumpAsPolygonsignorent les cellules raster qui se croisent avec moins de 50% (ou 51%) de leur taille.

Ces deux captures d'écran d'une intersection CORINE Land Use montrent la différence. Première image avec ST_Intersection, deuxième avec ST_Clipet ST_DumpAsPolygons.

entrez la description de l'image ici

entrez la description de l'image ici

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.