Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -251,60 +251,59 @@ def aggregate_data_yearly(collection):
|
|
251 |
# return 0
|
252 |
# return ee.Number(cloudy_pixels).divide(ee.Number(total_pixels)).multiply(100)
|
253 |
|
254 |
-
def
|
255 |
-
|
256 |
-
|
|
|
257 |
qa60 = image.select('QA60')
|
258 |
-
|
259 |
-
# Identify opaque and cirrus clouds
|
260 |
opaque_clouds = qa60.bitwiseAnd(1 << 10)
|
261 |
cirrus_clouds = qa60.bitwiseAnd(1 << 11)
|
262 |
cloud_mask = opaque_clouds.Or(cirrus_clouds)
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
collection_with_clouds = collection.map(calculate_cloud_percentage)
|
287 |
-
|
288 |
-
# Filter out images with cloud percentage exceeding the threshold
|
289 |
-
filtered_collection = collection_with_clouds.filter(ee.Filter.lt('cloud_percentage', max_cloud_percentage))
|
290 |
|
291 |
-
return filtered_collection
|
292 |
-
|
293 |
-
# Preprocessing function
|
294 |
def preprocess_collection(collection, pixel_cloud_threshold):
|
295 |
def mask_cloudy_pixels(image):
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
300 |
clear_pixels = cloud_mask.Not()
|
301 |
return image.updateMask(clear_pixels)
|
302 |
-
|
303 |
if pixel_cloud_threshold > 0:
|
304 |
return collection.map(mask_cloudy_pixels)
|
305 |
return collection
|
306 |
|
307 |
-
# Process single geometry
|
308 |
# Process single geometry
|
309 |
def process_single_geometry(row, start_date_str, end_date_str, dataset_id, selected_bands, reducer_choice, shape_type, aggregation_period, custom_formula, original_lat_col, original_lon_col, kernel_size=None, include_boundary=None, user_scale=None, pixel_cloud_threshold=0):
|
310 |
if shape_type.lower() == "point":
|
@@ -423,10 +422,14 @@ def process_aggregation(locations_df, start_date_str, end_date_str, dataset_id,
|
|
423 |
|
424 |
st.write(f"Original Collection Size: {raw_collection.size().getInfo()}")
|
425 |
|
426 |
-
# Apply cloud filtering
|
427 |
if pixel_cloud_threshold > 0:
|
428 |
-
|
429 |
-
|
|
|
|
|
|
|
|
|
430 |
|
431 |
# Use ThreadPoolExecutor to process each geometry
|
432 |
with ThreadPoolExecutor(max_workers=10) as executor:
|
|
|
251 |
# return 0
|
252 |
# return ee.Number(cloudy_pixels).divide(ee.Number(total_pixels)).multiply(100)
|
253 |
|
254 |
+
def calculate_cloud_percentage(image):
|
255 |
+
# Check if QA60 band exists (Level-1C)
|
256 |
+
bands = image.bandNames().getInfo()
|
257 |
+
if 'QA60' in bands:
|
258 |
qa60 = image.select('QA60')
|
|
|
|
|
259 |
opaque_clouds = qa60.bitwiseAnd(1 << 10)
|
260 |
cirrus_clouds = qa60.bitwiseAnd(1 << 11)
|
261 |
cloud_mask = opaque_clouds.Or(cirrus_clouds)
|
262 |
+
elif 'SCL' in bands: # Check if SCL band exists (Level-2A)
|
263 |
+
scl = image.select('SCL')
|
264 |
+
cloud_mask = scl.eq(8).Or(scl.eq(9)).Or(scl.eq(10)) # Cloud, cirrus, snow/ice
|
265 |
+
else:
|
266 |
+
raise ValueError("Cloud masking bands (QA60 or SCL) not found in the dataset.")
|
267 |
+
|
268 |
+
total_pixels = cloud_mask.reduceRegion(
|
269 |
+
reducer=ee.Reducer.count(),
|
270 |
+
geometry=image.geometry(),
|
271 |
+
scale=60,
|
272 |
+
maxPixels=1e13
|
273 |
+
).get('constant') # Use 'constant' for renamed bands
|
274 |
+
|
275 |
+
cloudy_pixels = cloud_mask.reduceRegion(
|
276 |
+
reducer=ee.Reducer.sum(),
|
277 |
+
geometry=image.geometry(),
|
278 |
+
scale=60,
|
279 |
+
maxPixels=1e13
|
280 |
+
).get('constant')
|
281 |
+
|
282 |
+
if total_pixels == 0:
|
283 |
+
return 0
|
284 |
+
return ee.Number(cloudy_pixels).divide(ee.Number(total_pixels)).multiply(100)
|
|
|
|
|
|
|
|
|
285 |
|
|
|
|
|
|
|
286 |
def preprocess_collection(collection, pixel_cloud_threshold):
|
287 |
def mask_cloudy_pixels(image):
|
288 |
+
bands = image.bandNames().getInfo()
|
289 |
+
if 'QA60' in bands: # Level-1C
|
290 |
+
qa60 = image.select('QA60')
|
291 |
+
opaque_clouds = qa60.bitwiseAnd(1 << 10)
|
292 |
+
cirrus_clouds = qa60.bitwiseAnd(1 << 11)
|
293 |
+
cloud_mask = opaque_clouds.Or(cirrus_clouds)
|
294 |
+
elif 'SCL' in bands: # Level-2A
|
295 |
+
scl = image.select('SCL')
|
296 |
+
cloud_mask = scl.eq(8).Or(scl.eq(9)).Or(scl.eq(10)) # Cloud, cirrus, snow/ice
|
297 |
+
else:
|
298 |
+
raise ValueError("Cloud masking bands (QA60 or SCL) not found in the dataset.")
|
299 |
+
|
300 |
clear_pixels = cloud_mask.Not()
|
301 |
return image.updateMask(clear_pixels)
|
302 |
+
|
303 |
if pixel_cloud_threshold > 0:
|
304 |
return collection.map(mask_cloudy_pixels)
|
305 |
return collection
|
306 |
|
|
|
307 |
# Process single geometry
|
308 |
def process_single_geometry(row, start_date_str, end_date_str, dataset_id, selected_bands, reducer_choice, shape_type, aggregation_period, custom_formula, original_lat_col, original_lon_col, kernel_size=None, include_boundary=None, user_scale=None, pixel_cloud_threshold=0):
|
309 |
if shape_type.lower() == "point":
|
|
|
422 |
|
423 |
st.write(f"Original Collection Size: {raw_collection.size().getInfo()}")
|
424 |
|
425 |
+
# Apply cloud filtering if applicable
|
426 |
if pixel_cloud_threshold > 0:
|
427 |
+
try:
|
428 |
+
raw_collection = preprocess_collection(raw_collection, pixel_cloud_threshold)
|
429 |
+
st.write(f"Filtered Collection Size (After Cloud Masking): {raw_collection.size().getInfo()}")
|
430 |
+
except Exception as e:
|
431 |
+
st.error(f"Cloud masking failed: {str(e)}")
|
432 |
+
st.stop()
|
433 |
|
434 |
# Use ThreadPoolExecutor to process each geometry
|
435 |
with ThreadPoolExecutor(max_workers=10) as executor:
|