aletrn commited on
Commit
7acc2ae
·
1 Parent(s): 5ec3c7c

[feat] (backend) add nextzen terrain xyz provider as DEM raster source, make sam predictions with RGB image made with normalized slope, elevation and curvature as channels

Browse files
samgis/io/raster_helpers.py ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """helpers for computer vision duties"""
2
+ import numpy as np
3
+ from numpy import ndarray
4
+
5
+ from samgis import app_logger
6
+ from samgis.utilities.type_hints import TmsTerrainProvidersNames
7
+
8
+
9
+ def get_nextzen_terrain_rgb_formula(red: ndarray, green: ndarray, blue: ndarray) -> ndarray:
10
+ """
11
+ Compute a 32-bits 2d digital elevation model from a nextzen 'terrarium' (terrain-rgb) raster.
12
+ 'Terrarium' format PNG tiles contain raw elevation data in meters, in Mercator projection (EPSG:3857).
13
+ All values are positive with a 32,768 offset, split into the red, green, and blue channels,
14
+ with 16 bits of integer and 8 bits of fraction. To decode:
15
+
16
+ (red * 256 + green + blue / 256) - 32768
17
+
18
+ More details on https://www.mapzen.com/blog/elevation/
19
+
20
+ Args:
21
+ red: red-valued channel image array
22
+ green: green-valued channel image array
23
+ blue: blue-valued channel image array
24
+
25
+ Returns:
26
+ ndarray: nextzen 'terrarium' 2d digital elevation model raster at 32 bits
27
+
28
+ """
29
+ return (red * 256 + green + blue / 256) - 32768
30
+
31
+
32
+ def get_mapbox__terrain_rgb_formula(red: ndarray, green: ndarray, blue: ndarray) -> ndarray:
33
+ return ((red * 256 * 256 + green * 256 + blue) * 0.1) - 10000
34
+
35
+
36
+ providers_terrain_rgb_formulas = {
37
+ TmsTerrainProvidersNames.MAPBOX_TERRAIN_TILES_NAME: get_mapbox__terrain_rgb_formula,
38
+ TmsTerrainProvidersNames.NEXTZEN_TERRAIN_TILES_NAME: get_nextzen_terrain_rgb_formula
39
+ }
40
+
41
+
42
+ def _get_2d_array_from_3d(arr: ndarray) -> ndarray:
43
+ return arr.reshape(arr.shape[0], arr.shape[1])
44
+
45
+
46
+ def _channel_split(arr: ndarray) -> list[ndarray]:
47
+ from numpy import dsplit
48
+
49
+ return dsplit(arr, arr.shape[-1])
50
+
51
+
52
+ def get_raster_terrain_rgb_like(arr: ndarray, xyz_provider_name, nan_value_int: int = -12000):
53
+ """
54
+ Compute a 32-bits 2d digital elevation model from a terrain-rgb raster.
55
+
56
+ Args:
57
+ arr: rgb raster
58
+ xyz_provider_name: xyz provider
59
+ nan_value_int: threshold int value to replace NaN
60
+
61
+ Returns:
62
+ ndarray: 2d digital elevation model raster at 32 bits
63
+ """
64
+ red, green, blue = _channel_split(arr)
65
+ dem_rgb = providers_terrain_rgb_formulas[xyz_provider_name](red, green, blue)
66
+ output = _get_2d_array_from_3d(dem_rgb)
67
+ output[output < nan_value_int] = np.NaN
68
+ return output
69
+
70
+
71
+ def get_rgb_prediction_image(raster_cropped: ndarray, slope_cellsize: int, invert_image: bool = True) -> ndarray:
72
+ """
73
+ Return an RGB image from input numpy array
74
+
75
+ Args:
76
+ raster_cropped: input numpy array
77
+ slope_cellsize: window size to calculate slope and curvature (1st and 2nd degree array derivative)
78
+ invert_image:
79
+
80
+ Returns:
81
+ tuple of str: image filename, image path (with filename)
82
+ """
83
+ from samgis.utilities.constants import CHANNEL_EXAGGERATIONS_LIST
84
+
85
+ try:
86
+ slope, curvature = get_slope_curvature(raster_cropped, slope_cellsize=slope_cellsize)
87
+ channel0 = raster_cropped
88
+ channel1 = normalize_array_list(
89
+ [raster_cropped, slope, curvature], CHANNEL_EXAGGERATIONS_LIST, title=f"channel1_normlist")
90
+ channel2 = curvature
91
+
92
+ return get_rgb_image(channel0, channel1, channel2, invert_image=invert_image)
93
+ except ValueError as ve_get_rgb_prediction_image:
94
+ msg = f"ve_get_rgb_prediction_image:{ve_get_rgb_prediction_image}."
95
+ app_logger.error(msg)
96
+ raise ve_get_rgb_prediction_image
97
+
98
+
99
+ def get_rgb_image(arr_channel0: ndarray, arr_channel1: ndarray, arr_channel2: ndarray,
100
+ invert_image: bool = True) -> ndarray:
101
+ """
102
+ Return an RGB image from input R,G,B channel arrays
103
+
104
+ Args:
105
+ arr_channel0: channel image 0
106
+ arr_channel1: channel image 1
107
+ arr_channel2: channel image 2
108
+ invert_image: invert the RGB image channel order
109
+
110
+ Returns:
111
+ ndarray: RGB image
112
+
113
+ """
114
+ try:
115
+ # RED curvature, GREEN slope, BLUE dem, invert_image=True
116
+ if len(arr_channel0.shape) != 2:
117
+ msg = f"arr_size, wrong type:{type(arr_channel0)} or arr_size:{arr_channel0.shape}."
118
+ app_logger.error(msg)
119
+ raise ValueError(msg)
120
+ data_rgb = np.zeros((arr_channel0.shape[0], arr_channel0.shape[1], 3), dtype=np.uint8)
121
+ app_logger.debug(f"arr_container data_rgb, type:{type(data_rgb)}, arr_shape:{data_rgb.shape}.")
122
+ data_rgb[:, :, 0] = normalize_array(
123
+ arr_channel0.astype(float), high=1, norm_type="float", title=f"RGB:channel0") * 64
124
+ data_rgb[:, :, 1] = normalize_array(
125
+ arr_channel1.astype(float), high=1, norm_type="float", title=f"RGB:channel1") * 128
126
+ data_rgb[:, :, 2] = normalize_array(
127
+ arr_channel2.astype(float), high=1, norm_type="float", title=f"RGB:channel2") * 192
128
+ if invert_image:
129
+ data_rgb = np.bitwise_not(data_rgb)
130
+ return data_rgb
131
+ except ValueError as ve_get_rgb_image:
132
+ msg = f"ve_get_rgb_image:{ve_get_rgb_image}."
133
+ app_logger.error(msg)
134
+ raise ve_get_rgb_image
135
+
136
+
137
+ def get_slope_curvature(dem: ndarray, slope_cellsize: int, title: str = "") -> tuple[ndarray, ndarray]:
138
+ """
139
+ Return a tuple of two numpy arrays representing slope and curvature (1st grade derivative and 2nd grade derivative)
140
+
141
+ Args:
142
+ dem: input numpy array
143
+ slope_cellsize: window size to calculate slope and curvature
144
+ title: array name
145
+
146
+ Returns:
147
+ tuple of ndarrays: slope image, curvature image
148
+
149
+ """
150
+
151
+ app_logger.info(f"dem shape:{dem.shape}, slope_cellsize:{slope_cellsize}.")
152
+
153
+ try:
154
+ dem = dem.astype(float)
155
+ app_logger.debug("get_slope_curvature:: start")
156
+ slope = calculate_slope(dem, slope_cellsize)
157
+ app_logger.debug("get_slope_curvature:: created slope raster")
158
+ s2c = calculate_slope(slope, slope_cellsize)
159
+ curvature = normalize_array(s2c, norm_type="float", title=f"SC:curvature_{title}")
160
+ app_logger.debug("get_slope_curvature:: created curvature raster")
161
+
162
+ return slope, curvature
163
+ except ValueError as ve_get_slope_curvature:
164
+ msg = f"ve_get_slope_curvature:{ve_get_slope_curvature}."
165
+ app_logger.error(msg)
166
+ raise ve_get_slope_curvature
167
+
168
+
169
+ def calculate_slope(dem_array: ndarray, cell_size: int, calctype: str = "degree") -> ndarray:
170
+ """
171
+ Return a numpy array representing slope (1st grade derivative)
172
+
173
+ Args:
174
+ dem_array: input numpy array
175
+ cell_size: window size to calculate slope
176
+ calctype: calculus type
177
+
178
+ Returns:
179
+ ndarray: slope image
180
+
181
+ """
182
+
183
+ try:
184
+ gradx, grady = np.gradient(dem_array, cell_size)
185
+ dem_slope = np.sqrt(gradx ** 2 + grady ** 2)
186
+ if calctype == "degree":
187
+ dem_slope = np.degrees(np.arctan(dem_slope))
188
+ app_logger.debug(f"extracted slope with calctype:{calctype}.")
189
+ return dem_slope
190
+ except ValueError as ve_calculate_slope:
191
+ msg = f"ve_calculate_slope:{ve_calculate_slope}."
192
+ app_logger.error(msg)
193
+ raise ve_calculate_slope
194
+
195
+
196
+ def normalize_array(arr: ndarray, high: int = 255, norm_type: str = "float", invert: bool = False, title: str = "") -> ndarray:
197
+ """
198
+ Return normalized numpy array between 0 and 'high' value. Default normalization type is int
199
+
200
+ Args:
201
+ arr: input numpy array
202
+ high: max value to use for normalization
203
+ norm_type: type of normalization: could be 'float' or 'int'
204
+ invert: bool to choose if invert the normalized numpy array
205
+ title: array title name
206
+
207
+ Returns:
208
+ ndarray: normalized numpy array
209
+
210
+ """
211
+
212
+ h_min_arr = np.nanmin(arr)
213
+ h_arr_max = np.nanmax(arr)
214
+ try:
215
+ h_diff = h_arr_max - h_min_arr
216
+ app_logger.debug(
217
+ f"normalize_array:: '{title}',h_min_arr:{h_min_arr},h_arr_max:{h_arr_max},h_diff:{h_diff}, dtype:{arr.dtype}.")
218
+ except Exception as e_h_diff:
219
+ app_logger.error(f"e_h_diff:{e_h_diff}.")
220
+ raise e_h_diff
221
+
222
+ if check_empty_array(arr, high) or check_empty_array(arr, h_diff):
223
+ msg_ve = f"normalize_array::empty array '{title}',h_min_arr:{h_min_arr},h_arr_max:{h_arr_max},h_diff:{h_diff}, dtype:{arr.dtype}."
224
+ app_logger.error(msg_ve)
225
+ raise ValueError(msg_ve)
226
+ try:
227
+ normalized = high * (arr - h_min_arr) / h_diff
228
+ normalized = np.nanmax(normalized) - normalized if invert else normalized
229
+ return normalized.astype(int) if norm_type == "int" else normalized
230
+ except FloatingPointError as fe:
231
+ msg = f"normalize_array::{title}:h_arr_max:{h_arr_max},h_min_arr:{h_min_arr},fe:{fe}."
232
+ app_logger.error(msg)
233
+ raise ValueError(msg)
234
+
235
+
236
+ def normalize_array_list(arr_list: list[ndarray], exaggerations_list: list[float] = None, title: str = "") -> ndarray:
237
+ """
238
+ Return a normalized numpy array from a list of numpy array and an optional list of exaggeration values.
239
+
240
+ Args:
241
+ arr_list: list of array to use for normalization
242
+ exaggerations_list: list of exaggeration values
243
+ title: array title name
244
+
245
+ Returns:
246
+ ndarray: normalized numpy array
247
+
248
+ """
249
+
250
+ if not arr_list:
251
+ msg = f"input list can't be empty:{arr_list}."
252
+ app_logger.error(msg)
253
+ raise ValueError(msg)
254
+ if exaggerations_list is None:
255
+ exaggerations_list = list(np.ones(len(arr_list)))
256
+ arr_tmp = np.zeros(arr_list[0].shape)
257
+ for a, exaggeration in zip(arr_list, exaggerations_list):
258
+ app_logger.debug(f"normalize_array_list::exaggeration:{exaggeration}.")
259
+ arr_tmp += normalize_array(a, norm_type="float", title=f"ARRLIST:{title}.") * exaggeration
260
+ return arr_tmp / len(arr_list)
261
+
262
+
263
+ def check_empty_array(arr: ndarray, val: float) -> bool:
264
+ """
265
+ Return True if the input numpy array is empy. Check if
266
+ - all values are all the same value (0, 1 or given 'val' input float value)
267
+ - all values that are not NaN are a given 'val' float value
268
+
269
+ Args:
270
+ arr: input numpy array
271
+ val: value to use for check if array is empty
272
+
273
+ Returns:
274
+ bool: True if the input numpy array is empty, False otherwise
275
+
276
+ """
277
+
278
+ arr_check5_tmp = np.copy(arr)
279
+ arr_size = arr.shape[0]
280
+ arr_check3 = np.ones((arr_size, arr_size))
281
+ check1 = np.array_equal(arr, arr_check3)
282
+ check2 = np.array_equal(arr, np.zeros((arr_size, arr_size)))
283
+ arr_check3 *= val
284
+ check3 = np.array_equal(arr, arr_check3)
285
+ arr[np.isnan(arr)] = 0
286
+ check4 = np.array_equal(arr, np.zeros((arr_size, arr_size)))
287
+ arr_check5 = np.ones((arr_size, arr_size)) * val
288
+ arr_check5_tmp[np.isnan(arr_check5_tmp)] = val
289
+ check5 = np.array_equal(arr_check5_tmp, arr_check5)
290
+ app_logger.debug(f"array checks:{check1}, {check2}, {check3}, {check4}, {check5}.")
291
+ return check1 or check2 or check3 or check4 or check5
samgis/io/{lambda_helpers.py → wrappers_helpers.py} RENAMED
@@ -1,11 +1,11 @@
1
  """lambda helper functions"""
2
  from typing import Dict
3
- from xyzservices import providers
4
 
5
  from samgis import app_logger
6
  from samgis.io.coordinates_pixel_conversion import get_latlng_to_pixel_coordinates
7
- from samgis.utilities.constants import CUSTOM_RESPONSE_MESSAGES
8
- from samgis.utilities.type_hints import ApiRequestBody, ContentTypes
9
  from samgis.utilities.utilities import base64_decode
10
 
11
 
@@ -152,9 +152,30 @@ def get_parsed_request_body(event: Dict or str) -> ApiRequestBody:
152
  return parsed_body
153
 
154
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  def get_url_tile(source_type: str):
156
- from samgis.utilities.constants import DEFAULT_TMS_NAME, DEFAULT_TMS_NAME_SHORT
 
 
 
 
 
 
 
157
 
158
- if source_type.lower() == DEFAULT_TMS_NAME_SHORT:
159
- return providers.query_name(DEFAULT_TMS_NAME)
160
  return providers.query_name(source_type)
 
 
 
 
 
1
  """lambda helper functions"""
2
  from typing import Dict
3
+ from xyzservices import providers, TileProvider
4
 
5
  from samgis import app_logger
6
  from samgis.io.coordinates_pixel_conversion import get_latlng_to_pixel_coordinates
7
+ from samgis.utilities.constants import COMPLETE_URL_TILES_MAPBOX, COMPLETE_URL_TILES_NEXTZEN, CUSTOM_RESPONSE_MESSAGES
8
+ from samgis.utilities.type_hints import ApiRequestBody, ContentTypes, TmsTerrainProvidersNames, TmsDefaultProvidersNames
9
  from samgis.utilities.utilities import base64_decode
10
 
11
 
 
152
  return parsed_body
153
 
154
 
155
+ mapbox_terrain_rgb = TileProvider(
156
+ name=TmsTerrainProvidersNames.MAPBOX_TERRAIN_TILES_NAME,
157
+ url=COMPLETE_URL_TILES_MAPBOX,
158
+ attribution=""
159
+ )
160
+ nextzen_terrain_rgb = TileProvider(
161
+ name=TmsTerrainProvidersNames.NEXTZEN_TERRAIN_TILES_NAME,
162
+ url=COMPLETE_URL_TILES_NEXTZEN,
163
+ attribution=""
164
+ )
165
+
166
+
167
  def get_url_tile(source_type: str):
168
+ match source_type.lower():
169
+ case TmsDefaultProvidersNames.DEFAULT_TILES_NAME_SHORT:
170
+ return providers.query_name(TmsDefaultProvidersNames.DEFAULT_TILES_NAME_SHORT)
171
+ case TmsTerrainProvidersNames.MAPBOX_TERRAIN_TILES_NAME:
172
+ return mapbox_terrain_rgb
173
+ case TmsTerrainProvidersNames.NEXTZEN_TERRAIN_TILES_NAME:
174
+ app_logger.info("nextzen_terrain_rgb:", nextzen_terrain_rgb)
175
+ return nextzen_terrain_rgb
176
 
 
 
177
  return providers.query_name(source_type)
178
+
179
+
180
+ def check_source_type_is_terrain(source: str | TileProvider):
181
+ return isinstance(source, TileProvider) and source.name in list(TmsTerrainProvidersNames)
samgis/prediction_api/predictors.py CHANGED
@@ -3,10 +3,14 @@ from numpy import array as np_array, uint8, zeros, ndarray
3
 
4
  from samgis import app_logger, MODEL_FOLDER
5
  from samgis.io.geo_helpers import get_vectorized_raster_as_geojson
 
6
  from samgis.io.tms2geotiff import download_extent
 
7
  from samgis.prediction_api.sam_onnx import SegmentAnythingONNX
8
- from samgis.utilities.constants import MODEL_ENCODER_NAME, MODEL_DECODER_NAME, DEFAULT_TMS
9
- from samgis.utilities.type_hints import llist_float, dict_str_int, list_dict, tuple_ndarr_int, PIL_Image
 
 
10
 
11
  models_dict = {"fastsam": {"instance": None}}
12
 
@@ -16,7 +20,7 @@ def samexporter_predict(
16
  prompt: list_dict,
17
  zoom: float,
18
  model_name: str = "fastsam",
19
- source: str = DEFAULT_TMS
20
  ) -> dict_str_int:
21
  """
22
  Return predictions as a geojson from a geo-referenced image using the given input prompt.
@@ -49,6 +53,14 @@ def samexporter_predict(
49
  pt0, pt1 = bbox
50
  app_logger.info(f"tile_source: {source}: downloading geo-referenced raster with bbox {bbox}, zoom {zoom}.")
51
  img, transform = download_extent(w=pt1[1], s=pt1[0], e=pt0[1], n=pt0[0], zoom=zoom, source=source)
 
 
 
 
 
 
 
 
52
  app_logger.info(
53
  f"img type {type(img)} with shape/size:{img.size}, transform type: {type(transform)}, transform:{transform}.")
54
 
 
3
 
4
  from samgis import app_logger, MODEL_FOLDER
5
  from samgis.io.geo_helpers import get_vectorized_raster_as_geojson
6
+ from samgis.io.raster_helpers import get_raster_terrain_rgb_like, get_rgb_prediction_image
7
  from samgis.io.tms2geotiff import download_extent
8
+ from samgis.io.wrappers_helpers import check_source_type_is_terrain
9
  from samgis.prediction_api.sam_onnx import SegmentAnythingONNX
10
+ from samgis.utilities.constants import MODEL_ENCODER_NAME, MODEL_DECODER_NAME, DEFAULT_URL_TILES, SLOPE_CELLSIZE, \
11
+ DEFAULT_INPUT_SHAPE
12
+ from samgis.utilities.type_hints import llist_float, dict_str_int, list_dict, tuple_ndarr_int, PIL_Image, \
13
+ TmsTerrainProvidersNames
14
 
15
  models_dict = {"fastsam": {"instance": None}}
16
 
 
20
  prompt: list_dict,
21
  zoom: float,
22
  model_name: str = "fastsam",
23
+ source: str = DEFAULT_URL_TILES
24
  ) -> dict_str_int:
25
  """
26
  Return predictions as a geojson from a geo-referenced image using the given input prompt.
 
53
  pt0, pt1 = bbox
54
  app_logger.info(f"tile_source: {source}: downloading geo-referenced raster with bbox {bbox}, zoom {zoom}.")
55
  img, transform = download_extent(w=pt1[1], s=pt1[0], e=pt0[1], n=pt0[0], zoom=zoom, source=source)
56
+ if check_source_type_is_terrain(source):
57
+ app_logger.info(f"terrain-rgb like raster: transforms it into a DEM")
58
+ dem = get_raster_terrain_rgb_like(img, source.name)
59
+ # set a slope cell size proportional to the image width
60
+ slope_cellsize = int(img.shape[1] * SLOPE_CELLSIZE / DEFAULT_INPUT_SHAPE[1])
61
+ app_logger.info(f"terrain-rgb like raster: compute slope, curvature using {slope_cellsize} as cell size.")
62
+ img = get_rgb_prediction_image(dem, slope_cellsize)
63
+
64
  app_logger.info(
65
  f"img type {type(img)} with shape/size:{img.size}, transform type: {type(transform)}, transform:{transform}.")
66
 
samgis/prediction_api/sam_onnx.py CHANGED
@@ -29,14 +29,15 @@ from cv2 import INTER_LINEAR, warpAffine
29
  from onnxruntime import get_available_providers, InferenceSession
30
 
31
  from samgis import app_logger
 
32
 
33
 
34
  class SegmentAnythingONNX:
35
  """Segmentation model using SegmentAnything"""
36
 
37
  def __init__(self, encoder_model_path, decoder_model_path) -> None:
38
- self.target_size = 1024
39
- self.input_size = (684, 1024)
40
 
41
  # Load models
42
  providers = get_available_providers()
 
29
  from onnxruntime import get_available_providers, InferenceSession
30
 
31
  from samgis import app_logger
32
+ from samgis.utilities.constants import DEFAULT_INPUT_SHAPE
33
 
34
 
35
  class SegmentAnythingONNX:
36
  """Segmentation model using SegmentAnything"""
37
 
38
  def __init__(self, encoder_model_path, decoder_model_path) -> None:
39
+ self.target_size = DEFAULT_INPUT_SHAPE[1]
40
+ self.input_size = DEFAULT_INPUT_SHAPE
41
 
42
  # Load models
43
  providers = get_available_providers()
samgis/utilities/constants.py CHANGED
@@ -13,9 +13,6 @@ MODEL_ENCODER_NAME = "mobile_sam.encoder.onnx"
13
  MODEL_DECODER_NAME = "sam_vit_h_4b8939.decoder.onnx"
14
  TILE_SIZE = 256
15
  EARTH_EQUATORIAL_RADIUS = 6378137.0
16
- DEFAULT_TMS_NAME_SHORT = "openstreetmap"
17
- DEFAULT_TMS_NAME = "OpenStreetMap.Mapnik"
18
- DEFAULT_TMS = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'
19
  WKT_3857 = 'PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,'
20
  WKT_3857 += 'AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],'
21
  WKT_3857 += 'UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],'
@@ -33,3 +30,14 @@ N_WAIT = 0
33
  N_MAX_RETRIES = 2
34
  N_CONNECTION = 2
35
  ZOOM_AUTO = "auto"
 
 
 
 
 
 
 
 
 
 
 
 
13
  MODEL_DECODER_NAME = "sam_vit_h_4b8939.decoder.onnx"
14
  TILE_SIZE = 256
15
  EARTH_EQUATORIAL_RADIUS = 6378137.0
 
 
 
16
  WKT_3857 = 'PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,'
17
  WKT_3857 += 'AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],'
18
  WKT_3857 += 'UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],'
 
30
  N_MAX_RETRIES = 2
31
  N_CONNECTION = 2
32
  ZOOM_AUTO = "auto"
33
+ DEFAULT_URL_TILES = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'
34
+ DOMAIN_URL_TILES_MAPBOX = "api.mapbox.com"
35
+ RELATIVE_URL_TILES_MAPBOX = "v/mapbox.terrain-rgb/{zoom}/{x}/{y}{@2x}.pngraw?access_token={TOKEN}"
36
+ COMPLETE_URL_TILES_MAPBOX = f"https://{DOMAIN_URL_TILES_MAPBOX}/{RELATIVE_URL_TILES_MAPBOX}"
37
+ # https://s3.amazonaws.com/elevation-tiles-prod/terrarium/13/1308/3167.png
38
+ DOMAIN_URL_TILES_NEXTZEN = "s3.amazonaws.com"
39
+ RELATIVE_URL_TILES_NEXTZEN = "elevation-tiles-prod/terrarium/{z}/{x}/{y}.png" # "terrarium/{z}/{x}/{y}.png"
40
+ COMPLETE_URL_TILES_NEXTZEN = f"https://{DOMAIN_URL_TILES_NEXTZEN}/{RELATIVE_URL_TILES_NEXTZEN}"
41
+ CHANNEL_EXAGGERATIONS_LIST = [2.5, 1.1, 2.0]
42
+ DEFAULT_INPUT_SHAPE = 684, 1024
43
+ SLOPE_CELLSIZE = 61
samgis/utilities/type_hints.py CHANGED
@@ -1,5 +1,5 @@
1
  """custom type hints"""
2
- from enum import IntEnum, Enum
3
  from typing import TypedDict
4
 
5
  from PIL.Image import Image
@@ -7,8 +7,6 @@ from affine import Affine
7
  from numpy import ndarray
8
  from pydantic import BaseModel
9
 
10
- from samgis.utilities.constants import DEFAULT_TMS
11
-
12
 
13
  dict_str_int = dict[str, int]
14
  dict_str = dict[str]
@@ -25,6 +23,18 @@ PIL_Image = Image
25
  tuple_ndarray_transform = tuple[ndarray, Affine]
26
 
27
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  class LatLngDict(BaseModel):
29
  """Generic geographic latitude-longitude type"""
30
  lat: float
 
1
  """custom type hints"""
2
+ from enum import IntEnum, Enum, StrEnum
3
  from typing import TypedDict
4
 
5
  from PIL.Image import Image
 
7
  from numpy import ndarray
8
  from pydantic import BaseModel
9
 
 
 
10
 
11
  dict_str_int = dict[str, int]
12
  dict_str = dict[str]
 
23
  tuple_ndarray_transform = tuple[ndarray, Affine]
24
 
25
 
26
+ class TmsDefaultProvidersNames(StrEnum):
27
+ """Default xyz provider names"""
28
+ DEFAULT_TILES_NAME_SHORT = "openstreetmap"
29
+ DEFAULT_TILES_NAME = "openstreetmap.mapnik"
30
+
31
+
32
+ class TmsTerrainProvidersNames(StrEnum):
33
+ """Custom xyz provider names for digital elevation models"""
34
+ MAPBOX_TERRAIN_TILES_NAME = "mapbox.terrain-rgb"
35
+ NEXTZEN_TERRAIN_TILES_NAME = "nextzen.terrarium"
36
+
37
+
38
  class LatLngDict(BaseModel):
39
  """Generic geographic latitude-longitude type"""
40
  lat: float
wrappers/fastapi_wrapper.py CHANGED
@@ -7,7 +7,7 @@ from fastapi.responses import FileResponse, JSONResponse
7
  from fastapi.staticfiles import StaticFiles
8
 
9
  from samgis import app_logger
10
- from samgis.io.lambda_helpers import get_parsed_bbox_points
11
  from samgis.utilities.type_hints import ApiRequestBody
12
 
13
  app = FastAPI()
 
7
  from fastapi.staticfiles import StaticFiles
8
 
9
  from samgis import app_logger
10
+ from samgis.io.wrappers_helpers import get_parsed_bbox_points
11
  from samgis.utilities.type_hints import ApiRequestBody
12
 
13
  app = FastAPI()
wrappers/lambda_wrapper.py CHANGED
@@ -6,7 +6,7 @@ from aws_lambda_powertools.utilities.typing import LambdaContext
6
  from pydantic import ValidationError
7
 
8
  from samgis import app_logger
9
- from samgis.io.lambda_helpers import get_parsed_request_body, get_parsed_bbox_points, get_response
10
  from samgis.prediction_api.predictors import samexporter_predict
11
 
12
 
 
6
  from pydantic import ValidationError
7
 
8
  from samgis import app_logger
9
+ from samgis.io.wrappers_helpers import get_parsed_request_body, get_parsed_bbox_points, get_response
10
  from samgis.prediction_api.predictors import samexporter_predict
11
 
12