aletrn commited on
Commit
9271aef
·
1 Parent(s): 43d87b3

[feat] handle prompt point as lat-lng coordinates

Browse files
events/payload_point.json CHANGED
@@ -3,7 +3,7 @@
3
  "sw": {"lat": 30.1, "lng": 148.492},
4
  "prompt": [{
5
  "type": "point",
6
- "data": [500, 600],
7
  "label": 0
8
  }],
9
  "zoom": 6,
 
3
  "sw": {"lat": 30.1, "lng": 148.492},
4
  "prompt": [{
5
  "type": "point",
6
+ "data": {"lat": 36.91, "lng": 136.854},
7
  "label": 0
8
  }],
9
  "zoom": 6,
src/app.py CHANGED
@@ -7,6 +7,7 @@ from aws_lambda_powertools.event_handler import content_types
7
  from aws_lambda_powertools.utilities.typing import LambdaContext
8
 
9
  from src import app_logger
 
10
  from src.prediction_api.predictors import samexporter_predict
11
  from src.utilities.constants import CUSTOM_RESPONSE_MESSAGES
12
  from src.utilities.utilities import base64_decode
@@ -26,7 +27,7 @@ def get_response(status: int, start_time: float, request_id: str, response_body:
26
  str: json response
27
 
28
  """
29
- app_logger.info(f"response_body:{response_body}.")
30
  response_body["duration_run"] = time.time() - start_time
31
  response_body["message"] = CUSTOM_RESPONSE_MESSAGES[status]
32
  response_body["request_id"] = request_id
@@ -45,17 +46,27 @@ def get_parsed_bbox_points(request_input: Dict) -> Dict:
45
  app_logger.info(f"try to parsing input request {request_input}...")
46
  ne = request_input["ne"]
47
  sw = request_input["sw"]
48
- bbox = [
49
- [float(ne["lat"]), float(ne["lng"])],
50
- [float(sw["lat"]), float(sw["lng"])]
51
- ]
52
- app_logger.info(f"bbox {bbox}.")
53
-
54
- app_logger.info(f"unpacking {request_input}...")
 
 
 
 
 
 
 
 
 
 
55
  return {
56
  "bbox": bbox,
57
  "prompt": request_input["prompt"],
58
- "zoom": int(request_input["zoom"])
59
  }
60
 
61
 
@@ -67,8 +78,8 @@ def lambda_handler(event: dict, context: LambdaContext):
67
  app_logger.info(f"event version: {event['version']}.")
68
 
69
  try:
70
- app_logger.info(f"event:{json.dumps(event)}...")
71
- app_logger.info(f"context:{context}...")
72
 
73
  try:
74
  body = event["body"]
@@ -76,19 +87,19 @@ def lambda_handler(event: dict, context: LambdaContext):
76
  app_logger.error(f"e_constants1:{e_constants1}.")
77
  body = event
78
 
79
- app_logger.info(f"body: {type(body)}, {body}...")
80
 
81
  if isinstance(body, str):
82
  body_decoded_str = base64_decode(body)
83
- app_logger.info(f"body_decoded_str: {type(body_decoded_str)}, {body_decoded_str}...")
84
  body = json.loads(body_decoded_str)
85
 
86
- app_logger.info(f"body:{body}...")
87
 
88
  try:
89
  body_request = get_parsed_bbox_points(body)
90
  body_response = samexporter_predict(body_request["bbox"], body_request["prompt"], body_request["zoom"])
91
- app_logger.info(f"body_response::output:{body_response}.")
92
  response = get_response(HTTPStatus.OK.value, start_time, context.aws_request_id, body_response)
93
  except Exception as ex2:
94
  app_logger.error(f"exception2:{ex2}.")
 
7
  from aws_lambda_powertools.utilities.typing import LambdaContext
8
 
9
  from src import app_logger
10
+ from src.io.coordinates_pixel_conversion import get_point_latlng_to_pixel_coordinates, get_latlng_to_pixel_coordinates
11
  from src.prediction_api.predictors import samexporter_predict
12
  from src.utilities.constants import CUSTOM_RESPONSE_MESSAGES
13
  from src.utilities.utilities import base64_decode
 
27
  str: json response
28
 
29
  """
30
+ app_logger.debug(f"response_body:{response_body}.")
31
  response_body["duration_run"] = time.time() - start_time
32
  response_body["message"] = CUSTOM_RESPONSE_MESSAGES[status]
33
  response_body["request_id"] = request_id
 
46
  app_logger.info(f"try to parsing input request {request_input}...")
47
  ne = request_input["ne"]
48
  sw = request_input["sw"]
49
+ ne_latlng = [float(ne["lat"]), float(ne["lng"])]
50
+ sw_latlng = [float(sw["lat"]), float(sw["lng"])]
51
+ bbox = [ne_latlng, sw_latlng]
52
+ zoom = int(request_input["zoom"])
53
+ for prompt in request_input["prompt"]:
54
+ app_logger.info(f"current prompt: {type(prompt)}, value:{prompt}.")
55
+ data = prompt["data"]
56
+ app_logger.info(f"current data point: {type(data)}, value:{data}.")
57
+
58
+ diff_pixel_coordinates_ne = get_latlng_to_pixel_coordinates(ne, data, zoom)
59
+ app_logger.info(f'current data by current prompt["data"]: {type(data)}, {data} => {diff_pixel_coordinates_ne}.')
60
+ prompt["data"] = [diff_pixel_coordinates_ne["x"], diff_pixel_coordinates_ne["y"]]
61
+
62
+ app_logger.debug(f"bbox {bbox}.")
63
+ app_logger.debug(f'request_input["prompt"]:{request_input["prompt"]}.')
64
+
65
+ app_logger.info(f"unpacking elaborated {request_input}...")
66
  return {
67
  "bbox": bbox,
68
  "prompt": request_input["prompt"],
69
+ "zoom": zoom
70
  }
71
 
72
 
 
78
  app_logger.info(f"event version: {event['version']}.")
79
 
80
  try:
81
+ app_logger.debug(f"event:{json.dumps(event)}...")
82
+ app_logger.debug(f"context:{context}...")
83
 
84
  try:
85
  body = event["body"]
 
87
  app_logger.error(f"e_constants1:{e_constants1}.")
88
  body = event
89
 
90
+ app_logger.debug(f"body, #1: {type(body)}, {body}...")
91
 
92
  if isinstance(body, str):
93
  body_decoded_str = base64_decode(body)
94
+ app_logger.debug(f"body_decoded_str: {type(body_decoded_str)}, {body_decoded_str}...")
95
  body = json.loads(body_decoded_str)
96
 
97
+ app_logger.info(f"body, #2: {type(body)}, {body}...")
98
 
99
  try:
100
  body_request = get_parsed_bbox_points(body)
101
  body_response = samexporter_predict(body_request["bbox"], body_request["prompt"], body_request["zoom"])
102
+ app_logger.info(f"output body_response:{body_response}.")
103
  response = get_response(HTTPStatus.OK.value, start_time, context.aws_request_id, body_response)
104
  except Exception as ex2:
105
  app_logger.error(f"exception2:{ex2}.")
src/io/coordinates_pixel_conversion.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from typing import TypedDict, List
3
+
4
+ from src import app_logger
5
+ from src.utilities.constants import TILE_SIZE
6
+
7
+
8
+ class PixelCoordinate(TypedDict):
9
+ x: int
10
+ y: int
11
+
12
+
13
+ def get_latlng2pixel_projection(latlng) -> PixelCoordinate:
14
+ app_logger.info(f"latlng: {type(latlng)}, value:{latlng}.")
15
+ app_logger.info(f'latlng lat: {type(latlng["lat"])}, value:{latlng["lat"]}.')
16
+ app_logger.info(f'latlng lng: {type(latlng["lng"])}, value:{latlng["lng"]}.')
17
+ try:
18
+ sin_y: float = math.sin(latlng["lat"] * math.pi / 180)
19
+ app_logger.info(f"sin_y, #1:{sin_y}.")
20
+ sin_y = min(max(sin_y, -0.9999), 0.9999)
21
+ app_logger.info(f"sin_y, #2:{sin_y}.")
22
+ x = TILE_SIZE * (0.5 + latlng["lng"] / 360)
23
+ app_logger.info(f"x:{x}.")
24
+ y = TILE_SIZE * (0.5 - math.log((1 + sin_y) / (1 - sin_y)) / (4 * math.pi))
25
+ app_logger.info(f"y:{y}.")
26
+
27
+ return {"x": x, "y": y}
28
+ except Exception as e_get_latlng2pixel_projection:
29
+ app_logger.error(f'e_get_latlng2pixel_projection:{e_get_latlng2pixel_projection}.')
30
+ raise e_get_latlng2pixel_projection
31
+
32
+
33
+ def get_point_latlng_to_pixel_coordinates(latlng, zoom: int) -> PixelCoordinate:
34
+ try:
35
+ world_coordinate: PixelCoordinate = get_latlng2pixel_projection(latlng)
36
+ app_logger.debug(f"world_coordinate:{world_coordinate}.")
37
+ scale: int = pow(2, zoom)
38
+ app_logger.debug(f"scale:{scale}.")
39
+ return PixelCoordinate(
40
+ x=math.floor(world_coordinate["x"] * scale),
41
+ y=math.floor(world_coordinate["y"] * scale)
42
+ )
43
+ except Exception as e_format_latlng_to_pixel_coordinates:
44
+ app_logger.error(f'format_latlng_to_pixel_coordinates:{e_format_latlng_to_pixel_coordinates}.')
45
+ raise e_format_latlng_to_pixel_coordinates
46
+
47
+
48
+ def get_latlng_to_pixel_coordinates(latlng_origin, latlng_current_point, zoom):
49
+ latlng_map_origin = get_point_latlng_to_pixel_coordinates(latlng_origin, zoom)
50
+ latlng_map_current_point = get_point_latlng_to_pixel_coordinates(latlng_current_point, zoom)
51
+ diff_coord_x = abs(latlng_map_origin["x"] - latlng_map_current_point["x"])
52
+ diff_coord_y = abs(latlng_map_origin["y"] - latlng_map_current_point["y"])
53
+ return PixelCoordinate(x=diff_coord_x, y=diff_coord_y)
src/io/tms2geotiff.py CHANGED
@@ -14,19 +14,19 @@ import concurrent.futures
14
  from PIL import Image
15
  from PIL import TiffImagePlugin
16
 
 
17
  from src.utilities.constants import EARTH_EQUATORIAL_RADIUS, WKT_3857, DEFAULT_TMS
18
 
19
-
20
  Image.MAX_IMAGE_PIXELS = None
21
 
22
-
23
  try:
24
  import httpx
 
25
  SESSION = httpx.Client()
26
  except ImportError:
27
  import requests
28
- SESSION = requests.Session()
29
 
 
30
 
31
  SESSION.headers.update({
32
  "Accept": "*/*",
@@ -40,14 +40,14 @@ re_coords_split = re.compile('[ ,;]+')
40
  def from4326_to3857(lat, lon):
41
  xtile = math.radians(lon) * EARTH_EQUATORIAL_RADIUS
42
  ytile = math.log(math.tan(math.radians(45 + lat / 2.0))) * EARTH_EQUATORIAL_RADIUS
43
- return (xtile, ytile)
44
 
45
 
46
  def deg2num(lat, lon, zoom):
47
  n = 2 ** zoom
48
  xtile = ((lon + 180) / 360 * n)
49
  ytile = (1 - math.asinh(math.tan(math.radians(lat))) / math.pi) * n / 2
50
- return (xtile, ytile)
51
 
52
 
53
  def is_empty(im):
@@ -69,12 +69,12 @@ def mbtiles_init(dbname):
69
  cur.execute("BEGIN")
70
  cur.execute("CREATE TABLE IF NOT EXISTS metadata (name TEXT PRIMARY KEY, value TEXT)")
71
  cur.execute("CREATE TABLE IF NOT EXISTS tiles ("
72
- "zoom_level INTEGER NOT NULL, "
73
- "tile_column INTEGER NOT NULL, "
74
- "tile_row INTEGER NOT NULL, "
75
- "tile_data BLOB NOT NULL, "
76
- "UNIQUE (zoom_level, tile_column, tile_row)"
77
- ")")
78
  cur.execute("COMMIT")
79
  return db
80
 
@@ -89,13 +89,13 @@ def paste_tile(bigim, base_size, tile, corner_xy, bbox):
89
  base_size[0] = size[0]
90
  base_size[1] = size[1]
91
  newim = Image.new(mode, (
92
- size[0]*(bbox[2]-bbox[0]), size[1]*(bbox[3]-bbox[1])))
93
  else:
94
  newim = bigim
95
 
96
  dx = abs(corner_xy[0] - bbox[0])
97
  dy = abs(corner_xy[1] - bbox[1])
98
- xy0 = (size[0]*dx, size[1]*dy)
99
  if mode == 'RGB':
100
  newim.paste(im, xy0)
101
  else:
@@ -113,7 +113,8 @@ def get_tile(url):
113
  try:
114
  r = SESSION.get(url, timeout=60)
115
  break
116
- except Exception:
 
117
  retry -= 1
118
  if not retry:
119
  raise
@@ -127,7 +128,7 @@ def get_tile(url):
127
 
128
  def print_progress(progress, total, done=False):
129
  if done:
130
- print('Downloaded image %d/%d, %.2f%%' % (progress, total, progress*100/total))
131
 
132
 
133
  class ProgressBar:
@@ -175,7 +176,7 @@ def mbtiles_save(db, img_data, xy, zoom, img_format):
175
  else:
176
  current_format = 'image/' + im.format.lower()
177
  x, y = xy
178
- y = 2**zoom - 1 - y
179
  cur = db.cursor()
180
  if img_format is None or img_format == current_format:
181
  cur.execute("REPLACE INTO tiles VALUES (?,?,?,?)", (
@@ -196,10 +197,10 @@ def mbtiles_save(db, img_data, xy, zoom, img_format):
196
 
197
 
198
  def download_extent(
199
- source, lat0, lon0, lat1, lon1, zoom,
200
- mbtiles=None, save_image=True,
201
- progress_callback=print_progress,
202
- callback_interval=0.05
203
  ):
204
  x0, y0 = deg2num(lat0, lon0, zoom)
205
  x1, y1 = deg2num(lat1, lon1, zoom)
@@ -241,7 +242,7 @@ def download_extent(
241
  cur.execute("REPLACE INTO metadata VALUES ('bounds', ?)", (
242
  ",".join(map(str, bounds)),))
243
  cur.execute("REPLACE INTO metadata VALUES ('center', ?)", ("%s,%s,%d" % (
244
- (lon_max + lon_min)/2, (lat_max + lat_min)/2, zoom),))
245
  cur.execute("""
246
  INSERT INTO metadata VALUES ('minzoom', ?)
247
  ON CONFLICT(name) DO UPDATE SET value=excluded.value
@@ -267,7 +268,7 @@ def download_extent(
267
  with concurrent.futures.ThreadPoolExecutor(5) as executor:
268
  for x, y in corners:
269
  future = executor.submit(get_tile, source.format(z=zoom, x=x, y=y))
270
- futures[future] = (x, y)
271
  bbox = (math.floor(x0), math.floor(y0), math.ceil(x1), math.ceil(y1))
272
  bigim = None
273
  base_size = [256, 256]
@@ -316,11 +317,11 @@ def download_extent(
316
 
317
  xfrac = x0 - bbox[0]
318
  yfrac = y0 - bbox[1]
319
- x2 = round(base_size[0]*xfrac)
320
- y2 = round(base_size[1]*yfrac)
321
- imgw = round(base_size[0]*(x1-x0))
322
- imgh = round(base_size[1]*(y1-y0))
323
- retim = bigim.crop((x2, y2, x2+imgw, y2+imgh))
324
  if retim.mode == 'RGBA' and retim.getextrema()[3] == (255, 255):
325
  retim = retim.convert('RGB')
326
  bigim.close()
@@ -411,7 +412,7 @@ def save_image_fn(img, filename, matrix, **params):
411
  elif ext == '.png':
412
  img_params['optimize'] = True
413
  elif ext.startswith('.tif'):
414
- if img_memorysize(img) >= 4*1024*1024*1024:
415
  # BigTIFF
416
  return save_geotiff_gdal(img, filename, matrix)
417
  img_params['compression'] = 'tiff_adobe_deflate'
@@ -437,14 +438,14 @@ def save_geotiff_gdal(img, filename, matrix):
437
  imgbands = len(img.getbands())
438
  driver = gdal.GetDriverByName('GTiff')
439
  gdal_options = ['COMPRESS=DEFLATE', 'PREDICTOR=2', 'ZLEVEL=9', 'TILED=YES']
440
- if img_memorysize(img) >= 4*1024*1024*1024:
441
  gdal_options.append('BIGTIFF=YES')
442
- if img_memorysize(img) >= 50*1024*1024:
443
  gdal_options.append('NUM_THREADS=%d' % max(1, os.cpu_count()))
444
 
445
  gtiff = driver.Create(filename, img.size[0], img.size[1],
446
- imgbands, gdal.GDT_Byte,
447
- options=gdal_options)
448
  gtiff.SetGeoTransform(matrix)
449
  gtiff.SetProjection(WKT_3857)
450
  for band in range(imgbands):
@@ -589,12 +590,12 @@ def gui():
589
  return
590
  root_tk.update()
591
  try:
592
- img, matrix = download_extent(
593
  *args, progress_callback=update_progress, **kwargs)
594
  b_download.configure(text='Saving...', state='disabled')
595
  root_tk.update()
596
  if filename:
597
- save_image_auto(img, filename, matrix)
598
  reset()
599
  except TaskCancelled:
600
  reset()
@@ -632,7 +633,6 @@ def gui():
632
 
633
 
634
  def downloader(input_args, input_parser):
635
-
636
  download_args = [input_args.source]
637
  try:
638
  if input_args.extent:
@@ -652,11 +652,11 @@ def downloader(input_args, input_parser):
652
  download_args.append(bool(input_args.output))
653
  progress_bar = ProgressBar()
654
  download_args.append(progress_bar.print_progress)
655
- img, matrix = download_extent(*download_args)
656
  progress_bar.close()
657
  if input_args.output:
658
  print(f"Saving image to {input_args.output}.")
659
- save_image_auto(img, input_args.output, matrix)
660
  return 0
661
 
662
 
@@ -670,8 +670,8 @@ def main():
670
  parser.add_argument("-f", "--from", metavar='LAT,LON', help="one corner")
671
  parser.add_argument("-t", "--to", metavar='LAT,LON', help="the other corner")
672
  parser.add_argument("-e", "--extent",
673
- metavar='min_lon,min_lat,max_lon,max_lat',
674
- help="extent in one string (use either -e, or -f and -t)")
675
  parser.add_argument("-z", "--zoom", type=int, help="zoom level")
676
  parser.add_argument("-m", "--mbtiles", help="save MBTiles file")
677
  parser.add_argument("-g", "--gui", action='store_true', help="show GUI")
@@ -690,8 +690,8 @@ if __name__ == '__main__':
690
  # sys.exit(main())
691
  pt0 = 45.699, 127.1
692
  pt1 = 30.1, 148.492
693
- img_output_filename = "/Users/trincuz/workspace/segment-geospatial/tmp/japan_out_main.png"
694
- img, matrix = download_extent(DEFAULT_TMS, pt0[0], pt0[1], pt1[0], pt1[1], 6)
695
 
696
- print(f"Saving image to {img_output_filename}.")
697
- save_image_auto(img, img_output_filename, matrix)
 
14
  from PIL import Image
15
  from PIL import TiffImagePlugin
16
 
17
+ from src import PROJECT_ROOT_FOLDER, app_logger
18
  from src.utilities.constants import EARTH_EQUATORIAL_RADIUS, WKT_3857, DEFAULT_TMS
19
 
 
20
  Image.MAX_IMAGE_PIXELS = None
21
 
 
22
  try:
23
  import httpx
24
+
25
  SESSION = httpx.Client()
26
  except ImportError:
27
  import requests
 
28
 
29
+ SESSION = requests.Session()
30
 
31
  SESSION.headers.update({
32
  "Accept": "*/*",
 
40
  def from4326_to3857(lat, lon):
41
  xtile = math.radians(lon) * EARTH_EQUATORIAL_RADIUS
42
  ytile = math.log(math.tan(math.radians(45 + lat / 2.0))) * EARTH_EQUATORIAL_RADIUS
43
+ return xtile, ytile
44
 
45
 
46
  def deg2num(lat, lon, zoom):
47
  n = 2 ** zoom
48
  xtile = ((lon + 180) / 360 * n)
49
  ytile = (1 - math.asinh(math.tan(math.radians(lat))) / math.pi) * n / 2
50
+ return xtile, ytile
51
 
52
 
53
  def is_empty(im):
 
69
  cur.execute("BEGIN")
70
  cur.execute("CREATE TABLE IF NOT EXISTS metadata (name TEXT PRIMARY KEY, value TEXT)")
71
  cur.execute("CREATE TABLE IF NOT EXISTS tiles ("
72
+ "zoom_level INTEGER NOT NULL, "
73
+ "tile_column INTEGER NOT NULL, "
74
+ "tile_row INTEGER NOT NULL, "
75
+ "tile_data BLOB NOT NULL, "
76
+ "UNIQUE (zoom_level, tile_column, tile_row)"
77
+ ")")
78
  cur.execute("COMMIT")
79
  return db
80
 
 
89
  base_size[0] = size[0]
90
  base_size[1] = size[1]
91
  newim = Image.new(mode, (
92
+ size[0] * (bbox[2] - bbox[0]), size[1] * (bbox[3] - bbox[1])))
93
  else:
94
  newim = bigim
95
 
96
  dx = abs(corner_xy[0] - bbox[0])
97
  dy = abs(corner_xy[1] - bbox[1])
98
+ xy0 = (size[0] * dx, size[1] * dy)
99
  if mode == 'RGB':
100
  newim.paste(im, xy0)
101
  else:
 
113
  try:
114
  r = SESSION.get(url, timeout=60)
115
  break
116
+ except Exception as request_tile_exception:
117
+ app_logger.error(f"retry {retry}, request_tile_exception:{request_tile_exception}.")
118
  retry -= 1
119
  if not retry:
120
  raise
 
128
 
129
  def print_progress(progress, total, done=False):
130
  if done:
131
+ print('Downloaded image %d/%d, %.2f%%' % (progress, total, progress * 100 / total))
132
 
133
 
134
  class ProgressBar:
 
176
  else:
177
  current_format = 'image/' + im.format.lower()
178
  x, y = xy
179
+ y = 2 ** zoom - 1 - y
180
  cur = db.cursor()
181
  if img_format is None or img_format == current_format:
182
  cur.execute("REPLACE INTO tiles VALUES (?,?,?,?)", (
 
197
 
198
 
199
  def download_extent(
200
+ source, lat0, lon0, lat1, lon1, zoom,
201
+ mbtiles=None, save_image=True,
202
+ progress_callback=print_progress,
203
+ callback_interval=0.05
204
  ):
205
  x0, y0 = deg2num(lat0, lon0, zoom)
206
  x1, y1 = deg2num(lat1, lon1, zoom)
 
242
  cur.execute("REPLACE INTO metadata VALUES ('bounds', ?)", (
243
  ",".join(map(str, bounds)),))
244
  cur.execute("REPLACE INTO metadata VALUES ('center', ?)", ("%s,%s,%d" % (
245
+ (lon_max + lon_min) / 2, (lat_max + lat_min) / 2, zoom),))
246
  cur.execute("""
247
  INSERT INTO metadata VALUES ('minzoom', ?)
248
  ON CONFLICT(name) DO UPDATE SET value=excluded.value
 
268
  with concurrent.futures.ThreadPoolExecutor(5) as executor:
269
  for x, y in corners:
270
  future = executor.submit(get_tile, source.format(z=zoom, x=x, y=y))
271
+ futures[future] = (x, y)
272
  bbox = (math.floor(x0), math.floor(y0), math.ceil(x1), math.ceil(y1))
273
  bigim = None
274
  base_size = [256, 256]
 
317
 
318
  xfrac = x0 - bbox[0]
319
  yfrac = y0 - bbox[1]
320
+ x2 = round(base_size[0] * xfrac)
321
+ y2 = round(base_size[1] * yfrac)
322
+ imgw = round(base_size[0] * (x1 - x0))
323
+ imgh = round(base_size[1] * (y1 - y0))
324
+ retim = bigim.crop((x2, y2, x2 + imgw, y2 + imgh))
325
  if retim.mode == 'RGBA' and retim.getextrema()[3] == (255, 255):
326
  retim = retim.convert('RGB')
327
  bigim.close()
 
412
  elif ext == '.png':
413
  img_params['optimize'] = True
414
  elif ext.startswith('.tif'):
415
+ if img_memorysize(img) >= 4 * 1024 * 1024 * 1024:
416
  # BigTIFF
417
  return save_geotiff_gdal(img, filename, matrix)
418
  img_params['compression'] = 'tiff_adobe_deflate'
 
438
  imgbands = len(img.getbands())
439
  driver = gdal.GetDriverByName('GTiff')
440
  gdal_options = ['COMPRESS=DEFLATE', 'PREDICTOR=2', 'ZLEVEL=9', 'TILED=YES']
441
+ if img_memorysize(img) >= 4 * 1024 * 1024 * 1024:
442
  gdal_options.append('BIGTIFF=YES')
443
+ if img_memorysize(img) >= 50 * 1024 * 1024:
444
  gdal_options.append('NUM_THREADS=%d' % max(1, os.cpu_count()))
445
 
446
  gtiff = driver.Create(filename, img.size[0], img.size[1],
447
+ imgbands, gdal.GDT_Byte,
448
+ options=gdal_options)
449
  gtiff.SetGeoTransform(matrix)
450
  gtiff.SetProjection(WKT_3857)
451
  for band in range(imgbands):
 
590
  return
591
  root_tk.update()
592
  try:
593
+ img, matrix_projection = download_extent(
594
  *args, progress_callback=update_progress, **kwargs)
595
  b_download.configure(text='Saving...', state='disabled')
596
  root_tk.update()
597
  if filename:
598
+ save_image_auto(img, filename, matrix_projection)
599
  reset()
600
  except TaskCancelled:
601
  reset()
 
633
 
634
 
635
  def downloader(input_args, input_parser):
 
636
  download_args = [input_args.source]
637
  try:
638
  if input_args.extent:
 
652
  download_args.append(bool(input_args.output))
653
  progress_bar = ProgressBar()
654
  download_args.append(progress_bar.print_progress)
655
+ img_geo, matrix = download_extent(*download_args)
656
  progress_bar.close()
657
  if input_args.output:
658
  print(f"Saving image to {input_args.output}.")
659
+ save_image_auto(img_geo, input_args.output, matrix)
660
  return 0
661
 
662
 
 
670
  parser.add_argument("-f", "--from", metavar='LAT,LON', help="one corner")
671
  parser.add_argument("-t", "--to", metavar='LAT,LON', help="the other corner")
672
  parser.add_argument("-e", "--extent",
673
+ metavar='min_lon,min_lat,max_lon,max_lat',
674
+ help="extent in one string (use either -e, or -f and -t)")
675
  parser.add_argument("-z", "--zoom", type=int, help="zoom level")
676
  parser.add_argument("-m", "--mbtiles", help="save MBTiles file")
677
  parser.add_argument("-g", "--gui", action='store_true', help="show GUI")
 
690
  # sys.exit(main())
691
  pt0 = 45.699, 127.1
692
  pt1 = 30.1, 148.492
693
+ geo_img_output_filename = PROJECT_ROOT_FOLDER / "tmp" / "japan_out_main.png"
694
+ geo_img, projection_matrix = download_extent(DEFAULT_TMS, pt0[0], pt0[1], pt1[0], pt1[1], 6)
695
 
696
+ print(f"Saving image to {geo_img_output_filename}.")
697
+ save_image_auto(geo_img, geo_img_output_filename, projection_matrix)
src/prediction_api/predictors.py CHANGED
@@ -62,7 +62,7 @@ def samexporter_predict(bbox: input_float_tuples, prompt: list[dict], zoom: floa
62
  models_instance = models_dict[model_name]["instance"]
63
 
64
  for coord in bbox:
65
- app_logger.info(f"bbox coord:{coord}, type:{type(coord)}.")
66
  app_logger.info(f"start download_extent using bbox:{bbox}, type:{type(bbox)}, download image...")
67
 
68
  pt0 = bbox[0]
@@ -70,30 +70,28 @@ def samexporter_predict(bbox: input_float_tuples, prompt: list[dict], zoom: floa
70
  img, matrix = download_extent(DEFAULT_TMS, pt0[0], pt0[1], pt1[0], pt1[1], zoom)
71
 
72
  app_logger.info(f"img type {type(img)}, matrix type {type(matrix)}.")
73
- app_logger.info(f"matrix values: {serialize(matrix)}.")
74
  np_img = np.array(img)
75
- app_logger.info(f"np_img type {type(np_img)}.")
76
- app_logger.info(f"np_img dtype {np_img.dtype}, shape {np_img.shape}.")
77
  app_logger.info(f"geotiff created with size/shape {img.size} and transform matrix {str(matrix)}, start to initialize SamGeo instance:")
78
- app_logger.info(f"use fastsam_model, ENCODER model {MODEL_ENCODER_NAME} and {MODEL_DECODER_NAME} from {MODEL_FOLDER})...")
79
-
80
- app_logger.info(f"model instantiated, creating embedding...")
81
  embedding = models_instance.encode(np_img)
82
  app_logger.info(f"embedding created, running predict_masks...")
83
  prediction_masks = models_instance.predict_masks(embedding, prompt)
84
- app_logger.info(f"predict_masks terminated")
85
- app_logger.info(f"prediction masks shape:{prediction_masks.shape}, {prediction_masks.dtype}.")
86
 
87
  mask = np.zeros((prediction_masks.shape[2], prediction_masks.shape[3]), dtype=np.uint8)
88
  for m in prediction_masks[0, :, :, :]:
89
  mask[m > 0.0] = 255
90
 
91
  mask_unique_values, mask_unique_values_count = serialize(np.unique(mask, return_counts=True))
92
- app_logger.info(f"mask_unique_values:{mask_unique_values}.")
93
- app_logger.info(f"mask_unique_values_count:{mask_unique_values_count}.")
94
 
95
  transform = load_affine_transformation_from_matrix(matrix)
96
- app_logger.info(f"image/geojson origin matrix:{matrix}, transform:{transform}.")
97
  shapes_generator = ({
98
  'properties': {'raster_val': v}, 'geometry': s}
99
  for i, (s, v)
 
62
  models_instance = models_dict[model_name]["instance"]
63
 
64
  for coord in bbox:
65
+ app_logger.debug(f"bbox coord:{coord}, type:{type(coord)}.")
66
  app_logger.info(f"start download_extent using bbox:{bbox}, type:{type(bbox)}, download image...")
67
 
68
  pt0 = bbox[0]
 
70
  img, matrix = download_extent(DEFAULT_TMS, pt0[0], pt0[1], pt1[0], pt1[1], zoom)
71
 
72
  app_logger.info(f"img type {type(img)}, matrix type {type(matrix)}.")
73
+ app_logger.debug(f"matrix values: {serialize(matrix)}.")
74
  np_img = np.array(img)
75
+ app_logger.debug(f"np_img type {type(np_img)}.")
76
+ app_logger.debug(f"np_img dtype {np_img.dtype}, shape {np_img.shape}.")
77
  app_logger.info(f"geotiff created with size/shape {img.size} and transform matrix {str(matrix)}, start to initialize SamGeo instance:")
78
+ app_logger.info(f"use {model_name} model, ENCODER model {MODEL_ENCODER_NAME} and {MODEL_DECODER_NAME} from {MODEL_FOLDER}): model instantiated, creating embedding...")
 
 
79
  embedding = models_instance.encode(np_img)
80
  app_logger.info(f"embedding created, running predict_masks...")
81
  prediction_masks = models_instance.predict_masks(embedding, prompt)
82
+ app_logger.debug(f"predict_masks terminated...")
83
+ app_logger.info(f"predict_masks terminated, prediction masks shape:{prediction_masks.shape}, {prediction_masks.dtype}.")
84
 
85
  mask = np.zeros((prediction_masks.shape[2], prediction_masks.shape[3]), dtype=np.uint8)
86
  for m in prediction_masks[0, :, :, :]:
87
  mask[m > 0.0] = 255
88
 
89
  mask_unique_values, mask_unique_values_count = serialize(np.unique(mask, return_counts=True))
90
+ app_logger.debug(f"mask_unique_values:{mask_unique_values}.")
91
+ app_logger.debug(f"mask_unique_values_count:{mask_unique_values_count}.")
92
 
93
  transform = load_affine_transformation_from_matrix(matrix)
94
+ app_logger.info(f"image/geojson origin matrix:{matrix}, transform:{transform}: create shapes_generator...")
95
  shapes_generator = ({
96
  'properties': {'raster_val': v}, 'geometry': s}
97
  for i, (s, v)
src/utilities/constants.py CHANGED
@@ -26,7 +26,10 @@ MODEL_ENCODER_NAME = "mobile_sam.encoder.onnx"
26
  MODEL_DECODER_NAME = "sam_vit_h_4b8939.decoder.onnx"
27
  ZOOM = 13
28
  SOURCE_TYPE = "Satellite"
29
-
30
  EARTH_EQUATORIAL_RADIUS = 6378137.0
31
  DEFAULT_TMS = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'
32
- WKT_3857 = 'PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH],EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"],AUTHORITY["EPSG","3857"]]'
 
 
 
 
26
  MODEL_DECODER_NAME = "sam_vit_h_4b8939.decoder.onnx"
27
  ZOOM = 13
28
  SOURCE_TYPE = "Satellite"
29
+ TILE_SIZE = 256
30
  EARTH_EQUATORIAL_RADIUS = 6378137.0
31
  DEFAULT_TMS = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'
32
+ WKT_3857 = 'PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,'
33
+ WKT_3857 += 'AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],'
34
+ WKT_3857 += 'PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH],EXTENSION["PROJ4",'
35
+ WKT_3857 += '"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"],AUTHORITY["EPSG","3857"]]'