RadGEEToolbox 1.7.3__py3-none-any.whl → 1.7.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- RadGEEToolbox/CollectionStitch.py +16 -3
- RadGEEToolbox/Export.py +16 -0
- RadGEEToolbox/GenericCollection.py +130 -34
- RadGEEToolbox/LandsatCollection.py +249 -50
- RadGEEToolbox/Sentinel1Collection.py +179 -37
- RadGEEToolbox/Sentinel2Collection.py +202 -51
- RadGEEToolbox/__init__.py +4 -4
- {radgeetoolbox-1.7.3.dist-info → radgeetoolbox-1.7.4.dist-info}/METADATA +6 -6
- radgeetoolbox-1.7.4.dist-info/RECORD +14 -0
- radgeetoolbox-1.7.3.dist-info/RECORD +0 -14
- {radgeetoolbox-1.7.3.dist-info → radgeetoolbox-1.7.4.dist-info}/WHEEL +0 -0
- {radgeetoolbox-1.7.3.dist-info → radgeetoolbox-1.7.4.dist-info}/licenses/LICENSE.txt +0 -0
- {radgeetoolbox-1.7.3.dist-info → radgeetoolbox-1.7.4.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,7 @@ import ee
|
|
|
2
2
|
import math
|
|
3
3
|
import pandas as pd
|
|
4
4
|
import numpy as np
|
|
5
|
+
import warnings
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class Sentinel1Collection:
|
|
@@ -230,6 +231,14 @@ class Sentinel1Collection:
|
|
|
230
231
|
self._DbFromSigma0 = None
|
|
231
232
|
self._multilook = None
|
|
232
233
|
|
|
234
|
+
def __call__(self):
|
|
235
|
+
"""
|
|
236
|
+
Allows the object to be called as a function, returning itself.
|
|
237
|
+
This enables property-like methods to be accessed with or without parentheses
|
|
238
|
+
(e.g., .mosaicByDate or .mosaicByDate()).
|
|
239
|
+
"""
|
|
240
|
+
return self
|
|
241
|
+
|
|
233
242
|
@staticmethod
|
|
234
243
|
def image_dater(image):
|
|
235
244
|
"""
|
|
@@ -245,7 +254,7 @@ class Sentinel1Collection:
|
|
|
245
254
|
return image.set({"Date_Filter": date})
|
|
246
255
|
|
|
247
256
|
@staticmethod
|
|
248
|
-
def
|
|
257
|
+
def pixelAreaSum(
|
|
249
258
|
image, band_name, geometry, threshold=-1, scale=10, maxPixels=1e12
|
|
250
259
|
):
|
|
251
260
|
"""
|
|
@@ -304,8 +313,26 @@ class Sentinel1Collection:
|
|
|
304
313
|
# Call to iterate the calculate_and_set_area function over the list of bands, starting with the original image
|
|
305
314
|
final_image = ee.Image(bands.iterate(calculate_and_set_area, image))
|
|
306
315
|
return final_image
|
|
316
|
+
|
|
317
|
+
@staticmethod
|
|
318
|
+
def PixelAreaSum(
|
|
319
|
+
image, band_name, geometry, threshold=-1, scale=10, maxPixels=1e12
|
|
320
|
+
):
|
|
321
|
+
warnings.warn(
|
|
322
|
+
"The 'PixelAreaSum' method is deprecated. Please use 'pixelAreaSum' instead.",
|
|
323
|
+
DeprecationWarning,
|
|
324
|
+
stacklevel=2
|
|
325
|
+
)
|
|
326
|
+
return Sentinel1Collection.pixelAreaSum(
|
|
327
|
+
image=image,
|
|
328
|
+
band_name=band_name,
|
|
329
|
+
geometry=geometry,
|
|
330
|
+
threshold=threshold,
|
|
331
|
+
scale=scale,
|
|
332
|
+
maxPixels=maxPixels,
|
|
333
|
+
)
|
|
307
334
|
|
|
308
|
-
def
|
|
335
|
+
def pixelAreaSumCollection(
|
|
309
336
|
self, band_name, geometry, threshold=-1, scale=10, maxPixels=1e12, output_type='ImageCollection', area_data_export_path=None
|
|
310
337
|
):
|
|
311
338
|
"""
|
|
@@ -332,7 +359,7 @@ class Sentinel1Collection:
|
|
|
332
359
|
collection = self.collection
|
|
333
360
|
# Area calculation for each image in the collection, using the PixelAreaSum function
|
|
334
361
|
AreaCollection = collection.map(
|
|
335
|
-
lambda image: Sentinel1Collection.
|
|
362
|
+
lambda image: Sentinel1Collection.pixelAreaSum(
|
|
336
363
|
image,
|
|
337
364
|
band_name=band_name,
|
|
338
365
|
geometry=geometry,
|
|
@@ -348,17 +375,35 @@ class Sentinel1Collection:
|
|
|
348
375
|
|
|
349
376
|
# If an export path is provided, the area data will be exported to a CSV file
|
|
350
377
|
if area_data_export_path:
|
|
351
|
-
Sentinel1Collection(collection=self._PixelAreaSumCollection).
|
|
378
|
+
Sentinel1Collection(collection=self._PixelAreaSumCollection).exportProperties(property_names=prop_names, file_path=area_data_export_path+'.csv')
|
|
352
379
|
# Returning the result in the desired format based on output_type argument or raising an error for invalid input
|
|
353
380
|
if output_type == 'ImageCollection' or output_type == 'ee.ImageCollection':
|
|
354
381
|
return self._PixelAreaSumCollection
|
|
355
382
|
elif output_type == 'Sentinel1Collection':
|
|
356
383
|
return Sentinel1Collection(collection=self._PixelAreaSumCollection)
|
|
357
384
|
elif output_type == 'DataFrame' or output_type == 'Pandas' or output_type == 'pd' or output_type == 'dataframe' or output_type == 'df':
|
|
358
|
-
return Sentinel1Collection(collection=self._PixelAreaSumCollection).
|
|
385
|
+
return Sentinel1Collection(collection=self._PixelAreaSumCollection).exportProperties(property_names=prop_names)
|
|
359
386
|
else:
|
|
360
387
|
raise ValueError("Incorrect `output_type`. The `output_type` argument must be one of the following: 'ImageCollection', 'ee.ImageCollection', 'Sentinel1Collection', 'DataFrame', 'Pandas', 'pd', 'dataframe', or 'df'.")
|
|
361
388
|
|
|
389
|
+
def PixelAreaSumCollection(
|
|
390
|
+
self, band_name, geometry, threshold=-1, scale=10, maxPixels=1e12, output_type='ImageCollection', area_data_export_path=None
|
|
391
|
+
):
|
|
392
|
+
warnings.warn(
|
|
393
|
+
"The 'PixelAreaSumCollection' method is deprecated. Please use 'pixelAreaSumCollection' instead.",
|
|
394
|
+
DeprecationWarning,
|
|
395
|
+
stacklevel=2
|
|
396
|
+
)
|
|
397
|
+
return self.pixelAreaSumCollection(
|
|
398
|
+
band_name=band_name,
|
|
399
|
+
geometry=geometry,
|
|
400
|
+
threshold=threshold,
|
|
401
|
+
scale=scale,
|
|
402
|
+
maxPixels=maxPixels,
|
|
403
|
+
output_type=output_type,
|
|
404
|
+
area_data_export_path=area_data_export_path
|
|
405
|
+
)
|
|
406
|
+
|
|
362
407
|
@staticmethod
|
|
363
408
|
def add_month_property_fn(image):
|
|
364
409
|
"""
|
|
@@ -707,7 +752,7 @@ class Sentinel1Collection:
|
|
|
707
752
|
return Sentinel1Collection(collection=self._speckle_filter)
|
|
708
753
|
|
|
709
754
|
@property
|
|
710
|
-
def
|
|
755
|
+
def sigma0FromDb(self):
|
|
711
756
|
"""
|
|
712
757
|
Property attribute function to convert image collection from decibels to sigma0. Results are calculated once per class object then cached for future use.
|
|
713
758
|
|
|
@@ -732,9 +777,18 @@ class Sentinel1Collection:
|
|
|
732
777
|
sigma0_collection = collection.map(conversion)
|
|
733
778
|
self._Sigma0FromDb = sigma0_collection
|
|
734
779
|
return Sentinel1Collection(collection=self._Sigma0FromDb)
|
|
780
|
+
|
|
781
|
+
@property
|
|
782
|
+
def Sigma0FromDb(self):
|
|
783
|
+
warnings.warn(
|
|
784
|
+
"The 'Sigma0FromDb' property is deprecated. Please use 'sigma0FromDb' instead.",
|
|
785
|
+
DeprecationWarning,
|
|
786
|
+
stacklevel=2
|
|
787
|
+
)
|
|
788
|
+
return self.sigma0FromDb
|
|
735
789
|
|
|
736
790
|
@property
|
|
737
|
-
def
|
|
791
|
+
def dbFromSigma0(self):
|
|
738
792
|
"""
|
|
739
793
|
Property attribute function to convert image collection from decibels to sigma0. Results are calculated once per class object then cached for future use.
|
|
740
794
|
|
|
@@ -760,6 +814,15 @@ class Sentinel1Collection:
|
|
|
760
814
|
self._DbFromSigma0 = dB_collection
|
|
761
815
|
return Sentinel1Collection(collection=self._DbFromSigma0)
|
|
762
816
|
|
|
817
|
+
@property
|
|
818
|
+
def DbFromSigma0(self):
|
|
819
|
+
warnings.warn(
|
|
820
|
+
"The 'DbFromSigma0' property is deprecated. Please use 'dbFromSigma0' instead.",
|
|
821
|
+
DeprecationWarning,
|
|
822
|
+
stacklevel=2
|
|
823
|
+
)
|
|
824
|
+
return self.dbFromSigma0
|
|
825
|
+
|
|
763
826
|
@staticmethod
|
|
764
827
|
def anomaly_fn(image, geometry, band_name=None, anomaly_band_name=None, replace=True, scale=10):
|
|
765
828
|
"""
|
|
@@ -847,7 +910,7 @@ class Sentinel1Collection:
|
|
|
847
910
|
self._dates = dates
|
|
848
911
|
return self._dates
|
|
849
912
|
|
|
850
|
-
def
|
|
913
|
+
def exportProperties(self, property_names, file_path=None):
|
|
851
914
|
"""
|
|
852
915
|
Fetches and returns specified properties from each image in the collection as a list, and returns a pandas DataFrame and optionally saves the results to a csv file.
|
|
853
916
|
|
|
@@ -902,6 +965,14 @@ class Sentinel1Collection:
|
|
|
902
965
|
print(f"Properties saved to {file_path}")
|
|
903
966
|
|
|
904
967
|
return df
|
|
968
|
+
|
|
969
|
+
def ExportProperties(self, property_names, file_path=None):
|
|
970
|
+
warnings.warn(
|
|
971
|
+
"The 'ExportProperties' method is deprecated. Please use 'exportProperties' instead.",
|
|
972
|
+
DeprecationWarning,
|
|
973
|
+
stacklevel=2
|
|
974
|
+
)
|
|
975
|
+
return self.exportProperties(property_names=property_names, file_path=file_path)
|
|
905
976
|
|
|
906
977
|
def get_filtered_collection(self):
|
|
907
978
|
"""
|
|
@@ -1966,6 +2037,9 @@ class Sentinel1Collection:
|
|
|
1966
2037
|
|
|
1967
2038
|
if geometry is not None and not isinstance(geometry, ee.Geometry):
|
|
1968
2039
|
raise ValueError(f'The chosen `geometry`: {geometry} is not a valid ee.Geometry object.')
|
|
2040
|
+
|
|
2041
|
+
native_projection = image_collection.first().select(target_band).projection()
|
|
2042
|
+
|
|
1969
2043
|
# define the join, which will join all images newer than the current image
|
|
1970
2044
|
# use system:time_start if the image does not have a Date_Filter property
|
|
1971
2045
|
if join_method == 'system:time_start':
|
|
@@ -2021,7 +2095,7 @@ class Sentinel1Collection:
|
|
|
2021
2095
|
# convert the image collection to an image of s_statistic values per pixel
|
|
2022
2096
|
# where the s_statistic is the sum of partial s values
|
|
2023
2097
|
# renaming the band as 's_statistic' for later usage
|
|
2024
|
-
final_s_image = partial_s_col.sum().rename('s_statistic')
|
|
2098
|
+
final_s_image = partial_s_col.sum().rename('s_statistic').setDefaultProjection(native_projection)
|
|
2025
2099
|
|
|
2026
2100
|
|
|
2027
2101
|
########## PART 2 - VARIANCE and Z-SCORE ##########
|
|
@@ -2084,7 +2158,7 @@ class Sentinel1Collection:
|
|
|
2084
2158
|
mask = ee.Image(1).clip(geometry)
|
|
2085
2159
|
final_image = final_image.updateMask(mask)
|
|
2086
2160
|
|
|
2087
|
-
return final_image
|
|
2161
|
+
return final_image.setDefaultProjection(native_projection)
|
|
2088
2162
|
|
|
2089
2163
|
def sens_slope_trend(self, target_band=None, join_method='system:time_start', geometry=None):
|
|
2090
2164
|
"""
|
|
@@ -2120,6 +2194,8 @@ class Sentinel1Collection:
|
|
|
2120
2194
|
if geometry is not None and not isinstance(geometry, ee.Geometry):
|
|
2121
2195
|
raise ValueError(f'The chosen `geometry`: {geometry} is not a valid ee.Geometry object.')
|
|
2122
2196
|
|
|
2197
|
+
native_projection = image_collection.first().select(target_band).projection()
|
|
2198
|
+
|
|
2123
2199
|
# Add Year Band (Time X-Axis)
|
|
2124
2200
|
def add_year_band(image):
|
|
2125
2201
|
# Handle user-defined date strings vs system time
|
|
@@ -2147,7 +2223,7 @@ class Sentinel1Collection:
|
|
|
2147
2223
|
mask = ee.Image(1).clip(geometry)
|
|
2148
2224
|
slope_band = slope_band.updateMask(mask)
|
|
2149
2225
|
|
|
2150
|
-
return slope_band
|
|
2226
|
+
return slope_band.setDefaultProjection(native_projection)
|
|
2151
2227
|
|
|
2152
2228
|
|
|
2153
2229
|
def mask_to_polygon(self, polygon):
|
|
@@ -2161,20 +2237,15 @@ class Sentinel1Collection:
|
|
|
2161
2237
|
Sentinel1Collection: masked Sentinel1Collection image collection
|
|
2162
2238
|
|
|
2163
2239
|
"""
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
mask = ee.Image.constant(1).clip(polygon)
|
|
2240
|
+
# Convert the polygon to a mask
|
|
2241
|
+
mask = ee.Image.constant(1).clip(polygon)
|
|
2167
2242
|
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
# Update the internal collection state
|
|
2172
|
-
self._geometry_masked_collection = Sentinel1Collection(
|
|
2173
|
-
collection=masked_collection
|
|
2174
|
-
)
|
|
2243
|
+
# Update the mask of each image in the collection
|
|
2244
|
+
masked_collection = self.collection.map(lambda img: img.updateMask(mask)\
|
|
2245
|
+
.copyProperties(img).set('system:time_start', img.get('system:time_start')))
|
|
2175
2246
|
|
|
2176
2247
|
# Return the updated object
|
|
2177
|
-
return
|
|
2248
|
+
return Sentinel1Collection(collection=masked_collection)
|
|
2178
2249
|
|
|
2179
2250
|
def mask_out_polygon(self, polygon):
|
|
2180
2251
|
"""
|
|
@@ -2187,23 +2258,18 @@ class Sentinel1Collection:
|
|
|
2187
2258
|
Sentinel1Collection: masked Sentinel1Collection image collection
|
|
2188
2259
|
|
|
2189
2260
|
"""
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
full_mask = ee.Image.constant(1)
|
|
2261
|
+
# Convert the polygon to a mask
|
|
2262
|
+
full_mask = ee.Image.constant(1)
|
|
2193
2263
|
|
|
2194
|
-
|
|
2195
|
-
|
|
2264
|
+
# Use paint to set pixels inside polygon as 0
|
|
2265
|
+
area = full_mask.paint(polygon, 0)
|
|
2196
2266
|
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
# Update the internal collection state
|
|
2201
|
-
self._geometry_masked_out_collection = Sentinel1Collection(
|
|
2202
|
-
collection=masked_collection
|
|
2203
|
-
)
|
|
2267
|
+
# Update the mask of each image in the collection
|
|
2268
|
+
masked_collection = self.collection.map(lambda img: img.updateMask(area)\
|
|
2269
|
+
.copyProperties(img).set('system:time_start', img.get('system:time_start')))
|
|
2204
2270
|
|
|
2205
2271
|
# Return the updated object
|
|
2206
|
-
return
|
|
2272
|
+
return Sentinel1Collection(collection=masked_collection)
|
|
2207
2273
|
|
|
2208
2274
|
def image_grab(self, img_selector):
|
|
2209
2275
|
"""
|
|
@@ -2255,7 +2321,7 @@ class Sentinel1Collection:
|
|
|
2255
2321
|
new_col = self.collection.filter(ee.Filter.eq("Date_Filter", img_date))
|
|
2256
2322
|
return new_col.first()
|
|
2257
2323
|
|
|
2258
|
-
def
|
|
2324
|
+
def collectionStitch(self, img_col2):
|
|
2259
2325
|
"""
|
|
2260
2326
|
Function to mosaic two Sentinel1Collection objects which share image dates.
|
|
2261
2327
|
Mosaics are only formed for dates where both image collections have images.
|
|
@@ -2307,9 +2373,17 @@ class Sentinel1Collection:
|
|
|
2307
2373
|
|
|
2308
2374
|
# Return a Sentinel1Collection instance
|
|
2309
2375
|
return Sentinel1Collection(collection=new_col)
|
|
2376
|
+
|
|
2377
|
+
def CollectionStitch(self, img_col2):
|
|
2378
|
+
warnings.warn(
|
|
2379
|
+
"The 'CollectionStitch' method is deprecated. Please use 'collectionStitch' instead.",
|
|
2380
|
+
DeprecationWarning,
|
|
2381
|
+
stacklevel=2
|
|
2382
|
+
)
|
|
2383
|
+
return self.collectionStitch(img_col2)
|
|
2310
2384
|
|
|
2311
2385
|
@property
|
|
2312
|
-
def
|
|
2386
|
+
def mosaicByDateDepr(self):
|
|
2313
2387
|
"""
|
|
2314
2388
|
Property attribute function to mosaic collection images that share the same date.
|
|
2315
2389
|
The property CLOUD_COVER for each image is used to calculate an overall mean,
|
|
@@ -2370,6 +2444,74 @@ class Sentinel1Collection:
|
|
|
2370
2444
|
|
|
2371
2445
|
# Convert the list of mosaics to an ImageCollection
|
|
2372
2446
|
return self._MosaicByDate
|
|
2447
|
+
|
|
2448
|
+
@property
|
|
2449
|
+
def mosaicByDate(self):
|
|
2450
|
+
"""
|
|
2451
|
+
Property attribute function to mosaic collection images that share the same date.
|
|
2452
|
+
|
|
2453
|
+
The property CLOUD_COVER for each image is used to calculate an overall mean,
|
|
2454
|
+
which replaces the CLOUD_COVER property for each mosaiced image.
|
|
2455
|
+
Server-side friendly.
|
|
2456
|
+
|
|
2457
|
+
NOTE: if images are removed from the collection from cloud filtering, you may have mosaics composed of only one image.
|
|
2458
|
+
|
|
2459
|
+
Returns:
|
|
2460
|
+
LandsatCollection: LandsatCollection image collection with mosaiced imagery and mean CLOUD_COVER as a property
|
|
2461
|
+
"""
|
|
2462
|
+
if self._MosaicByDate is None:
|
|
2463
|
+
distinct_dates = self.collection.distinct("Date_Filter")
|
|
2464
|
+
|
|
2465
|
+
# Define a join to link images by Date_Filter
|
|
2466
|
+
filter_date = ee.Filter.equals(leftField="Date_Filter", rightField="Date_Filter")
|
|
2467
|
+
join = ee.Join.saveAll(matchesKey="date_matches")
|
|
2468
|
+
|
|
2469
|
+
# Apply the join
|
|
2470
|
+
# Primary: Distinct dates collection
|
|
2471
|
+
# Secondary: The full original collection
|
|
2472
|
+
joined_col = ee.ImageCollection(join.apply(distinct_dates, self.collection, filter_date))
|
|
2473
|
+
|
|
2474
|
+
# Define the mosaicking function
|
|
2475
|
+
def _mosaic_day(img):
|
|
2476
|
+
# Recover the list of images for this day
|
|
2477
|
+
daily_list = ee.List(img.get("date_matches"))
|
|
2478
|
+
daily_col = ee.ImageCollection.fromImages(daily_list)
|
|
2479
|
+
|
|
2480
|
+
# Create the mosaic
|
|
2481
|
+
mosaic = daily_col.mosaic().setDefaultProjection(img.projection())
|
|
2482
|
+
|
|
2483
|
+
# Properties to preserve from the representative image
|
|
2484
|
+
props_of_interest = [
|
|
2485
|
+
"platform_number",
|
|
2486
|
+
"instrument",
|
|
2487
|
+
"instrumentMode",
|
|
2488
|
+
"orbitNumber_start",
|
|
2489
|
+
"orbitNumber_stop",
|
|
2490
|
+
"orbitProperties_pass",
|
|
2491
|
+
"resolution_meters",
|
|
2492
|
+
"transmitterReceiverPolarisation",
|
|
2493
|
+
"system:time_start",
|
|
2494
|
+
"crs"
|
|
2495
|
+
]
|
|
2496
|
+
|
|
2497
|
+
# Return mosaic with properties set
|
|
2498
|
+
return mosaic.copyProperties(img, props_of_interest)
|
|
2499
|
+
|
|
2500
|
+
# 5. Map the function and wrap the result
|
|
2501
|
+
mosaiced_col = joined_col.map(_mosaic_day)
|
|
2502
|
+
self._MosaicByDate = Sentinel1Collection(collection=mosaiced_col)
|
|
2503
|
+
|
|
2504
|
+
# Convert the list of mosaics to an ImageCollection
|
|
2505
|
+
return self._MosaicByDate
|
|
2506
|
+
|
|
2507
|
+
@property
|
|
2508
|
+
def MosaicByDate(self):
|
|
2509
|
+
warnings.warn(
|
|
2510
|
+
"The 'MosaicByDate' property is deprecated. Please use 'mosaicByDate' instead.",
|
|
2511
|
+
DeprecationWarning,
|
|
2512
|
+
stacklevel=2
|
|
2513
|
+
)
|
|
2514
|
+
return self.mosaicByDate
|
|
2373
2515
|
|
|
2374
2516
|
@staticmethod
|
|
2375
2517
|
def ee_to_df(
|