diff --git a/sentinel-2/sentinel-2.md b/sentinel-2/sentinel-2.md index bcda4b0b..98927bf7 100644 --- a/sentinel-2/sentinel-2.md +++ b/sentinel-2/sentinel-2.md @@ -135,6 +135,8 @@ Dedicated to supplying data for [Copernicus services](https://www.esa.int/Our_Ac - [Water In Wetlands Index (WIW)](/sentinel-2/wiw_s2_script) - [Simple Water Bodies' Mapping - SWBM ](/sentinel-2/simple_water_bodies_mapping-swbm) - [MAGO Water Quality Monitoring Tool](/sentinel-2/mago_water_quality_monitoring_tool) + - [Ship detection](/sentinel-2/ship_detection) - highlights ships at sea and their wakes + #### Urban planning algorithms - [Green city](/sentinel-2/green_city) diff --git a/sentinel-2/ship_detection/README.md b/sentinel-2/ship_detection/README.md new file mode 100644 index 00000000..f0fdda0c --- /dev/null +++ b/sentinel-2/ship_detection/README.md @@ -0,0 +1,61 @@ +--- +title: Ship detection +parent: Sentinel-2 +grand_parent: Sentinel +layout: script +permalink: /sentinel-2/ship_detection/ +nav_exclude: true +examples: +- zoom: '14' + lat: '35.39643' + lng: '13.21956' + datasetId: S2L2A + fromTime: '2026-06-02T00:00:00.000Z' + toTime: '2026-06-02T23:59:59.999Z' + platform: + - CDSE + - EOB + evalscripturl: https://custom-scripts.sentinel-hub.com/custom-scripts/sentinel-2/ship_detection/script.js +--- + +## General description + +This script highlights **ships** on the open sea in Sentinel-2 L2A optical imagery, and is a +quick-look / spotting tool for the Copernicus Browser. It is especially useful for fishing +vessels: alongside the hulls it brings out their **wakes** and - when a purse-seine set is in +progress - the thin curved **net floatline** arc a seiner pays out around a school. + +Vessels are picked out with a simple per-pixel test: over open water the near-infrared (B08) and +short-wave infrared (B11/B12) reflectances are very low, while a hull is comparatively bright in +those bands, so a pixel is flagged as a likely vessel when + +``` +B08 > SHIP_T_NIR OR B11 > SHIP_T_SWIR OR B12 > SHIP_T_SWIR +``` + +A gamma-stretched true-color base (`WATER_MAX`, `GAMMA`) brings out wakes, slicks and the sunglint +texture in which floatline arcs are visible. + +The script has four modes (set `MODE` at the top): + +- `MODE = 0` - **Enhanced true color**: wakes, slicks and sunglint texture. +- `MODE = 1` - **Vessel highlighter** (default): likely hulls flagged red on a dimmed base. +- `MODE = 2` - **NIR/SWIR false color**: hulls glow, water goes black. +- `MODE = 3` - **Glint-stretch (mono)**: maximum surface texture for nets and wakes. + +**Tuning:** sunglint varies strongly between scenes, so raise `SHIP_T_NIR` / `SHIP_T_SWIR` over +bright, glinty water and lower them over calm, dark water. Note this is a *per-pixel* script +(Sentinel Hub evalscripts have no access to neighbouring pixels), so it spots candidates but does +not measure or filter them by cluster size - that kind of spatial analysis is a downstream step. + +## Description of representative images + +Fishing vessels (tuna purse seiners) working SE of Lampedusa (Strait of Sicily) during the +bluefin season; vessels flagged red with `MODE = 1`. Acquired 2026-06-02. + +![Ships highlighted in the Strait of Sicily](fig/fig1.png) + +## References + +- Sentinel-2 bands: [Sentinel-2 L2A documentation](https://docs.sentinel-hub.com/api/latest/data/sentinel-2-l2a/) +- Custom scripts evalscript reference: [Evalscript V3](https://docs.sentinel-hub.com/api/latest/evalscript/v3/) diff --git a/sentinel-2/ship_detection/fig/fig1.png b/sentinel-2/ship_detection/fig/fig1.png new file mode 100644 index 00000000..4079eab3 Binary files /dev/null and b/sentinel-2/ship_detection/fig/fig1.png differ diff --git a/sentinel-2/ship_detection/script.js b/sentinel-2/ship_detection/script.js new file mode 100644 index 00000000..05cfd9cc --- /dev/null +++ b/sentinel-2/ship_detection/script.js @@ -0,0 +1,36 @@ +//VERSION=3 +// ============================================================ +// Purse-seiner / wake / net interpreter for Sentinel-2 L2A +// Paste into Copernicus Browser -> Custom script. Pick a MODE. +// 0 = Enhanced true color -> wakes, slicks, sunglint texture +// 1 = Vessel highlighter -> hulls flagged red on a dim base +// 2 = NIR/SWIR false color -> hulls glow, water goes black +// 3 = Glint-stretch (mono) -> max surface texture for nets/wakes +// Tune WATER_MAX / GAMMA / SHIP_T_* below. +// Note: per-pixel only (no spatial filtering in-browser). For wake/net +// edge enhancement and detection, use the offline toolkit (Run-SeinerScan.ps1). +// ============================================================ + +const MODE = 1; + +const WATER_MAX = 0.06; // reflectance mapped to white for water bands (raise to see more texture) +const GAMMA = 0.6; // <1 brightens wakes/slicks +const STRETCH = 1.0; // overall gain + +const SHIP_T_NIR = 0.045; // B08 threshold (hull bright in NIR vs dark water) +const SHIP_T_SWIR = 0.020; // B11/B12 threshold (water ~0 in SWIR) + +function setup() { + return { input: ["B02","B03","B04","B08","B11","B12","dataMask"], output: { bands: 3 } }; +} +function s(x){ let v=Math.max(0,Math.min(1,(x/WATER_MAX)*STRETCH)); return Math.pow(v,GAMMA); } +function isShip(p){ return (p.B08>SHIP_T_NIR)||(p.B11>SHIP_T_SWIR)||(p.B12>SHIP_T_SWIR); } + +function evaluatePixel(p){ + let tc=[s(p.B04),s(p.B03),s(p.B02)]; // S2 order: R=B04 G=B03 B=B02 + if (MODE===0) return tc; + if (MODE===1){ if(isShip(p)) return [1.0,0.1,0.0]; return [tc[0]*0.5,tc[1]*0.5,tc[2]*0.7]; } + if (MODE===2) return [Math.min(1,p.B12*12), Math.min(1,p.B08*12), s(p.B03)]; + if (MODE===3){ let g=s(p.B03); if(isShip(p)) return [1.0,0.7,0.0]; return [g,g,g]; } + return tc; +}