Skip to content

Commit 386fe67

Browse files
committed
fixxed date selection in advancd settings
1 parent d8883cf commit 386fe67

3 files changed

Lines changed: 44 additions & 85 deletions

File tree

backend/gee_processing.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,14 @@ def initialize_gee():
5858
raise
5959

6060

61-
def get_sentinel1_image(geometry: Dict[str, Any]) -> Tuple[Optional[ee.Image], Optional[str]]:
61+
def get_sentinel1_image(geometry: Dict[str, Any], start_date: Optional[str] = None) -> Tuple[Optional[ee.Image], Optional[str]]:
6262
"""
6363
Get the most recent Sentinel-1 image for the AOI
6464
6565
Args:
6666
geometry: GeoJSON geometry dict
67+
start_date: Optional end date (YYYY-MM-DD). If provided, searches for latest image on or before this date.
68+
If None, searches last 30 days.
6769
6870
Returns:
6971
Tuple of (ee.Image, acquisition_date_string) or (None, None) if no imagery found
@@ -72,14 +74,23 @@ def get_sentinel1_image(geometry: Dict[str, Any]) -> Tuple[Optional[ee.Image], O
7274
# Convert GeoJSON to ee.Geometry
7375
ee_geometry = ee.Geometry(geometry)
7476

75-
# Define date range (last 30 days)
76-
end_date = datetime.now()
77-
start_date = end_date - timedelta(days=30)
77+
# Define date range
78+
if start_date:
79+
# Parse user-provided date and search backwards from it
80+
end = datetime.strptime(start_date, '%Y-%m-%d')
81+
# Search up to 90 days before the selected date
82+
start = end - timedelta(days=90)
83+
logger.info(f"Searching for latest imagery on or before {start_date}")
84+
else:
85+
# Default: search last 30 days to present
86+
end = datetime.now()
87+
start = end - timedelta(days=30)
88+
logger.info("Searching for imagery from last 30 days")
7889

7990
# Filter Sentinel-1 collection
8091
collection = (ee.ImageCollection('COPERNICUS/S1_GRD')
8192
.filterBounds(ee_geometry)
82-
.filterDate(start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d'))
93+
.filterDate(start.strftime('%Y-%m-%d'), end.strftime('%Y-%m-%d'))
8394
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'))
8495
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH'))
8596
.filter(ee.Filter.eq('instrumentMode', 'IW'))
@@ -93,7 +104,8 @@ def get_sentinel1_image(geometry: Dict[str, Any]) -> Tuple[Optional[ee.Image], O
93104
size = image_list.size().getInfo()
94105

95106
if size == 0:
96-
logger.warning("No Sentinel-1 imagery found in the last 30 days")
107+
date_range = f"from {start_date}" if start_date else "in the last 30 days"
108+
logger.warning(f"No Sentinel-1 imagery found {date_range}")
97109
return None, None
98110

99111
# Get the image

backend/main.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@
4343
class WaterDetectionRequest(BaseModel):
4444
"""Request model for water detection"""
4545
geometry: Dict[str, Any] = Field(..., description="GeoJSON geometry (Polygon or MultiPolygon)")
46-
vv_threshold: Optional[float] = Field(None, ge=-30, le=0, description="VV polarization threshold in dB")
47-
vh_threshold: Optional[float] = Field(None, ge=-35, le=0, description="VH polarization threshold in dB")
48-
vv_vh_diff: Optional[float] = Field(None, ge=0, le=10, description="VV-VH difference threshold")
46+
start_date: Optional[str] = Field(None, description="Start date for imagery search (YYYY-MM-DD). Searches from this date to present.")
4947
slope_max: Optional[float] = Field(None, ge=0, le=30, description="Maximum slope in degrees")
5048
min_area_pixels: Optional[int] = Field(None, ge=1, le=1000, description="Minimum area in pixels")
5149
texture_window: Optional[int] = Field(None, ge=1, le=9, description="Texture analysis window size")
@@ -112,7 +110,7 @@ async def detect_water_endpoint(request: WaterDetectionRequest):
112110

113111
# Get Sentinel-1 imagery
114112
logger.info("Fetching Sentinel-1 imagery...")
115-
s1_image, acquisition_date = get_sentinel1_image(request.geometry)
113+
s1_image, acquisition_date = get_sentinel1_image(request.geometry, start_date=request.start_date)
116114

117115
if s1_image is None:
118116
# No imagery found - return empty result with warning
@@ -145,18 +143,10 @@ async def detect_water_endpoint(request: WaterDetectionRequest):
145143
logger.info("Detecting water...")
146144
# Only include non-None parameters
147145
params = {}
148-
if request.vv_threshold is not None:
149-
params['vv_threshold'] = request.vv_threshold
150-
if request.vh_threshold is not None:
151-
params['vh_threshold'] = request.vh_threshold
152-
if request.vv_vh_diff is not None:
153-
params['vv_vh_diff'] = request.vv_vh_diff
154146
if request.slope_max is not None:
155147
params['slope_max'] = request.slope_max
156148
if request.min_area_pixels is not None:
157149
params['min_area_pixels'] = request.min_area_pixels
158-
if request.texture_window is not None:
159-
params['texture_window'] = request.texture_window
160150

161151
# Pass raw image for better threshold calculation
162152
params['raw_image'] = s1_image
@@ -218,9 +208,7 @@ async def detect_water_endpoint(request: WaterDetectionRequest):
218208
"processing_time_seconds": processing_time,
219209
"aoi_area_km2": round(area_km2, 2),
220210
"parameters_used": {
221-
"vv_threshold": request.vv_threshold or "auto (Otsu)",
222-
"vh_threshold": request.vh_threshold or -20,
223-
"vv_vh_diff": request.vv_vh_diff or 2,
211+
"start_date": request.start_date or "latest available",
224212
"slope_max": request.slope_max or 5,
225213
"min_area_pixels": request.min_area_pixels or 100
226214
}

frontend/src/components/AdvancedPanel.js

Lines changed: 23 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ import './AdvancedPanel.css';
33

44
function AdvancedPanel({ showAdvanced, setShowAdvanced, params, setParams }) {
55
const handleParamChange = (key, value) => {
6+
setParams({
7+
...params,
8+
[key]: value === '' ? null : value,
9+
});
10+
};
11+
12+
const handleNumericChange = (key, value) => {
613
setParams({
714
...params,
815
[key]: value === '' ? null : parseFloat(value),
@@ -21,77 +28,32 @@ function AdvancedPanel({ showAdvanced, setShowAdvanced, params, setParams }) {
2128
{showAdvanced && (
2229
<div className="advanced-content">
2330
<p className="advanced-help">
24-
Leave blank to use automatic (Otsu) thresholding.
25-
Adjust these values to fine-tune water detection.
31+
Fine-tune detection settings for specific scenarios.
2632
</p>
2733

2834
<div className="param-group">
2935
<label>
30-
<span className="param-label">VV Threshold (dB)</span>
31-
<span className="param-value">
32-
{params.vv_threshold ?? 'Auto'}
33-
</span>
34-
</label>
35-
<input
36-
type="range"
37-
min="-25"
38-
max="-5"
39-
step="0.5"
40-
value={params.vv_threshold ?? -15}
41-
onChange={(e) => handleParamChange('vv_threshold', e.target.value)}
42-
/>
43-
<button
44-
className="reset-btn"
45-
onClick={() => handleParamChange('vv_threshold', '')}
46-
>
47-
Reset
48-
</button>
49-
</div>
50-
51-
<div className="param-group">
52-
<label>
53-
<span className="param-label">VH Threshold (dB)</span>
36+
<span className="param-label">End Date (optional)</span>
5437
<span className="param-value">
55-
{params.vh_threshold ?? -20}
38+
{params.start_date || 'Latest available'}
5639
</span>
5740
</label>
5841
<input
59-
type="range"
60-
min="-30"
61-
max="-10"
62-
step="0.5"
63-
value={params.vh_threshold ?? -20}
64-
onChange={(e) => handleParamChange('vh_threshold', e.target.value)}
65-
/>
66-
<button
67-
className="reset-btn"
68-
onClick={() => handleParamChange('vh_threshold', '')}
69-
>
70-
Reset
71-
</button>
72-
</div>
73-
74-
<div className="param-group">
75-
<label>
76-
<span className="param-label">VV-VH Difference</span>
77-
<span className="param-value">
78-
{params.vv_vh_diff ?? 8}
79-
</span>
80-
</label>
81-
<input
82-
type="range"
83-
min="0"
84-
max="15"
85-
step="0.5"
86-
value={params.vv_vh_diff ?? 8}
87-
onChange={(e) => handleParamChange('vv_vh_diff', e.target.value)}
42+
type="date"
43+
value={params.start_date || ''}
44+
max={new Date().toISOString().split('T')[0]}
45+
onChange={(e) => handleParamChange('start_date', e.target.value)}
46+
style={{ width: '100%', padding: '8px', fontSize: '14px' }}
8847
/>
8948
<button
9049
className="reset-btn"
91-
onClick={() => handleParamChange('vv_vh_diff', '')}
50+
onClick={() => handleParamChange('start_date', '')}
9251
>
9352
Reset
9453
</button>
54+
<p style={{ fontSize: '12px', color: '#666', margin: '4px 0 0 0' }}>
55+
Searches for latest image on or before this date
56+
</p>
9557
</div>
9658

9759
<div className="param-group">
@@ -107,7 +69,7 @@ function AdvancedPanel({ showAdvanced, setShowAdvanced, params, setParams }) {
10769
max="15"
10870
step="1"
10971
value={params.slope_max ?? 5}
110-
onChange={(e) => handleParamChange('slope_max', e.target.value)}
72+
onChange={(e) => handleNumericChange('slope_max', e.target.value)}
11173
/>
11274
<button
11375
className="reset-btn"
@@ -130,7 +92,7 @@ function AdvancedPanel({ showAdvanced, setShowAdvanced, params, setParams }) {
13092
max="500"
13193
step="10"
13294
value={params.min_area_pixels ?? 100}
133-
onChange={(e) => handleParamChange('min_area_pixels', e.target.value)}
95+
onChange={(e) => handleNumericChange('min_area_pixels', e.target.value)}
13496
/>
13597
<button
13698
className="reset-btn"
@@ -143,15 +105,12 @@ function AdvancedPanel({ showAdvanced, setShowAdvanced, params, setParams }) {
143105
<button
144106
className="reset-all-btn"
145107
onClick={() => setParams({
146-
vv_threshold: null,
147-
vh_threshold: null,
148-
vv_vh_diff: null,
108+
start_date: null,
149109
slope_max: null,
150110
min_area_pixels: null,
151-
texture_window: null,
152111
})}
153112
>
154-
Reset All to Auto
113+
Reset All to Defaults
155114
</button>
156115
</div>
157116
)}

0 commit comments

Comments
 (0)