Prestazioni nel calcolo delle statistiche raster in PostGIS


9

Sto cercando di calcolare le statistiche raster (min, max, media) per ogni poligono in un livello vettoriale usando PostgreSQL / PostGIS.

Questa risposta GIS.SE descrive come eseguire questa operazione, calcolando l'intersezione tra il poligono e il raster e quindi calcolando una media ponderata: https://gis.stackexchange.com/a/19858/12420

Sto usando la seguente query (dov'è il demmio raster, topo_area_su_regionè il mio vettore ed toidè un ID univoco:

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;

Funziona, ma è troppo lento. Il mio livello vettoriale ha 2489k funzioni, ognuna delle quali impiega circa 90 ms per l'elaborazione: occorrerebbero giorni per elaborare l'intero livello. La velocità del calcolo non sembra essere significativamente migliorata se calcolassi solo il minimo e il massimo (il che evita le chiamate a ST_Area).

Se eseguo un calcolo simile utilizzando Python (GDAL, NumPy e PIL), posso ridurre significativamente il tempo necessario per elaborare i dati, se invece di vettorizzare il raster (usando ST_Intersection) rasterizzo il vettore. Vedi il codice qui: https://gist.github.com/snorfalorpagus/7320167

Non ho davvero bisogno di una media ponderata - un approccio "se tocca, è in" è abbastanza buono - e sono ragionevolmente sicuro che questo è ciò che sta rallentando le cose.

Domanda : esiste un modo per far comportare PostGIS in questo modo? cioè per restituire i valori di tutte le celle dal raster toccato da un poligono, anziché dall'intersezione esatta.

Sono molto nuovo di PostgreSQL / PostGIS, quindi forse c'è qualcos'altro che non sto facendo bene. Sto eseguendo PostgreSQL 9.3.1 e PostGIS 2.1 su Windows 7 (2.9GHz i7, 8GB RAM) e ho modificato la configurazione del database come suggerito qui: http://postgis.net/workshops/postgis-intro/tuning.html

inserisci qui la descrizione dell'immagine


1
Ho modificato la mia risposta. Ho dimenticato di dire che l'intersezione nella mia risposta è meno precisa.
Stefan

Risposte:


11

Hai ragione, l'uso ST_Intersectionrallenta la tua query evidente.

Invece di usarlo ST_Intersectionè meglio tagliare ( ST_Clip) il tuo raster con i poligoni (i tuoi campi) e scaricare il risultato come poligoni ( ST_DumpAsPolygons). Quindi ogni cella raster verrà convertita in un piccolo rettangolo poligonale con valori distinti.

Per ricevere min, max o media dai dump è possibile utilizzare le stesse istruzioni.

Questa query dovrebbe fare il trucco:

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;

Nell'istruzione ST_Clipsi definisce il raster, la banda raster (= 1), il poligono e se il ritaglio deve essere VERO o FALSO.

Inoltre puoi usare avg((gv).val)per calcolare il valore medio.

MODIFICARE

Il risultato del tuo approccio è il più esatto, ma il più lento. I risultati della combinazione di ST_Clipe ST_DumpAsPolygonsstanno ignorando le celle raster che si intersecano con meno del 50% (o 51%) delle loro dimensioni.

Queste due schermate di un incrocio CORINE Land Use mostrano la differenza. Prima foto con ST_Intersection, seconda con ST_Clipe ST_DumpAsPolygons.

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.