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ù dem
est mon raster, topo_area_su_region
mon vecteur et toid
un 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
la source
Réponses:
Vous avez raison, l'utilisation
ST_Intersection
ralentit sensiblement votre requête.Au lieu de l'utiliser,
ST_Intersection
il 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:
Dans l'instruction,
ST_Clip
vous 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_Clip
etST_DumpAsPolygons
ignorent 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 avecST_Clip
etST_DumpAsPolygons
.la source