fix: durcir les filtres AFAI — SWIR guard, NDWI marge côtière, filtre PostGIS 1km²

- S2 : ajout garde SWIR (B11 > 0.03 = artifact atmo/cirrus), NIR abaissé
  à 0.06, NDWI marge côtière (> 0.05), AFAI threshold 0.020
- S3 : même logique, NIR 0.06, NDWI 0.05, MCI 0.020
- PostGIS : suppression des polygones < 1 km² après vectorisation
  (résidus ponctuels = bruit ou artefact atmosphérique en Caraïbe)
- Auto-suppression de l'observation si plus aucun polygone valide
- PROCESSING_VERSION 1.2.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gwadaking
2026-04-02 17:04:20 -04:00
parent edca50200e
commit 6752b6df0b
2 changed files with 49 additions and 13 deletions

View File

@@ -18,7 +18,7 @@ class IngestionService
private const SARGASSUM_DN = 1;
private const SIMPLIFY_TOLERANCE = 0.001; // degrés (~100m à l'équateur)
private const MIN_RING_POINTS = 8; // filtre polygones < ~2 pixels (bruit)
private const PROCESSING_VERSION = '1.1.0';
private const PROCESSING_VERSION = '1.2.0';
public function __construct(
private SentinelHubClient $sentinelHub,
@@ -218,17 +218,46 @@ class IngestionService
return ['type' => 'MultiPolygon', 'coordinates' => $polygons];
}
private const MIN_POLYGON_AREA_M2 = 1_000_000; // 1 km² — filtre résidus AFAI
private function updateSpatialMeta(string $id): void
{
// 1) Filtrer les micro-polygones < MIN_POLYGON_AREA_M2 avant simplification
// Un fragment < 1 km² en plein océan est du bruit ou un artefact atmo.
$this->em->getConnection()->executeStatement(
"UPDATE sargassum_observation
SET geometry = (
SELECT COALESCE(
ST_Collect(geom),
'GEOMETRYCOLLECTION EMPTY'::geometry
)
FROM (
SELECT (ST_Dump(geometry)).geom AS geom
) parts
WHERE ST_Area(geom::geography) >= :minArea
)
WHERE id = :id",
['id' => $id, 'minArea' => self::MIN_POLYGON_AREA_M2]
);
// 2) Simplifier + calculer bbox et surface finale
$this->em->getConnection()->executeStatement(
'UPDATE sargassum_observation
SET
geometry = ST_SimplifyPreserveTopology(geometry, :tolerance),
bbox = ST_Envelope(geometry),
geometry = ST_SimplifyPreserveTopology(geometry, :tolerance),
bbox = ST_Envelope(geometry),
coverage_area = ROUND(CAST(ST_Area(geometry::geography) / 1000000 AS numeric), 2)
WHERE id = :id',
WHERE id = :id
AND NOT ST_IsEmpty(geometry)',
['id' => $id, 'tolerance' => self::SIMPLIFY_TOLERANCE]
);
// 3) Supprimer l'observation si plus rien ne reste après filtrage
$this->em->getConnection()->executeStatement(
'DELETE FROM sargassum_observation
WHERE id = :id AND (ST_IsEmpty(geometry) OR geometry IS NULL)',
['id' => $id]
);
}
private function cleanup(string $dir): void