Satellite Change Detection
A hands-on tutorial. Map deforestation, mining, urbanisation, floods, burns and surface-water change anywhere on Earth from free satellite data — then export georeferenced GeoTIFFs and print-ready maps. All in Python, powered by Google Earth Engine and Microsoft Planetary Computer.
Tutorial praktis. Petakan deforestasi, tambang, urbanisasi, banjir, kebakaran, dan perubahan air permukaan di mana saja dari data satelit gratis — lalu ekspor GeoTIFF tergeoreferensi dan peta siap cetak. Semua dengan Python, ditenagai Google Earth Engine dan Microsoft Planetary Computer.
1 · What you'll buildYang akan Anda buat
By the end you'll run a single command like this…
Di akhir tutorial, Anda menjalankan satu perintah seperti ini…
satchange -s deforestation --lat -3.333 --lon 122.25 --radius 6 --map
…and get three things for your chosen area:
…dan mendapat tiga berkas untuk area pilihan Anda:
- a quick-look PNG of the change,
- a full-resolution, georeferenced GeoTIFF you can open in QGIS/ArcGIS, and
- a value-added map (A4 PDF + PNG) with legend, scale bar, statistics and a location inset.
- PNG pratinjau perubahan,
- GeoTIFF resolusi penuh tergeoreferensi yang bisa dibuka di QGIS/ArcGIS, dan
- peta value-added (A4 PDF + PNG) dengan legenda, skala, statistik, dan inset lokasi.
You pick a scenario (what kind of change) and a location (a coordinate). The tool selects the right remote-sensing method automatically. No prior GIS coding required.
Anda memilih skenario (jenis perubahan) dan lokasi (koordinat). Alat memilih metode penginderaan jauh yang tepat secara otomatis. Tanpa perlu pengalaman pemrograman GIS.
2 · How it works (the science)Cara kerjanya (sainsnya)
“Change detection” compares the landscape at two (or more) points in time and highlights what changed. Different phenomena leave different spectral or radar fingerprints, so each scenario uses a purpose-built index or method:
“Deteksi perubahan” membandingkan bentang lahan pada dua (atau lebih) titik waktu dan menonjolkan apa yang berubah. Fenomena berbeda meninggalkan sidik jari spektral atau radar yang berbeda, sehingga tiap skenario memakai indeks atau metode khusus:
| ScenarioSkenario | Method & formulaMetode & rumus | Sensor | BasisDasar |
|---|---|---|---|
| deforestation | ΔNDVI < 0. NDVI = (NIR−Red)/(NIR+Red) = (B8−B4)/(B8+B4). Vegetation loss lowers NDVI.Kehilangan vegetasi menurunkan NDVI. | Sentinel-2 | NDVI (Rouse 1973; Tucker 1979) |
| urbanization | ΔNDBI > 0. NDBI = (SWIR−NIR)/(SWIR+NIR) = (B11−B8)/(B11+B8). Built-up reflects more SWIR.Permukaan terbangun memantulkan lebih banyak SWIR. | Sentinel-2 | Zha et al. 2003 |
| burn | dNBR. NBR = (NIR−SWIR2)/(NIR+SWIR2) = (B8−B12)/(B8+B12). Burns lower NBR.Kebakaran menurunkan NBR. | Sentinel-2 | Key & Benson 2006 |
| water | ΔNDWI. NDWI = (Green−NIR)/(Green+NIR) = (B3−B8)/(B3+B8). | Sentinel-2 | McFeeters 1996 |
| flood | SAR water: smooth water gives low VV backscatter. Uses one pre scene and one post scene from the same relative orbit (the latest pass in each window) — the standard S1 method, not a window average. Flood = water in the post scene but not the pre scene. Permanent water & the ocean are masked (ESA WorldCover). The two acquisition dates are reported in the stats and on the map.Air SAR: air halus memberi backscatter VV rendah. Memakai satu citra pra dan satu citra pasca dari orbit relatif yang sama (lintasan terbaru di tiap jendela) — metode S1 baku, bukan rata-rata jendela. Banjir = air pada citra pasca tetapi tidak pada citra pra. Air permanen & laut di-mask (ESA WorldCover). Kedua tanggal akuisisi ditampilkan di statistik dan peta. | Sentinel-1 | UN-SPIDER |
| disturbance | Impact mapping where water detection fails — forested hills, flash floods, landslides. Vegetation/structure removed → VH backscatter drops. Uses one pre + one post scene (same relative orbit); flags where VH fell >3 dB (severe >6 dB). SRTM slope attributes steep drops as landslide-like vs flat drops as sediment/inundation-like. Use this when flood shows nothing over terrain.Pemetaan dampak saat deteksi air gagal — perbukitan berhutan, banjir bandang, longsor. Vegetasi/struktur hilang → backscatter VH turun. Memakai satu citra pra + satu pasca (orbit relatif sama); menandai VH turun >3 dB (berat >6 dB). Lereng SRTM mengklasifikasi penurunan di lereng curam sebagai mirip longsor vs di dataran sebagai mirip endapan/genangan. Pakai ini saat flood tak menampilkan apa pun di medan bergunung. |
Sentinel-1 | SAR VH change + slopePerubahan VH SAR + lereng |
| coastline | Sea boundary, shoreline change & retreat rate. Extracts the sea↔land boundary as a raster and a vector polyline (GeoJSON). --pre/--post maps erosion (land→sea) vs accretion; --epochs builds a periodical time-series (shorelines-by-year map + trend) and casts cross-shore transects for the retreat rate in m/yr. Three sensors via --coast-method: sar (Sentinel-1, cloud-proof), optical (Sentinel-2 MNDWI sub-pixel, 2015+), landsat (MNDWI 30 m, back to 1984 — decadal change).Batas laut, perubahan garis pantai & laju surut. Mengekstrak batas laut↔darat sebagai raster dan polyline vektor (GeoJSON). --pre/--post memetakan abrasi (darat→laut) vs akresi; --epochs membangun deret waktu periodik (peta garis pantai per tahun + tren) dan membuat transek lintas-pantai untuk laju surut m/thn. Tiga sensor lewat --coast-method: sar (Sentinel-1, tembus awan), optical (MNDWI Sentinel-2 sub-piksel, sejak 2015), landsat (MNDWI 30 m, sejak 1984 — perubahan multi-dekade). |
S1 / S2 / Landsat | MNDWI + Otsu + marching-squares (MIT; not CoastSat/GPL)MNDWI + Otsu + marching-squares (MIT; bukan CoastSat/GPL) |
| transit-access | Share of population with access to public transport (SDG 11.2.1). Builds the pedestrian street network from OpenStreetMap, loads stops from your GeoJSON (--transit-file) or OSM, runs a multi-source Dijkstra so every node gets its walking distance along streets to the nearest stop, then weights by the WorldPop 100 m grid: a cell has access if its nearest street node is within the threshold (default 500 m; SDG 11.2.1 uses 500 m for buses, ~1 km for rail via --walk-dist 500,1000). Because it uses the real network, a river or limited-access road with no crossing correctly blocks access. Outputs the % served, a service-area polygon, and a map.Persentase populasi dengan akses ke transportasi publik (SDG 11.2.1). Membangun jaringan jalan pejalan kaki dari OpenStreetMap, memuat halte dari GeoJSON Anda (--transit-file) atau OSM, menjalankan multi-source Dijkstra agar tiap simpul memperoleh jarak jalan kaki menyusuri jalan ke halte terdekat, lalu dibobot grid WorldPop 100 m: sebuah sel dianggap punya akses bila simpul jalan terdekatnya ≤ ambang (default 500 m; SDG 11.2.1 memakai 500 m untuk bus, ~1 km untuk kereta lewat --walk-dist 500,1000). Karena memakai jaringan nyata, sungai atau jalan bebas-hambatan tanpa penyeberangan tetap memutus akses. Keluaran: % terlayani, poligon area terlayani, dan peta. |
WorldPop + OSM | Network Dijkstra + population weightingDijkstra jaringan + pembobotan populasi |
| mining | SIRAD: mean VH backscatter of 3 periods → an R/G/B image (new activity = blue). Plus ΔNDVI loss.SIRAD: rerata backscatter VH 3 periode → citra R/G/B (aktivitas baru = biru). Plus kehilangan ΔNDVI. | Sentinel-1 + S2 | Multi-temporal SARSAR multi-temporal |
| urban-trend | NDBI at 3 epochs → R/G/B timing composite. Blue = newest growth, white = built all epochs.NDBI di 3 epoch → komposit waktu R/G/B. Biru = pertumbuhan terbaru, putih = terbangun sepanjang waktu. | Landsat 5, 8/9 | Multi-epoch NDBI (archive to 1984; L7 skipped — SLC-off)NDBI multi-epoch (arsip sejak 1984; L7 dilewati — SLC-off) |
| urban-history | Built-up expansion & vegetation loss by decade since 1980. Combines GHSL GHS-BUILT-S (authoritative built-up surface, 1980-2025) with Landsat NDBI/NDVI. Produces a "first built-up decade" map (city sprawl ring by ring), a decadal panel, built-up & vegetation trend charts, a full-span vegetation-to-urban conversion map, and a one-page infographic poster. Landsat TM/OLI are kept separate (not comparable across the 2011→2013 break): TM epochs 1990/2000/2010 (mutually comparable) drive the vegetation-loss map; OLI epochs 2015/2020/2025 (mutually comparable) are reported separately. GHSL is GEE-only; on MPC it runs Landsat-only. It also overlays the current OSM road skeleton (motorway/toll/trunk/primary/secondary) as context — honest: OSM history records when a road was mapped, not built (data starts 2004; Indonesia only well-mapped after ~2015), so only today's network is shown, never a road-construction timeline.Perluasan terbangun & kehilangan vegetasi per dekade sejak 1980. Menggabungkan GHSL GHS-BUILT-S (permukaan terbangun otoritatif, 1980-2025) dengan NDBI/NDVI Landsat. Menghasilkan peta "dekade pertama terbangun" (kota meluas cincin demi cincin), panel per dekade, grafik tren terbangun & vegetasi, peta konversi vegetasi→urban rentang penuh, dan poster infografik satu halaman. TM/OLI Landsat dipisah (tak sebanding pada 2011→2013): epoch TM 1990/2000/2010 (sebanding satu sama lain) untuk peta vegetation-loss; epoch OLI 2015/2020/2025 (sebanding satu sama lain) dilaporkan terpisah. GHSL hanya di GEE; di MPC berjalan Landsat-saja. Juga menampilkan rangka jalan OSM terkini (tol/arteri) sebagai konteks — jujur: riwayat OSM mencatat kapan jalan dipetakan, bukan dibangun (data mulai 2004; Indonesia baru terpetakan baik setelah ~2015), jadi hanya jaringan masa kini yang ditampilkan, bukan lini masa pembangunan jalan. | GHSL + Landsat | EU JRC GHSL |
How clouds are handledCara menangani awan
Optical scenarios never rely on a single image. For each period the tool builds a cloud-masked median composite of many Sentinel-2 scenes: every scene is masked pixel-by-pixel using the Scene Classification (SCL) band, then the median is taken. The result is effectively cloud-free even in cloudy regions. The standalone Sentinel-2 downloader additionally prefers a single scene with ≤10% cloud, falling back to the composite when none exists.
Skenario optik tak pernah bergantung pada satu citra. Untuk tiap periode, alat menyusun median composite bebas awan dari banyak scene Sentinel-2: tiap scene di-mask per-piksel memakai band Scene Classification (SCL), lalu diambil mediannya. Hasilnya praktis bebas awan bahkan di wilayah berawan. Pengunduh Sentinel-2 mandiri juga mengutamakan satu scene dengan awan ≤10%, dan beralih ke composite bila tak ada.
3 · SetupPersiapan
You need Python 3.11+. The Earth Engine backend needs a free Google Earth Engine account (sign up); the Planetary Computer backend needs no account at all.
Anda memerlukan Python 3.11+. Backend Earth Engine butuh akun Google Earth Engine gratis (daftar); backend Planetary Computer tanpa akun sama sekali.
- Install the packagePasang paket
Gives you thepip install 'satchange[all]' # everything # or leaner: pip install 'satchange[gee]' · pip install 'satchange[mpc,maps]'satchangeandsatmapcommands. To work from source instead:git clone https://github.com/firmanhadi21/rs-change-detection && cd rs-change-detection && pip install -e '.[all]'— thenpython3 detect.py …works identically. Memberi perintahsatchangedansatmap. Untuk memakai dari sumber:git clone https://github.com/firmanhadi21/rs-change-detection && cd rs-change-detection && pip install -e '.[all]'— lalupython3 detect.py …berfungsi sama. - Authenticate Earth Engine (GEE backend only)Autentikasi Earth Engine (backend GEE saja)
Opens a browser to link your Google account. To use a service-account key from any directory, point satchange at it withearthengine authenticate--ee-key /path/to/ee-geodetic.json, orexport SATCHANGE_EE_KEY=/path/to/ee-geodetic.json, or copy it to~/.config/earthengine/ee-geodetic.json. (A key at./scripts/config/ee-geodetic.jsononly works when you run from the repo root.) Skip this entirely with--backend mpc. Membuka browser untuk menautkan akun Google. Untuk memakai kunci service account dari direktori mana pun, arahkan satchange dengan--ee-key /path/ke/ee-geodetic.json, atauexport SATCHANGE_EE_KEY=/path/ke/ee-geodetic.json, atau salin ke~/.config/earthengine/ee-geodetic.json. (Kunci di./scripts/config/ee-geodetic.jsonhanya berlaku saat dijalankan dari root repo.) Lewati dengan--backend mpc. - Check it's workingCek berjalan
Should print the six available scenarios. Harusnya menampilkan enam skenario.satchange --list
--backend mpc to any command — Microsoft Planetary Computer streams Sentinel-1/2 & Landsat Cloud-Optimized GeoTIFFs and processes them locally (comes with satchange[mpc]). Outputs and maps are identical.--drive (optionally --drive-folder NAME) to also start an async full-resolution export to your Google Drive. Note: Drive export uses your personal Google account — run earthengine authenticate first (a service-account key exports to the service account's own Drive, which you can't browse). Monitor the task in the EE Code Editor Tasks tab; the GeoTIFF appears in Drive/satchange/.--drive (opsional --drive-folder NAMA) untuk juga memulai ekspor resolusi penuh asinkron ke Google Drive Anda. Catatan: ekspor Drive memakai akun Google pribadi — jalankan earthengine authenticate dulu (kunci service account mengekspor ke Drive milik service account yang tak bisa Anda buka). Pantau task di tab Tasks EE Code Editor; GeoTIFF muncul di Drive/satchange/.--backend mpc pada perintah apa pun — Microsoft Planetary Computer mengalirkan COG Sentinel-1/2 & Landsat dan memprosesnya lokal (termasuk di satchange[mpc]). Keluaran dan peta identik.4 · Your first detectionDeteksi pertama Anda
Let's map vegetation loss around a coordinate. Pick any lat/lon (decimal degrees; south and west are negative).
Mari petakan kehilangan vegetasi di sekitar koordinat. Pilih lat/lon apa saja (derajat desimal; selatan dan barat negatif).
satchange -s deforestation --lat -3.333 --lon 122.25 --radius 6
The tool builds a square area of interest (half-side = radius km), makes a cloud-free Sentinel-2 NDVI composite for a baseline year and a recent year, subtracts them, and downloads the result. You'll see something like:
Alat membangun area minat persegi (setengah-sisi = radius km), membuat composite NDVI Sentinel-2 bebas awan untuk tahun dasar dan tahun terkini, menguranginya, lalu mengunduh hasilnya. Anda akan melihat kira-kira:
=== Change detection: deforestation ===
Location: -3.333, 122.25 radius 6.0 km [m3p333_122p25]
Downloading dndvi PNG... Saved: images/deforestation_dndvi_m3p333_122p25.png
Downloading dndvi GeoTIFF... Saved: data/deforestation_dndvi_m3p333_122p25.tif
=== Results ===
"pct_affected": 6.3, "pct_severe": 2.7, "scenes_pre": 30, "scenes_post": 25 …
- can confuse the shell if you use -l. Either use --lat/--lon (above) or attach the value with =: -l=-3.333,122.25.- di depan bisa membingungkan shell bila memakai -l. Gunakan --lat/--lon (di atas) atau sambungkan nilai dengan =: -l=-3.333,122.25.--city "Jakarta, Indonesia" instead of --lat/--lon — satchange geocodes it with free OpenStreetMap Nominatim and prints the resolved coordinates. Add a country for accuracy (e.g. --city "Bandung, Indonesia").--city "Jakarta, Indonesia" alih-alih --lat/--lon — satchange menggeokode dengan OpenStreetMap Nominatim gratis dan mencetak koordinat hasilnya. Tambahkan negara agar akurat (mis. --city "Bandung, Indonesia").5 · Reading the outputsMembaca keluaran
| FileBerkas | What it isIsinya | Open withBuka dengan |
|---|---|---|
…_<name>.png | Coloured quick-lookPratinjau berwarna | Any image viewerPenampil gambar apa saja |
…_<name>.tif | Full-resolution, georeferenced GeoTIFF (EPSG:4326)GeoTIFF resolusi penuh tergeoreferensi (EPSG:4326) | QGIS, ArcGIS, rasterio |
…_map.pdf / .png | Value-added map (with --map)Peta value-added (dengan --map) | PDF / image viewer |
stats.json | Statistics: % area affected, mean Δ, scene countsStatistik: % area terdampak, rerata Δ, jumlah scene | Any text editorEditor teks apa saja |
output/<timestamp>_<scenario>_<name>_<id>/ — PNG, GeoTIFF, stats, metadata (and maps) together, so runs never overwrite each other.output/<timestamp>_<skenario>_<nama>_<id>/ yang unik — PNG, GeoTIFF, statistik, metadata (dan peta) jadi satu, sehingga antar-run tak saling menimpa.For optical scenarios the change layer uses a diverging palette: red = loss, pale = little change, green = gain. The stats.json quantifies it — e.g. pct_affected is the share of the area whose change passed the threshold.
Untuk skenario optik, layer perubahan memakai palet divergen: merah = kehilangan, pucat = sedikit berubah, hijau = pertambahan. stats.json mengukurnya — mis. pct_affected adalah proporsi area yang perubahannya melewati ambang.
6 · Every scenarioSetiap skenario
List them any time with satchange --list. Commands:
Lihat daftarnya kapan saja dengan satchange --list. Perintah:
# Deforestation / vegetation loss (default baseline vs recent year)
satchange -s deforestation --lat -3.333 --lon 122.25
# Mining — radar temporal (SIRAD) + NDVI loss, two products
satchange -s mining --lat -3.333 --lon 122.25
# set the 3 SIRAD periods (R/G/B) yourself with --epochs:
satchange -s mining --lat -3.333 --lon 122.25 \
--epochs 2024-01-01:2024-06-30,2024-07-01:2024-12-31,2025-01-01:2025-06-30
# Urbanisation — built-up (NDBI) gain
satchange -s urbanization --lat -6.2 --lon 106.8 --radius 12
# Surface-water change (NDWI)
satchange -s water --lat -0.5 --lon 117.1
# Flood — needs an explicit baseline and event window
satchange -s flood --lat 27.2 --lon 68.3 \
--pre 2022-07-01:2022-07-25 --post 2022-08-20:2022-09-10
# Disturbance — flood/landslide impact in terrain, when flood shows nothing
satchange -s disturbance --lat 1.9983 --lon 99.4235 --radius 15 \
--pre 2025-11-01:2025-11-11 --post 2025-11-26:2025-11-29 --map
# Burn severity — needs pre-fire and post-fire windows
satchange -s burn --lat -7.5 --lon 110.4 \
--pre 2025-08-01:2025-08-20 --post 2025-09-10:2025-09-30
# Urban growth timing across 3 epochs (Landsat; default 2010/2015/2020)
satchange -s urban-trend --lat -6.30 --lon 107.15 --radius 10 --map
# Urban history: built-up by decade since 1980 (GHSL + Landsat), whole metro
satchange -s urban-history --lat -6.2 --lon 106.85 --radius 45 -n jabodetabek
# Hybrid: auto-locate the most-changed hotspot + a PlanetScope ~3 m close-up
satchange -s urban-history --lat -6.2 --lon 106.85 --radius 45 --planet # dry-run (free)
# Coastline: shoreline change (SAR) — erosion & accretion between two dates
satchange -s coastline --lat -6.95 --lon 110.45 --radius 8 \
--pre 2016-01-01:2016-12-31 --post 2025-01-01:2025-12-31
# Coastline time-series + retreat-rate transects (Landsat, back to the 1990s)
satchange -s coastline --coast-method landsat --lat -6.95 --lon 110.45 --radius 10 \
--epochs 1994-01-01:1996-12-31,2014-01-01:2016-12-31,2023-01-01:2025-12-31
# Custom cross-shore transects drawn in QGIS (clean m/yr in complex bays)
satchange -s coastline --coast-method landsat --city "Pekalongan" --radius 12 \
--epochs 1994-01-01:1996-12-31,2014-01-01:2016-12-31,2023-01-01:2025-12-31 \
--transects-file my_transects.geojson
# Public-transport access (SDG 11.2.1): % population within a walk of a stop
satchange -s transit-access --city "Semarang" --radius 8 --walk-dist 500,1000
# ...or supply your own stops/routes (e.g. a BRT corridor exported from QGIS)
satchange -s transit-access --city "Semarang" --radius 10 \
--transit-file transjateng_stops.geojson
satchange[transit]. -s transit-access pulls the OSM walking network (Overpass) + WorldPop (GEE), so install the extra: pip install 'satchange[transit]'. Stops come from OSM by default; pass --transit-file stops.geojson (points or route lines, auto-sampled) for networks OSM hasn't mapped — Indonesian angkot routes often aren't. Tune the corridor width of the drawn service area with --access-buffer (map only; the % is network-distance based, not buffer based).satchange[transit]. -s transit-access mengambil jaringan jalan OSM (Overpass) + WorldPop (GEE), jadi pasang ekstra: pip install 'satchange[transit]'. Halte default dari OSM; berikan --transit-file stops.geojson (titik atau garis rute, dicuplik otomatis) untuk jaringan yang belum dipetakan OSM — rute angkot sering belum ada. Setel lebar koridor area terlayani dengan --access-buffer (hanya peta; persentasenya berbasis jarak jaringan, bukan buffer).--transects-file). In complex bays the auto-transects can mis-orient. Draw your own cross-shore lines in QGIS, save them as a GeoJSON of LineStrings (first vertex = landward), and pass --transects-file my.geojson — each is intersected with every epoch's shoreline and regressed to a clean m/yr rate (CoastSat-style, MIT-native). On tides: shorelines here come from median composites, which are already tide-averaged (waterline ≈ mean tide). Per-scene tidal correction applies only to per-date imagery, not composites, so it's deliberately not faked.--transects-file). Di teluk kompleks, transek otomatis bisa salah arah. Gambar sendiri garis lintas-pantai di QGIS, simpan sebagai GeoJSON LineString (titik pertama = sisi darat), lalu berikan --transects-file my.geojson — tiap transek dipotong dengan garis pantai tiap epoch dan diregresi menjadi laju m/thn yang bersih (ala CoastSat, MIT-native). Soal pasang-surut: garis pantai di sini dari komposit median yang sudah ter-rata-rata terhadap pasang (waterline ≈ muka air rata-rata). Koreksi pasang per-scene hanya berlaku untuk citra per-tanggal, bukan komposit, jadi sengaja tidak dipalsukan.--planet). For urban-history, free wide-area GHSL locates the single most-changed grid cell, then a small, quota-cheap PlanetScope daily scene (4-band → NDVI works) zooms in at ~3 m. It's quota-safe: search is free, and ordering/downloading only happens with --planet-confirm. Set the change period with --hotspot-from/--hotspot-to and the imagery dates with --planet-pre/--planet-post. Key from $PLANET_API_KEY or ~/.planet.json/~/planet.conf. Without --planet, PlanetScope is never touched.--planet). Untuk urban-history, GHSL area-luas gratis menemukan sel paling banyak berubah, lalu satu scene harian PlanetScope (4-band → NDVI) meng-close-up pada ~3 m. Hemat kuota: pencarian gratis, unduhan hanya dengan --planet-confirm. Atur periode perubahan dengan --hotspot-from/--hotspot-to dan tanggal citra dengan --planet-pre/--planet-post. Kunci dari $PLANET_API_KEY atau ~/.planet.json/~/planet.conf. Tanpa --planet, PlanetScope tak pernah disentuh.--pre START:END --post START:END (format YYYY-MM-DD:YYYY-MM-DD). Other scenarios have default windows you can still override. For flood, each window is a search range, not a composite — the tool picks a single Sentinel-1 scene from each (the most recent pass, same relative orbit). Keep windows tight (≈2–4 weeks) so each holds a pass but doesn't reach far from the event; place --post to end on/after the flood peak, since it takes the latest pass in the window.--pre START:END --post START:END (format YYYY-MM-DD:YYYY-MM-DD). Skenario lain punya jendela default yang tetap bisa diubah. Untuk banjir, tiap jendela adalah rentang pencarian, bukan komposit — alat memilih satu citra Sentinel-1 dari masing-masing (lintasan terbaru, orbit relatif sama). Buat jendela sempit (≈2–4 minggu) agar tiap jendela berisi satu lintasan namun tidak jauh dari kejadian; atur --post berakhir pada/setelah puncak banjir, karena diambil lintasan terbaru dalam jendela.-s mining builds an R/G/B radar composite from three time periods — blue = activity only in the newest. Set them with --epochs W1,W2,W3 (the same option urban-trend uses); omit it for the default recent years: satchange -s mining --lat -3.333 --lon 122.25 --epochs 2024-01-01:2024-12-31,2025-01-01:2025-12-31,2026-01-01:2026-06-30-s mining membangun komposit radar R/G/B dari tiga periode — biru = aktivitas hanya di periode terbaru. Aturlah dengan --epochs W1,W2,W3 (opsi yang sama dengan urban-trend); kosongkan untuk memakai tahun terkini default: satchange -s mining --lat -3.333 --lon 122.25 --epochs 2024-01-01:2024-12-31,2025-01-01:2025-12-31,2026-01-01:2026-06-30--method. Sentinel-2 built-up: NDBI (default), UI, BU (=NDBI−NDVI), IBI. Thermal built-up NDISI, EBBI auto-switch to Landsat 8/9 (they need a thermal band Sentinel-2 lacks). Each method has its own default thresholds — tune with --thr/--severe.--method. Built-up Sentinel-2: NDBI (default), UI, BU (=NDBI−NDVI), IBI. Indeks termal NDISI, EBBI otomatis beralih ke Landsat 8/9 (butuh band termal yang tak ada di Sentinel-2). Tiap metode punya ambang default — setel dengan --thr/--severe.-s urban-trend, which runs on Landsat (archive back to 1984) and maps NDBI at three epochs to R/G/B in one image (white = built the whole time, blue = newest growth): satchange -s urban-trend --lat -6.30 --lon 107.15 --epochs 2010-01-01:2010-12-31,2015-01-01:2015-12-31,2020-01-01:2020-12-31-s urban-trend yang berbasis Landsat (arsip sejak 1984) dan memetakan NDBI tiga epoch ke R/G/B dalam satu citra (putih = terbangun terus, biru = paling baru): satchange -s urban-trend --lat -6.30 --lon 107.15 --epochs 2010-01-01:2010-12-31,2015-01-01:2015-12-31,2020-01-01:2020-12-31
urban-trend over Cikarang/Bekasi (east Jakarta). Built-up grew 10% (2010) → 23% (2020), 15% newly built. White = built the whole time; blue/cyan = newer growth.urban-trend di Cikarang/Bekasi (timur Jakarta). Built-up tumbuh 10% (2010) → 23% (2020), 15% baru. Putih = terbangun terus; biru/cyan = pertumbuhan lebih baru.7 · Make a map productMembuat produk peta
Add --map to any run to render an A4-landscape map sheet (PDF + PNG) per product: OpenStreetMap basemap, the change layer, title, legend, a statistics panel, a location inset, coordinate grid, scale bar and north arrow.
Tambahkan --map pada run apa pun untuk membuat lembar peta A4 landscape (PDF + PNG) per produk: basemap OpenStreetMap, layer perubahan, judul, legenda, panel statistik, inset lokasi, grid koordinat, skala, dan panah utara.
satchange -s mining --lat -3.333 --lon 122.25 --map
Already have results and just want to re-render (no Earth Engine needed)? Every run drops a .meta.json sidecar, so:
Sudah punya hasil dan ingin render ulang (tanpa Earth Engine)? Tiap run menulis sidecar .meta.json, jadi:
satmap output/20260708-2226_deforestation_x_fac24e # a run folder
satmap output/<run>/mining_sirad_x.tif --basemap gray # or one .tif
Maps land in maps/. Tweak the layout in mapmaker.py and re-run instantly.
Peta tersimpan di maps/. Ubah tata letak di mapmaker.py lalu jalankan ulang seketika.
8 · Adapt it to your own areaMenyesuaikan untuk area Anda
Pick a locationPilih lokasi
Find coordinates by right-clicking a spot in Google Maps (it copies lat, lon), or from OpenStreetMap. Choose a --radius to match the feature: a few km for a single mine or town, 10–20 km for a flood plain or a fire.
Cari koordinat dengan klik kanan di Google Maps (menyalin lat, lon), atau dari OpenStreetMap. Pilih --radius sesuai objek: beberapa km untuk satu tambang atau kota, 10–20 km untuk dataran banjir atau kebakaran.
Save a named presetSimpan preset bernama
Add reusable places to sites.py and call them with --site:
Tambahkan lokasi yang sering dipakai ke sites.py dan panggil dengan --site:
SITES = {
"my_area": {
"label": "My study area",
"lat": 1.234, "lon": 103.456, "radius_km": 8.0,
"sentinel2_date": "2026-06-15",
"sirad_periods": [("2024-01-01","2024-12-31"),
("2025-01-01","2025-12-31"),
("2026-01-01","2026-06-30")],
"ndvi_pre": ("2023-01-01","2023-12-31"),
"ndvi_post": ("2026-01-01","2026-06-30"),
},
}
satchange -s deforestation --site my_area --map
Add a brand-new scenarioTambah skenario baru
Most scenarios are one dictionary entry in scenarios.py. To add, say, a moisture-change scenario using NDWI on a custom threshold you only add a registry entry — the generic optical-change engine does the rest:
Kebanyakan skenario hanya satu entri dictionary di scenarios.py. Untuk menambah, misalnya, skenario perubahan kelembapan memakai NDWI dengan ambang khusus, cukup tambahkan satu entri — mesin perubahan optik generik menangani sisanya:
"moisture": {
"label": "Moisture change (NDWI)",
"run": _optical("NDWI", "gain", 0.08, 0.20), # index, direction, thresholds
"radius": 10.0, "needs": "pre_post",
"pre": ("2023-01-01","2023-12-31"),
"post": ("2025-01-01","2025-12-31"),
"interpretation": "Greener = wetter.",
},
New spectral indices go in indices.py (a one-line normalised difference). Radar or bespoke methods get a small run_* function in scenarios.py.
Indeks spektral baru masuk ke indices.py (satu baris normalized difference). Metode radar atau khusus memakai fungsi run_* kecil di scenarios.py.
9 · Reproducibility & dataReproduksibilitas & data
- Data: Copernicus Sentinel-1 (radar) and Sentinel-2 (optical), free and open, courtesy ESA, processed in Google Earth Engine.
- AOI: a square centred on your coordinate (half-side = radius), axis-aligned in EPSG:4326.
- Orbit auto-selection: radar scenarios check both ascending and descending orbits and use whichever has imagery in every period.
- Outputs are regenerable, so results and maps are git-ignored; only code and this tutorial are versioned.
- Data: Copernicus Sentinel-1 (radar) dan Sentinel-2 (optik), gratis dan terbuka, dari ESA, diproses di Google Earth Engine.
- AOI: persegi berpusat di koordinat Anda (setengah-sisi = radius), sejajar sumbu di EPSG:4326.
- Pemilihan orbit otomatis: skenario radar memeriksa orbit ascending dan descending lalu memakai yang punya citra di tiap periode.
- Keluaran bisa dibuat ulang, jadi hasil dan peta di-git-ignore; hanya kode dan tutorial ini yang diversikan.
10 · TroubleshootingPemecahan masalah
| SymptomGejala | FixSolusi |
|---|---|
No Sentinel-2 scenes in pre/post window | Widen your --pre/--post dates or increase --radius. Very cloudy tropics may need a longer window.Perlebar tanggal --pre/--post atau perbesar --radius. Tropis sangat berawan mungkin butuh jendela lebih panjang. |
No orbit covers all periods | Enlarge the radius or shift the period dates; Sentinel-1 coverage is sparse in some years/areas.Perbesar radius atau geser tanggal periode; cakupan Sentinel-1 jarang di sebagian tahun/area. |
| Earth Engine auth errorsGalat autentikasi Earth Engine | Usually a wrong working directory: the key at scripts/config/ee-geodetic.json is only found when you run from the repo root. Pass --ee-key /path/to/ee-geodetic.json, set SATCHANGE_EE_KEY, copy the key to ~/.config/earthengine/ee-geodetic.json, or re-run earthengine authenticate.Biasanya direktori kerja salah: kunci di scripts/config/ee-geodetic.json hanya ditemukan saat dijalankan dari root repo. Berikan --ee-key /path/ke/ee-geodetic.json, set SATCHANGE_EE_KEY, salin kunci ke ~/.config/earthengine/ee-geodetic.json, atau jalankan ulang earthengine authenticate. |
Basemap missing / Basemap hilang / EPSG code unknown | A stale external PROJ database (e.g. from an OTB install) is shadowing PROJ. The tool clears PROJ_LIB; if it persists, unset PROJ_LIB.Basis data PROJ eksternal usang (mis. dari OTB) menutupi PROJ. Alat menghapus PROJ_LIB; bila masih, jalankan unset PROJ_LIB. |
| Direct GeoTIFF download refusedUnduhan GeoTIFF langsung ditolak | Very large AOIs exceed Earth Engine's limit — reduce --radius, or use --drive to export to Google Drive.AOI sangat besar melewati batas Earth Engine — kecilkan --radius, atau pakai --drive untuk ekspor ke Google Drive. |
11 · Further readingBacaan lanjut
- Zha, Gao & Ni (2003). Use of NDBI in automatically mapping urban areas from TM imagery. Int. J. Remote Sensing 24(3).
- Key & Benson (2006). Landscape Assessment: the Normalized Burn Ratio (NBR/dNBR). USDA Forest Service, FIREMON.
- UN-SPIDER. Recommended Practice: Flood Mapping with Sentinel-1 SAR in Google Earth Engine.
- UN-SPIDER. Normalized Burn Ratio — in detail.
- Earth Lab. Work with the Differenced Normalized Burn Index (dNBR).
- Google Earth Engine. Sentinel-1 SAR guide · Sentinel-2 SR Harmonized.