eotdl 2025.4.22.post2__py3-none-any.whl → 2025.5.26__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.
- eotdl/__init__.py +1 -1
- eotdl/cli.py +2 -1
- eotdl/commands/auth.py +5 -2
- eotdl/commands/datasets.py +16 -10
- eotdl/commands/models.py +8 -9
- eotdl/commands/pipelines.py +132 -0
- eotdl/datasets/__init__.py +1 -1
- eotdl/datasets/ingest.py +18 -7
- eotdl/datasets/retrieve.py +16 -2
- eotdl/datasets/stage.py +1 -1
- eotdl/datasets/update.py +6 -4
- eotdl/fe/__init__.py +4 -0
- eotdl/fe/ingest.py +49 -0
- eotdl/fe/openeo/__init__.py +2 -0
- eotdl/fe/openeo/advanced_patch_extraction.py +124 -0
- eotdl/fe/openeo/basic_point_extraction.py +86 -0
- eotdl/fe/openeo/dataframe_utils.py +230 -0
- eotdl/fe/openeo/s3proxy_utils.py +180 -0
- eotdl/fe/openeo/spatial_utils.py +28 -0
- eotdl/fe/openeo/temporal_utils.py +16 -0
- eotdl/fe/retrieve.py +18 -0
- eotdl/fe/stage.py +63 -0
- eotdl/fe/update.py +12 -0
- eotdl/files/__init__.py +1 -0
- eotdl/files/get_url.py +18 -0
- eotdl/files/ingest.py +4 -4
- eotdl/files/metadata.py +2 -1
- eotdl/models/ingest.py +3 -2
- eotdl/models/update.py +6 -4
- eotdl/repos/DatasetsAPIRepo.py +15 -3
- eotdl/repos/FEAPIRepo.py +50 -0
- eotdl/repos/FilesAPIRepo.py +0 -1
- eotdl/repos/ModelsAPIRepo.py +3 -2
- eotdl/repos/__init__.py +2 -1
- eotdl/tools/ais_labelling.py +273 -0
- {eotdl-2025.4.22.post2.dist-info → eotdl-2025.5.26.dist-info}/METADATA +1 -1
- {eotdl-2025.4.22.post2.dist-info → eotdl-2025.5.26.dist-info}/RECORD +39 -23
- {eotdl-2025.4.22.post2.dist-info → eotdl-2025.5.26.dist-info}/WHEEL +0 -0
- {eotdl-2025.4.22.post2.dist-info → eotdl-2025.5.26.dist-info}/entry_points.txt +0 -0
eotdl/files/metadata.py
CHANGED
@@ -35,7 +35,8 @@ class Metadata(BaseModel):
|
|
35
35
|
f.write(f"name: {self.name}\n")
|
36
36
|
f.write(f"license: {self.license}\n")
|
37
37
|
f.write(f"source: {self.source}\n")
|
38
|
-
|
38
|
+
if self.thumbnail:
|
39
|
+
f.write(f"thumbnail: {self.thumbnail}\n")
|
39
40
|
f.write(f"authors:\n")
|
40
41
|
for author in self.authors:
|
41
42
|
f.write(f" - {author}\n")
|
eotdl/models/ingest.py
CHANGED
@@ -3,7 +3,7 @@ from pathlib import Path
|
|
3
3
|
from ..repos import ModelsAPIRepo
|
4
4
|
from ..files.ingest import prep_ingest_stac, prep_ingest_folder, ingest, ingest_virtual, ingest_catalog
|
5
5
|
|
6
|
-
def retrieve_model(metadata, user):
|
6
|
+
def retrieve_model(metadata, user, private=False):
|
7
7
|
repo = ModelsAPIRepo()
|
8
8
|
data, error = repo.retrieve_model(metadata.name)
|
9
9
|
# print(data, error)
|
@@ -22,6 +22,7 @@ def ingest_model(
|
|
22
22
|
logger=print,
|
23
23
|
force_metadata_update=False,
|
24
24
|
sync_metadata=False,
|
25
|
+
private=False,
|
25
26
|
):
|
26
27
|
path = Path(path)
|
27
28
|
if not path.is_dir():
|
@@ -30,7 +31,7 @@ def ingest_model(
|
|
30
31
|
prep_ingest_stac(path, logger)
|
31
32
|
else:
|
32
33
|
prep_ingest_folder(path, verbose, logger, force_metadata_update, sync_metadata)
|
33
|
-
return ingest(path, ModelsAPIRepo(), retrieve_model, 'models')
|
34
|
+
return ingest(path, ModelsAPIRepo(), retrieve_model, 'models', private)
|
34
35
|
|
35
36
|
def ingest_virtual_model( # could work for a list of paths with minimal changes...
|
36
37
|
path,
|
eotdl/models/update.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from ..repos import ModelsAPIRepo
|
2
|
-
|
3
|
-
|
2
|
+
from ..auth import with_auth
|
3
|
+
from .retrieve import retrieve_model
|
4
4
|
def update_model(model_id, metadata, content, user):
|
5
5
|
repo = ModelsAPIRepo()
|
6
6
|
data, error = repo.update_model(
|
@@ -16,9 +16,11 @@ def update_model(model_id, metadata, content, user):
|
|
16
16
|
raise Exception(error)
|
17
17
|
return data
|
18
18
|
|
19
|
-
|
19
|
+
@with_auth
|
20
|
+
def deactivate_model(model_name, user):
|
21
|
+
model = retrieve_model(model_name)
|
20
22
|
repo = ModelsAPIRepo()
|
21
|
-
data, error = repo.deactivate_model(
|
23
|
+
data, error = repo.deactivate_model(model['id'], user)
|
22
24
|
if error:
|
23
25
|
raise Exception(error)
|
24
26
|
return data
|
eotdl/repos/DatasetsAPIRepo.py
CHANGED
@@ -18,15 +18,26 @@ class DatasetsAPIRepo(APIRepo):
|
|
18
18
|
response = requests.get(url)
|
19
19
|
return self.format_response(response)
|
20
20
|
|
21
|
+
def retrieve_private_datasets(self, user):
|
22
|
+
url = self.url + "datasets/private"
|
23
|
+
response = requests.get(url, headers=self.generate_headers(user))
|
24
|
+
return self.format_response(response)
|
25
|
+
|
21
26
|
def retrieve_dataset(self, name):
|
22
27
|
response = requests.get(self.url + "datasets?name=" + name)
|
23
28
|
return self.format_response(response)
|
24
29
|
|
30
|
+
def retrieve_private_dataset(self, name, user):
|
31
|
+
response = requests.get(self.url + "datasets/private?name=" + name, headers=self.generate_headers(user))
|
32
|
+
return self.format_response(response)
|
33
|
+
|
25
34
|
def get_dataset_by_id(self, dataset_id):
|
26
35
|
response = requests.get(self.url + "datasets/" + dataset_id)
|
27
36
|
return self.format_response(response)
|
28
37
|
|
29
|
-
def create_dataset(self, metadata, user):
|
38
|
+
def create_dataset(self, metadata, user, private=False):
|
39
|
+
if private:
|
40
|
+
metadata["visibility"] = "private"
|
30
41
|
response = requests.post(
|
31
42
|
self.url + "datasets",
|
32
43
|
json=metadata,
|
@@ -42,8 +53,9 @@ class DatasetsAPIRepo(APIRepo):
|
|
42
53
|
)
|
43
54
|
return self.format_response(response)
|
44
55
|
|
45
|
-
def deactivate_dataset(self, dataset_name):
|
56
|
+
def deactivate_dataset(self, dataset_name, user):
|
46
57
|
response = requests.patch(
|
47
|
-
self.url + "datasets/deactivate/" + dataset_name
|
58
|
+
self.url + "datasets/deactivate/" + dataset_name,
|
59
|
+
headers=self.generate_headers(user),
|
48
60
|
)
|
49
61
|
return self.format_response(response)
|
eotdl/repos/FEAPIRepo.py
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
import requests
|
2
|
+
|
3
|
+
from ..repos import APIRepo
|
4
|
+
|
5
|
+
class FEAPIRepo(APIRepo):
|
6
|
+
def __init__(self, url=None):
|
7
|
+
super().__init__(url)
|
8
|
+
|
9
|
+
def retrieve_pipelines(self, name, limit):
|
10
|
+
url = self.url + "pipelines"
|
11
|
+
if name is not None:
|
12
|
+
url += "?match=" + name
|
13
|
+
if limit is not None:
|
14
|
+
if name is None:
|
15
|
+
url += "?limit=" + str(limit)
|
16
|
+
else:
|
17
|
+
url += "&limit=" + str(limit)
|
18
|
+
response = requests.get(url)
|
19
|
+
return self.format_response(response)
|
20
|
+
|
21
|
+
def retrieve_pipeline(self, name):
|
22
|
+
response = requests.get(self.url + "pipelines?name=" + name)
|
23
|
+
return self.format_response(response)
|
24
|
+
|
25
|
+
def get_pipeline_by_id(self, pipeline_id):
|
26
|
+
response = requests.get(self.url + "pipelines/" + pipeline_id)
|
27
|
+
return self.format_response(response)
|
28
|
+
|
29
|
+
def create_pipeline(self, metadata, user):
|
30
|
+
response = requests.post(
|
31
|
+
self.url + "pipelines",
|
32
|
+
json=metadata,
|
33
|
+
headers=self.generate_headers(user),
|
34
|
+
)
|
35
|
+
return self.format_response(response)
|
36
|
+
|
37
|
+
def complete_ingestion(self, pipeline_id, version, size, user):
|
38
|
+
response = requests.post(
|
39
|
+
self.url + "pipelines/complete/" + pipeline_id,
|
40
|
+
json={"version": version, "size": size},
|
41
|
+
headers=self.generate_headers(user),
|
42
|
+
)
|
43
|
+
return self.format_response(response)
|
44
|
+
|
45
|
+
def deactivate_pipeline(self, pipeline_id, user):
|
46
|
+
response = requests.patch(
|
47
|
+
self.url + "pipelines/deactivate/" + pipeline_id,
|
48
|
+
headers=self.generate_headers(user),
|
49
|
+
)
|
50
|
+
return self.format_response(response)
|
eotdl/repos/FilesAPIRepo.py
CHANGED
eotdl/repos/ModelsAPIRepo.py
CHANGED
@@ -38,8 +38,9 @@ class ModelsAPIRepo(APIRepo):
|
|
38
38
|
)
|
39
39
|
return self.format_response(response)
|
40
40
|
|
41
|
-
def deactivate_model(self, model_name):
|
41
|
+
def deactivate_model(self, model_name, user):
|
42
42
|
response = requests.patch(
|
43
|
-
self.url + "models/deactivate/" + model_name
|
43
|
+
self.url + "models/deactivate/" + model_name,
|
44
|
+
headers=self.generate_headers(user),
|
44
45
|
)
|
45
46
|
return self.format_response(response)
|
eotdl/repos/__init__.py
CHANGED
@@ -4,4 +4,5 @@ from .AuthAPIRepo import AuthAPIRepo
|
|
4
4
|
from .DatasetsAPIRepo import DatasetsAPIRepo
|
5
5
|
from .FilesAPIRepo import FilesAPIRepo
|
6
6
|
from .ModelsAPIRepo import ModelsAPIRepo
|
7
|
-
from .STACAPIRepo import STACAPIRepo
|
7
|
+
from .STACAPIRepo import STACAPIRepo
|
8
|
+
from .FEAPIRepo import FEAPIRepo
|
@@ -0,0 +1,273 @@
|
|
1
|
+
import json
|
2
|
+
import numpy as np
|
3
|
+
import pandas as pd
|
4
|
+
import rasterio
|
5
|
+
import rasterio.features
|
6
|
+
from scipy import signal
|
7
|
+
from shapely import affinity
|
8
|
+
from shapely.geometry import Polygon
|
9
|
+
from pathlib import Path
|
10
|
+
import geopandas as gpd
|
11
|
+
|
12
|
+
|
13
|
+
def convert_shape_to_wgs84(poly, transform):
|
14
|
+
a,b,c,d,e,f = transform[:6]
|
15
|
+
mat = (a,b,d,e,c,f)
|
16
|
+
return affinity.affine_transform(poly, mat)
|
17
|
+
|
18
|
+
def get_vessel_shape(center, width, length, theta):
|
19
|
+
""" Get the bounding box for a ship
|
20
|
+
Args:
|
21
|
+
center (float): Ship's center index (subpixel)
|
22
|
+
width (float): Ship's width in pixel
|
23
|
+
length (float): Ship's length in pixel
|
24
|
+
theta (float): Ship's heading angle in radian
|
25
|
+
Returns:
|
26
|
+
(Shapely Polygon): Bounding box
|
27
|
+
"""
|
28
|
+
width = width/2
|
29
|
+
length = length/2
|
30
|
+
poly = Polygon([(-width, -length), (-width, length), (width, length),
|
31
|
+
(width, -length)])
|
32
|
+
|
33
|
+
poly = affinity.rotate(poly, theta, 'center', use_radians=True)
|
34
|
+
poly = affinity.translate(poly, xoff=center[0], yoff=center[1])
|
35
|
+
return poly
|
36
|
+
|
37
|
+
|
38
|
+
def center_cross_correlation(data, width, length, theta, upsample_factor):
|
39
|
+
""" Approximate the center of the boat with a cross correlation of the data
|
40
|
+
and a gaussian model
|
41
|
+
Args:
|
42
|
+
data (Rasterio DatasetReader): tif file reader
|
43
|
+
width (float): Ship's width in pixel
|
44
|
+
length (float): Ship's length in pixel
|
45
|
+
theta (float): Ship's heading angle in radian
|
46
|
+
upsample_factor (uint): up sampling factor
|
47
|
+
Returns:
|
48
|
+
(Numpy Array): centered mask
|
49
|
+
(Numpy Array): Correlations with each bands of the image
|
50
|
+
(Numpy Array): Coordinates of the center of the boat
|
51
|
+
"""
|
52
|
+
# Up sampling
|
53
|
+
up_sampled_data = np.repeat(np.repeat(data, upsample_factor, axis=1),
|
54
|
+
upsample_factor, axis=0)
|
55
|
+
|
56
|
+
# Rectangular mask
|
57
|
+
size = (data.shape[0]*upsample_factor, data.shape[1]*upsample_factor)
|
58
|
+
shape = get_vessel_shape([size[0]/2, size[1]/2], width * upsample_factor, length*upsample_factor, theta)
|
59
|
+
centered_mask = rasterio.features.rasterize([shape], out_shape=(size), all_touched=True).astype(np.int8)
|
60
|
+
|
61
|
+
# Remove null edges of the mask
|
62
|
+
border_padding_size = 2 * upsample_factor
|
63
|
+
max_x = int(np.max(shape.exterior.coords.xy[1])) +3 + border_padding_size
|
64
|
+
min_x = int(np.min(shape.exterior.coords.xy[1])) -2 - border_padding_size
|
65
|
+
max_y = int(np.max(shape.exterior.coords.xy[0])) +3 + border_padding_size
|
66
|
+
min_y = int(np.min(shape.exterior.coords.xy[0])) -2 - border_padding_size
|
67
|
+
|
68
|
+
if (max_x - min_x)%2 == 0:
|
69
|
+
max_x += 1
|
70
|
+
if (max_y - min_y)%2 == 0:
|
71
|
+
max_y += 1
|
72
|
+
|
73
|
+
cropped_mask = centered_mask[min_x:max_x, min_y:max_y]
|
74
|
+
background_value = -1
|
75
|
+
|
76
|
+
####
|
77
|
+
background_value = 0
|
78
|
+
cropped_mask[cropped_mask == 0 ] = -1
|
79
|
+
####
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
model_mask = cropped_mask.copy()
|
84
|
+
model_mask[0:border_padding_size] = background_value
|
85
|
+
model_mask[-border_padding_size:] = background_value
|
86
|
+
model_mask[:,0:border_padding_size] = background_value
|
87
|
+
model_mask[:,-border_padding_size:] = background_value
|
88
|
+
for i in range(2,model_mask.shape[0]-2):
|
89
|
+
for j in range(2, model_mask.shape[1]-2):
|
90
|
+
window = cropped_mask[i-2:i+3,j-2:j+3]
|
91
|
+
if np.all(window != 1):
|
92
|
+
model_mask[i,j] = background_value
|
93
|
+
|
94
|
+
# Model and data must have the same dimensions parity to avoid an offset after the cross correlation
|
95
|
+
if model_mask.shape[0] %2 == 0:
|
96
|
+
model_mask = np.append(model_mask, -1* np.ones((1, model_mask.shape[1])), axis=0)
|
97
|
+
if model_mask.shape[1] %2 == 0:
|
98
|
+
model_mask = np.append(model_mask, -1* np.ones((model_mask.shape[0],1)), axis=1)
|
99
|
+
|
100
|
+
# Compute the coordinates of the maximum correlation for each band
|
101
|
+
mean_filter = np.ones(cropped_mask.shape)/np.size(cropped_mask)
|
102
|
+
correlations = np.zeros(up_sampled_data.shape)
|
103
|
+
for i in range(data.shape[2]):
|
104
|
+
correlation_band_i = signal.correlate2d(up_sampled_data[:, :, i],
|
105
|
+
model_mask, mode='valid', boundary='fill', fillvalue=0)
|
106
|
+
|
107
|
+
# Mean filter convolution (removes abnormal high values)
|
108
|
+
average_map = signal.convolve2d(up_sampled_data[:, :, i],
|
109
|
+
mean_filter, mode='valid', boundary='fill', fillvalue=np.inf)
|
110
|
+
correlation_band_i = np.divide(correlation_band_i, average_map,
|
111
|
+
out=np.zeros(correlation_band_i.shape), where=average_map!=0)
|
112
|
+
correlation_band_i -= np.min(correlation_band_i)
|
113
|
+
|
114
|
+
# resize the output
|
115
|
+
nb = correlations.shape[0]
|
116
|
+
na = correlation_band_i.shape[0]
|
117
|
+
lowerx = (nb) // 2 - (na // 2)
|
118
|
+
upperx = (nb // 2) + (na // 2)
|
119
|
+
nb = correlations.shape[1]
|
120
|
+
na = correlation_band_i.shape[1]
|
121
|
+
lowery = (nb) // 2 - (na // 2)
|
122
|
+
uppery = (nb // 2) + (na // 2)
|
123
|
+
correlations[lowerx:upperx, lowery:uppery,i] = correlation_band_i
|
124
|
+
|
125
|
+
|
126
|
+
window1d = np.abs(np.hamming(correlations.shape[0]))
|
127
|
+
window2d = np.sqrt(np.outer(window1d,window1d))
|
128
|
+
correlations *= np.repeat(window2d[:,:,None],correlations.shape[2],axis=2)
|
129
|
+
|
130
|
+
somme = np.sum(correlations, axis = 2)
|
131
|
+
|
132
|
+
##########################################################
|
133
|
+
|
134
|
+
|
135
|
+
|
136
|
+
center = np.argwhere(somme == np.max(somme))[0] / upsample_factor
|
137
|
+
|
138
|
+
# swap to the right coordinate system
|
139
|
+
center[0], center[1] = center[1], center[0]
|
140
|
+
|
141
|
+
return centered_mask, correlations, center
|
142
|
+
|
143
|
+
|
144
|
+
def generate_mask(file_path, output_dir, row_vessel, upsample_factor=1, output_type="raster", dilatation=5):
|
145
|
+
""" Get the entries for the csv file for an image without a mask
|
146
|
+
Args:
|
147
|
+
file_path (String): path to the image
|
148
|
+
output_dir (String): path to the output folder
|
149
|
+
row_vessel (Pandas Dataframe): boat's informations
|
150
|
+
upsample_factor (Int): upsampling factor for the model and the cross correlation
|
151
|
+
output_type (String): can be a 'raster' (.tif) or a 'vector' (.geojson) output
|
152
|
+
dilatation (Int): size of the dilation for the length and width of the mask in meters
|
153
|
+
Returns:
|
154
|
+
(Dict): csv entries for the image
|
155
|
+
"""
|
156
|
+
|
157
|
+
# Load the source tile
|
158
|
+
with rasterio.open(file_path, 'r') as src:
|
159
|
+
|
160
|
+
# All 10m channels except blue
|
161
|
+
data = src.read([2,3,4,11,12]).transpose(1, 2, 0)
|
162
|
+
|
163
|
+
# Get the dimensions of the boat
|
164
|
+
# pixel_res = abs(src.transform[4])
|
165
|
+
pixel_res = 10
|
166
|
+
width_px = row_vessel["Width"] / pixel_res
|
167
|
+
length_px = row_vessel["Length"] / pixel_res
|
168
|
+
|
169
|
+
# Get the center of the mask
|
170
|
+
model, correlations, center = center_cross_correlation(data,
|
171
|
+
width_px, length_px, row_vessel['Heading'], upsample_factor)
|
172
|
+
|
173
|
+
# Rectangular bounding box
|
174
|
+
mask_width_px = (row_vessel["Width"] + dilatation) / pixel_res
|
175
|
+
mask_length_px = (row_vessel["Length"] + dilatation) / pixel_res
|
176
|
+
shape = get_vessel_shape(center, mask_width_px, mask_length_px, row_vessel['Heading'])
|
177
|
+
mask = rasterio.features.rasterize([shape], out_shape=data.shape[0:2], all_touched=True)
|
178
|
+
|
179
|
+
if output_type == "vector":
|
180
|
+
# generate Geojson
|
181
|
+
shape_wgs84 = convert_shape_to_wgs84(shape, src.transform)
|
182
|
+
gdr = gpd.GeoDataFrame({'geometry': [shape_wgs84],
|
183
|
+
"labels": [["Boat"]],
|
184
|
+
"tasks":[["segmentation"]]},
|
185
|
+
crs='EPSG:4326')
|
186
|
+
|
187
|
+
# Write to geojson
|
188
|
+
label_geojson = gdr.to_json(drop_id=True)
|
189
|
+
out_mask_path = Path(file_path).parent / f"{file_path.stem}_labels.geojson"
|
190
|
+
|
191
|
+
with open(out_mask_path, "w") as dst:
|
192
|
+
dst.write(label_geojson)
|
193
|
+
|
194
|
+
elif output_type == "raster":
|
195
|
+
# Create the profile for the .tif
|
196
|
+
profile = {
|
197
|
+
'driver': 'GTiff',
|
198
|
+
'height': src.height,
|
199
|
+
'width': src.width,
|
200
|
+
'count': 1,
|
201
|
+
'dtype': rasterio.uint8,
|
202
|
+
'crs': src.crs,
|
203
|
+
'transform': src.transform,
|
204
|
+
'nodata': None,
|
205
|
+
'compress': 'lzw'
|
206
|
+
}
|
207
|
+
|
208
|
+
# Write the mask
|
209
|
+
out_mask_path = Path(output_dir) / f"mask_{Path(file_path).name}"
|
210
|
+
with rasterio.open(out_mask_path, 'w', **profile) as dst:
|
211
|
+
dst.write(mask, indexes=1)
|
212
|
+
|
213
|
+
|
214
|
+
def process_directoy(dir_name, output_dir, tiles_df, upsample_factor, output_type):
|
215
|
+
|
216
|
+
assert output_type == "raster" or output_type == "vector"
|
217
|
+
print(f"Processing tiles from {dir_name}")
|
218
|
+
|
219
|
+
# Prepare outputpath
|
220
|
+
output_dir_name = Path(output_dir)
|
221
|
+
|
222
|
+
if output_type =="vector":
|
223
|
+
|
224
|
+
labels_json = {"labels": [{"name": "Boat", "color": "#ff8000"}]}
|
225
|
+
json_path = Path(dir_name) / "labels.json"
|
226
|
+
|
227
|
+
with open(json_path, "w") as dst:
|
228
|
+
dst.write(json.dumps(labels_json))
|
229
|
+
|
230
|
+
# Generate the mask for each vessel
|
231
|
+
list_nan = []
|
232
|
+
|
233
|
+
# Convert angles in radian
|
234
|
+
tiles_df["Heading"] *= np.pi/180
|
235
|
+
|
236
|
+
for i in range(len(tiles_df)):
|
237
|
+
row_vessel = tiles_df.iloc[i]
|
238
|
+
img_path = Path(dir_name) / f"{row_vessel['ImageId']}.tiff"
|
239
|
+
|
240
|
+
# Get mmsi from filename
|
241
|
+
vessel = int(row_vessel["ImageId"].split('_')[1])
|
242
|
+
|
243
|
+
if row_vessel.isnull().values.any(): # Tiles with Nan data
|
244
|
+
list_nan.append(vessel)
|
245
|
+
|
246
|
+
else:
|
247
|
+
# Get the mask of the boat
|
248
|
+
generate_mask(img_path, output_dir_name, row_vessel, upsample_factor, output_type)
|
249
|
+
|
250
|
+
if list_nan:
|
251
|
+
print(f"No mask saved for the vessels {list_nan}, NaN values found in the AIS data")
|
252
|
+
|
253
|
+
|
254
|
+
def process_db(images_path, output_dir, upsample_factor, output_type = "raster"):
|
255
|
+
""" Get the entries for the csv file for an image without a mask
|
256
|
+
Args:
|
257
|
+
csv_tiles (String): path to the csv folder of the tiles
|
258
|
+
output_dir (String): path to the output folder
|
259
|
+
upsample_factor (Int): upsampling factor for the model and the cross correlation
|
260
|
+
output_type (String): can be a 'raster' (.tif) or a 'vector' (.geojson) output
|
261
|
+
"""
|
262
|
+
# Prepare the output file
|
263
|
+
csv_paths = Path(images_path).glob("*.csv")
|
264
|
+
for csv_tiles in csv_paths:
|
265
|
+
# read the tiles csv
|
266
|
+
tiles_df = pd.read_csv(csv_tiles)
|
267
|
+
# Get the path to the tiles
|
268
|
+
tiles_path = Path(csv_tiles).parent
|
269
|
+
process_directoy(tiles_path,
|
270
|
+
output_dir=output_dir,
|
271
|
+
tiles_df=tiles_df,
|
272
|
+
upsample_factor=upsample_factor,
|
273
|
+
output_type=output_type)
|
@@ -1,5 +1,5 @@
|
|
1
|
-
eotdl/__init__.py,sha256
|
2
|
-
eotdl/cli.py,sha256=
|
1
|
+
eotdl/__init__.py,sha256=7OVkF8SLpGQOJkvOiT6XHXrkE9hp4JDvF9-vFYP8Ytg,27
|
2
|
+
eotdl/cli.py,sha256=MgRmnBcnPtRTW_nuvtH41y7MSjmVMzr1JOt9X-oDnt4,759
|
3
3
|
eotdl/access/__init__.py,sha256=k-zmTwB6VLoWt_AsXx9CnEKdtONBZAaC8T6vqPMPSjk,436
|
4
4
|
eotdl/access/download.py,sha256=e5H8LUkCfIVkFxJFM5EwCMG-R5DHVSHDGLvuNM5DNc8,2815
|
5
5
|
eotdl/access/search.py,sha256=1indipTfna4VAfGlKb8gkaYyHAELdHR4cm1mVIDW69s,1415
|
@@ -18,40 +18,56 @@ eotdl/auth/errors.py,sha256=E1lv3Igk--J-SOgNH18i8Xx9bXrrMyBSHKt_CAUmGPo,308
|
|
18
18
|
eotdl/auth/is_logged.py,sha256=QREuhkoDnarZoUZwCxVCNoESGb_Yukh0lJo1pXvrV9Q,115
|
19
19
|
eotdl/auth/logout.py,sha256=P_Sp6WmVvnG3R9V1L9541KNyHFko9DtQPqAKD2vaguw,161
|
20
20
|
eotdl/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
21
|
-
eotdl/commands/auth.py,sha256=
|
22
|
-
eotdl/commands/datasets.py,sha256=
|
23
|
-
eotdl/commands/models.py,sha256=
|
21
|
+
eotdl/commands/auth.py,sha256=sSfawOpht6ntToFXDJrOu11IATV9vN03Bqyg5LNGb1s,1646
|
22
|
+
eotdl/commands/datasets.py,sha256=1ksdUYSalEY8ts0_ak3-nhV4WyygkNl33uiZ6K2GUaM,5508
|
23
|
+
eotdl/commands/models.py,sha256=a6ozJC0MH7CsK2-ts6sN_9EFbT6bzoaJne8v83JjTzg,4942
|
24
|
+
eotdl/commands/pipelines.py,sha256=uvdS7NFzxG95IiKKFf5ha4TgGZsN-LO7Pucmp0GWgnw,4396
|
24
25
|
eotdl/commands/stac.py,sha256=jgjjkGw9tIvuovyAwfEu6B4ZMoMvEj5lrj_lO-9IqrE,1444
|
25
26
|
eotdl/curation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
26
27
|
eotdl/curation/stac/__init__.py,sha256=FMi-qzd6v1sdsqZsBRRnedccaJFXJGCPCH3uTctyLYU,37
|
27
28
|
eotdl/curation/stac/api.py,sha256=5XW9yzSxiuML70bBbzJ0DGx0GmplmhYtgeGZg029Qjk,1428
|
28
29
|
eotdl/curation/stac/stac.py,sha256=4f7xrh2CcXTkTs3or1UMVxiFfwtVfTqH4YwTGsbi6No,1013
|
29
|
-
eotdl/datasets/__init__.py,sha256=
|
30
|
-
eotdl/datasets/ingest.py,sha256=
|
31
|
-
eotdl/datasets/retrieve.py,sha256=
|
32
|
-
eotdl/datasets/stage.py,sha256=
|
33
|
-
eotdl/datasets/update.py,sha256=
|
34
|
-
eotdl/
|
30
|
+
eotdl/datasets/__init__.py,sha256=3FtdIDmSaCg4P15oI5d-7DDomuUEz4E3PjK78Ofvm3g,283
|
31
|
+
eotdl/datasets/ingest.py,sha256=sxtnaRTUZxtg5Wfs8uei7M63xszpd6eWHH-KvDqPW5c,1750
|
32
|
+
eotdl/datasets/retrieve.py,sha256=vQzociVOcD1A1ZTfFC42jzgEYVcc_y_HcvlALBqpAd8,1210
|
33
|
+
eotdl/datasets/stage.py,sha256=dbmEV5VpaM1DEHhpCWTEgYAuCNUGaW0Ghm_oP8_COEg,2168
|
34
|
+
eotdl/datasets/update.py,sha256=QmhXZwAOqz5ysc_VpCjFFDo5tpt0EKG44G1jYeQmbkQ,706
|
35
|
+
eotdl/fe/__init__.py,sha256=nwm7HHfh_UrCnMMYaO2vqQ6y4ziVzAf6zt_RuvDSVF4,167
|
36
|
+
eotdl/fe/ingest.py,sha256=JkVxPkHbltmvlRP6fmPKZu5lx8HJGOp9dSxrzkCv8tQ,1489
|
37
|
+
eotdl/fe/retrieve.py,sha256=xrtmYcG14xgknu9yQJEdSjJMtSMoZkDU____95Yd6YY,448
|
38
|
+
eotdl/fe/stage.py,sha256=wxmX_uyNc2kLvU_bF2SvyBBr05sPlTA7xYq0T4pSzEo,2001
|
39
|
+
eotdl/fe/update.py,sha256=GO9ep8tAneGQrOseKdZnrADvNs1x9uhG4Q7Y5UhcLVI,354
|
40
|
+
eotdl/fe/openeo/__init__.py,sha256=oag2hTyLcRKF-7SGkY-ZcbuftUtABZMNtn1-8gOYDik,108
|
41
|
+
eotdl/fe/openeo/advanced_patch_extraction.py,sha256=jyfkHT8Co53xey2qbWimzYeB5kLwCEG_aCyK3OUefW4,5778
|
42
|
+
eotdl/fe/openeo/basic_point_extraction.py,sha256=pUFZ34J9Ob21V9Ur6GLO3d3HGKYU5o6vjBtF3eR3JXs,4105
|
43
|
+
eotdl/fe/openeo/dataframe_utils.py,sha256=QYG4xkJ6LER8q9lDD8ovd_pPcBb9dX2hbg4y5ZMMfW4,7981
|
44
|
+
eotdl/fe/openeo/s3proxy_utils.py,sha256=AH8cKyf8D8qM4UYXgBgZX7I2seKxhkhNjxQJpcqtxZI,6406
|
45
|
+
eotdl/fe/openeo/spatial_utils.py,sha256=E1FfPnzgfBMhFd4XAjRl9FEZO3QnHf27tJjkZzze75Q,1008
|
46
|
+
eotdl/fe/openeo/temporal_utils.py,sha256=R6epJqyhNH-c-wXVg8GgV3O_1DStk9hms5Oon4lPLH8,570
|
47
|
+
eotdl/files/__init__.py,sha256=3guFFgXq6WEQ6X1VsVnEZEzya2kpQajaDvLpNSQboVA,33
|
48
|
+
eotdl/files/get_url.py,sha256=gcD6E6cj9tsEsF2T5WdrFKK7rBjjjcGmWtyUc8IQEBo,772
|
35
49
|
eotdl/files/ingest.bck,sha256=dgjZfd-ACCKradDo2B02CPahwEhFtWvnKvTm372K5eo,6185
|
36
|
-
eotdl/files/ingest.py,sha256=
|
37
|
-
eotdl/files/metadata.py,sha256=
|
50
|
+
eotdl/files/ingest.py,sha256=RwQ3WazTm3b600QXEiHsTDApIegxAxW-Vhw9GkGQFP0,9427
|
51
|
+
eotdl/files/metadata.py,sha256=MGrIvcgNr3AMI3j9Jcdyp5Q3Jcuth8m6Z14BCDxF0xI,1405
|
38
52
|
eotdl/models/__init__.py,sha256=b6t1Z377On1F56c-GSy7FM_nBWRLHh1Ph2R24rPFiVY,239
|
39
53
|
eotdl/models/download.py,sha256=rRT3fG-qS3-SXfzFdqy0cuiDnOIV9Du74JCnsbbA9Ps,3475
|
40
|
-
eotdl/models/ingest.py,sha256=
|
54
|
+
eotdl/models/ingest.py,sha256=cvkxH_KZO1v2a6VSsd0Mady1kPQY7WGn0YBXaY90_Xc,1412
|
41
55
|
eotdl/models/retrieve.py,sha256=-Ij7dT4J1p7MW4n13OlPB9OW4tBaBXPwk9dW8IuCZPc,664
|
42
56
|
eotdl/models/stage.py,sha256=rvWN8vcBz7qHhu0TzJ90atw1kEr3JPKF0k2S-Sv-JVs,1944
|
43
|
-
eotdl/models/update.py,sha256=
|
57
|
+
eotdl/models/update.py,sha256=PIdPbPrdul-HSAAL21SadAkZT2kcnJyV2uTmi8dlK5k,676
|
44
58
|
eotdl/repos/APIRepo.py,sha256=s9w29Cnk5Pu4NvjyHAfcpM69a2lODICJ-Gn_iosxsPg,791
|
45
59
|
eotdl/repos/AuthAPIRepo.py,sha256=vYCqFawe3xUm2cx4SqVXCvzl8J_sr9rs_MkipYC0bXE,957
|
46
60
|
eotdl/repos/AuthRepo.py,sha256=jpzzhINCcDZHRCyrPDsp49h17IlXp2HvX3BB3f5cnb4,1154
|
47
|
-
eotdl/repos/DatasetsAPIRepo.py,sha256=
|
48
|
-
eotdl/repos/
|
49
|
-
eotdl/repos/
|
61
|
+
eotdl/repos/DatasetsAPIRepo.py,sha256=bJnMWQVQ-t25MHwisMKeq8yeAVxmbDB77TXtYdTwV70,2209
|
62
|
+
eotdl/repos/FEAPIRepo.py,sha256=nbyk1Wt3hzCYOm6zvZ1DA5UQ_rmY8G3cpSKs0rLem4I,1702
|
63
|
+
eotdl/repos/FilesAPIRepo.py,sha256=iJWT2_7TIg8gTMAihui5mBbcUWF5THh-AuuLcfyMHGk,4756
|
64
|
+
eotdl/repos/ModelsAPIRepo.py,sha256=hgnU8wkwESsrzfL6Wxpwwt7ejlnoOBeeNa4IrV4hwRo,1494
|
50
65
|
eotdl/repos/STACAPIRepo.py,sha256=GJIrLkgVB-donToJlgOmaJbxDmXzIuwlmCb9R2yoRIA,1387
|
51
|
-
eotdl/repos/__init__.py,sha256=
|
66
|
+
eotdl/repos/__init__.py,sha256=I4_friwwZ4sSQxmguYY2uBNWvpKLaHUEN1i6Zib_WWU,291
|
52
67
|
eotdl/shared/__init__.py,sha256=mF7doJC8Z5eTPmB01UQvPivThZac32DRY33T6qshXfg,41
|
53
68
|
eotdl/shared/checksum.py,sha256=4IB6N9jRO0chMDNJzpdnFDhC9wcFF9bO5oHq2HodcHw,479
|
54
69
|
eotdl/tools/__init__.py,sha256=_p3n2dw3ulwyr1OlVw5d_jMV64cNYfajQMUbzFfvIpU,178
|
70
|
+
eotdl/tools/ais_labelling.py,sha256=2KGbNGjN3R_Y26SoXPNBuXB7HSpUpyXViIByM-ABDvo,10655
|
55
71
|
eotdl/tools/geo_utils.py,sha256=JKHUAnqkwiIrvh5voDclWAW-i57qVqH2FUjeOt1TQf4,7547
|
56
72
|
eotdl/tools/metadata.py,sha256=RvNmoMdfEKoo-DzhEAqL-f9ZCjIe_bsdHQwACMk6w1E,1664
|
57
73
|
eotdl/tools/paths.py,sha256=yWhOtVxX4NxrDrrBX2fuye5N1mAqrxXFy_eA7dffd84,1152
|
@@ -60,7 +76,7 @@ eotdl/tools/time_utils.py,sha256=JHrQ3PxXkhwor8zcOFccf26zOG9WBtb9xHb6j-Fqa9k,466
|
|
60
76
|
eotdl/tools/tools.py,sha256=Tl4_v2ejkQo_zyZek8oofJwoYcdVosdOwW1C0lvWaNM,6354
|
61
77
|
eotdl/wrappers/__init__.py,sha256=IY3DK_5LMbc5bIQFleQA9kzFbPhWuTLesJ8dwfvpkdA,32
|
62
78
|
eotdl/wrappers/models.py,sha256=kNO4pYw9KKKmElE7bZWWHGs7FIThNUXj8XciKh_3rNw,6432
|
63
|
-
eotdl-2025.
|
64
|
-
eotdl-2025.
|
65
|
-
eotdl-2025.
|
66
|
-
eotdl-2025.
|
79
|
+
eotdl-2025.5.26.dist-info/METADATA,sha256=ifJ4T20QsC202xJpv8Cwn-4vBHQOF9e_l0Jdgb1rZ-Y,3365
|
80
|
+
eotdl-2025.5.26.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
81
|
+
eotdl-2025.5.26.dist-info/entry_points.txt,sha256=FV4dFIZ5zdWj1q1nUEEip29n3sAgbviVOizEz00gEF0,40
|
82
|
+
eotdl-2025.5.26.dist-info/RECORD,,
|
File without changes
|
File without changes
|