Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sentinel-2/sentinel-2.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
61 changes: 61 additions & 0 deletions sentinel-2/ship_detection/README.md
Original file line number Diff line number Diff line change
@@ -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/)
Binary file added sentinel-2/ship_detection/fig/fig1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions sentinel-2/ship_detection/script.js
Original file line number Diff line number Diff line change
@@ -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;
}