Kinerja dalam menghitung statistik raster di PostGIS

9

Saya mencoba menghitung statistik raster (min, maks, rata-rata) untuk setiap poligon dalam lapisan vektor menggunakan PostgreSQL / PostGIS.

Jawaban GIS.SE ini menjelaskan cara melakukan ini, dengan menghitung persimpangan antara poligon dan raster, lalu menghitung rata-rata tertimbang: https://gis.stackexchange.com/a/19858/12420

Saya menggunakan kueri berikut (di mana demraster saya, topo_area_su_regionadalah vektor saya, dan toidmerupakan ID unik:

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;

Ini berfungsi, tetapi terlalu lambat. Layer vektor saya memiliki fitur 2489k, dengan masing-masing membutuhkan sekitar 90 ms untuk diproses - akan butuh berhari - hari untuk memproses seluruh layer. Kecepatan perhitungan tampaknya tidak meningkat secara signifikan jika saya hanya menghitung min dan maks (yang menghindari panggilan ke ST_Area).

Jika saya melakukan perhitungan yang sama menggunakan Python (GDAL, NumPy dan PIL) saya dapat secara signifikan mengurangi jumlah waktu yang dibutuhkan untuk memproses data, jika alih-alih membuat vektor raster (menggunakan ST_Intersection) saya rasterize vektor. Lihat kode di sini: https://gist.github.com/snorfalorpagus/7320167

Saya tidak benar-benar membutuhkan rata-rata tertimbang - pendekatan "jika menyentuh, berarti" cukup baik - dan saya cukup yakin inilah yang memperlambat segalanya.

Pertanyaan : Apakah ada cara agar PostGIS berperilaku seperti ini? yaitu untuk mengembalikan nilai semua sel dari raster yang disentuh poligon, daripada persimpangan yang tepat.

Saya sangat baru di PostgreSQL / PostGIS, jadi mungkin ada hal lain yang tidak saya lakukan dengan benar. Saya menjalankan PostgreSQL 9.3.1 dan PostGIS 2.1 pada Windows 7 (2.9GHz i7, 8GB RAM) dan telah mengubah konfigurasi database seperti yang disarankan di sini: http://postgis.net/workshops/postgis-intro/tuning.html

masukkan deskripsi gambar di sini

Snorfalorpagus
sumber
1
Saya sudah mengedit jawaban saya. Saya lupa mengatakan bahwa persimpangan dalam jawaban saya kurang akurat.
Stefan

Jawaban:

11

Anda benar, menggunakan ST_Intersectionmemperlambat permintaan Anda terlihat.

Alih-alih menggunakannya ST_Intersectionlebih baik untuk memotong ( ST_Clip) raster Anda dengan poligon (bidang Anda) dan membuang hasilnya sebagai poligon ( ST_DumpAsPolygons). Jadi setiap sel raster akan dikonversi menjadi persegi panjang poligon kecil dengan nilai yang berbeda.

Untuk menerima min, maks atau berarti dari kesedihan Anda dapat menggunakan pernyataan yang sama.

Kueri ini harus melakukan trik:

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;

Dalam pernyataan yang ST_ClipAnda tentukan raster, band raster (= 1), poligon dan jika krop harus TRUE atau FALSE.

Selain itu Anda dapat menggunakan avg((gv).val)untuk menghitung nilai rata-rata.

EDIT

Hasil pendekatan Anda lebih tepat, tetapi lebih lambat. Hasil kombinasi ST_Clipdan ST_DumpAsPolygonsmengabaikan sel raster yang berpotongan dengan kurang dari 50% (atau 51%) dari ukurannya.

Dua tangkapan layar ini dari persimpangan CORINE Land Use menunjukkan perbedaan. Gambar pertama dengan ST_Intersection, gambar kedua dengan ST_Clipdan ST_DumpAsPolygons.

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Stefan
sumber