aletrn commited on
Commit
2f5b9e0
·
1 Parent(s): 6978dd2

[debug] add geopandas and rasterio to convert the FastSAM mask prediction into a geojson

Browse files
requirements.txt CHANGED
@@ -6,4 +6,6 @@ jmespath
6
  numpy
7
  onnxruntime
8
  opencv-python
9
- pillow
 
 
 
6
  numpy
7
  onnxruntime
8
  opencv-python
9
+ pillow
10
+ rasterio
11
+ geopandas
requirements_dev.txt CHANGED
@@ -6,4 +6,6 @@ jmespath
6
  numpy
7
  onnxruntime
8
  opencv-python
9
- pillow
 
 
 
6
  numpy
7
  onnxruntime
8
  opencv-python
9
+ pillow
10
+ rasterio
11
+ geopandas
src/app.py CHANGED
@@ -51,13 +51,6 @@ def lambda_handler(event: dict, context: LambdaContext):
51
  app_logger.info(f"context:{context}...")
52
 
53
  try:
54
- """
55
- img, matrix = download_extent(DEFAULT_TMS, pt0[0], pt0[1], pt1[0], pt1[1], 6)
56
- model_path = Path(MODEL_FOLDER) / "mobile_sam.encoder.onnx"
57
- model_path_isfile = model_path.is_file()
58
- model_path_stats = model_path.stat()
59
- app_logger.info(f"model_path:{model_path_isfile}, {model_path_stats}.")
60
- """
61
  pt0 = 45.699, 127.1
62
  pt1 = 30.1, 148.492
63
  bbox = [pt0, pt1]
 
51
  app_logger.info(f"context:{context}...")
52
 
53
  try:
 
 
 
 
 
 
 
54
  pt0 = 45.699, 127.1
55
  pt1 = 30.1, 148.492
56
  bbox = [pt0, pt1]
src/main.py CHANGED
@@ -1,57 +1,14 @@
1
- from typing import Dict
 
2
 
3
- from geojson_pydantic import Feature, Polygon, FeatureCollection
4
- from pydantic import BaseModel
5
-
6
- g1 = {
7
- "type": "FeatureCollection",
8
- "features": [{
9
- "type": "Feature",
10
- "geometry": {
11
- "type": "Polygon",
12
- "coordinates": [
13
- [
14
- [13.1, 52.46385],
15
- [13.42786, 52.6],
16
- [13.2, 52.5],
17
- [13.38272, 52.4],
18
- [13.43, 52.46385],
19
- [13.1, 52.46385]
20
- ]
21
- ],
22
- },
23
- "properties": {
24
- "name": "uno",
25
- },
26
- }, {
27
- "type": "Feature",
28
- "geometry": {
29
- "type": "Polygon",
30
- "coordinates": [
31
- [
32
- [13.77, 52.8],
33
- [13.88, 52.77],
34
- [13.99, 52.66],
35
- [13.11, 52.55],
36
- [13.33, 52.44],
37
- [13.77, 52.8]
38
- ]
39
- ],
40
- },
41
- "properties": {
42
- "name": "due",
43
- },
44
- }]
45
- }
46
-
47
- PolygonFeatureCollectionModel = FeatureCollection[Feature[Polygon, Dict]]
48
 
49
  if __name__ == '__main__':
50
- feat = PolygonFeatureCollectionModel(**g1)
51
- print(feat)
52
- print("feat")
53
- """
54
-
55
- point: {"lat":12.425847783029134,"lng":53.887939453125}
56
- map:ne:{"lat":17.895114303749143,"lng":58.27148437500001} sw:{"lat":0.6591651462894632,"lng":34.01367187500001}.
57
- """
 
1
+ import rasterio
2
+ from affine import loadsw
3
 
4
+ from src import PROJECT_ROOT_FOLDER
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
  if __name__ == '__main__':
7
+ with open(PROJECT_ROOT_FOLDER / "tmp" / "japan_out_main.pgw") as pgw:
8
+ pgw_file = pgw.read()
9
+ a = loadsw(pgw_file)
10
+ with rasterio.open(PROJECT_ROOT_FOLDER / "tmp" / "japan_out_main.png", "r") as src:
11
+ src_transform = src.transform
12
+ print(a, src_transform)
13
+ print(a, src_transform)
14
+ print("a, src_tranform")
src/prediction_api/predictors.py CHANGED
@@ -1,5 +1,7 @@
1
  # Press the green button in the gutter to run the script.
2
  import os
 
 
3
  import numpy as np
4
 
5
  from src import app_logger, MODEL_FOLDER
@@ -8,7 +10,6 @@ from src.prediction_api.sam_onnx import SegmentAnythingONNX
8
  from src.utilities.constants import ROOT, MODEL_ENCODER_NAME, ZOOM, SOURCE_TYPE, DEFAULT_TMS, MODEL_DECODER_NAME
9
  from src.utilities.serialize import serialize
10
  from src.utilities.type_hints import input_float_tuples
11
- from src.utilities.utilities import get_system_info
12
 
13
 
14
  def zip_arrays(arr1, arr2):
@@ -16,7 +17,7 @@ def zip_arrays(arr1, arr2):
16
  arr2_list = arr2.tolist()
17
  # return {serialize(k): serialize(v) for k, v in zip(arr1_list, arr2_list)}
18
  d = {}
19
- for n1, n2 in enumerate(zip(arr1_list, arr2_list)):
20
  app_logger.info(f"n1:{n1}, type {type(n1)}, n2:{n2}, type {type(n2)}.")
21
  n1f = str(n1)
22
  n2f = str(n2)
@@ -26,57 +27,82 @@ def zip_arrays(arr1, arr2):
26
  return d
27
 
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  def samexporter_predict(bbox: input_float_tuples, prompt: list[dict], zoom: float = ZOOM) -> dict:
30
  import tempfile
31
 
32
  try:
33
- os.environ['MPLCONFIGDIR'] = ROOT
34
- get_system_info()
35
- except Exception as e:
36
- app_logger.error(f"Error while setting 'MPLCONFIGDIR':{e}.")
37
-
38
- with tempfile.NamedTemporaryFile(prefix=f"{SOURCE_TYPE}_", suffix=".tif", dir=ROOT) as image_input_tmp:
39
- for coord in bbox:
40
- app_logger.info(f"bbox coord:{coord}, type:{type(coord)}.")
41
- app_logger.info(f"start download_extent using bbox:{bbox}, type:{type(bbox)}, download image...")
42
-
43
- pt0 = bbox[0]
44
- pt1 = bbox[1]
45
- img, matrix = download_extent(DEFAULT_TMS, pt0[0], pt0[1], pt1[0], pt1[1], zoom)
46
-
47
- app_logger.info(f"img type {type(img)}, matrix type {type(matrix)}.")
48
- np_img = np.array(img)
49
- app_logger.info(f"np_img type {type(np_img)}.")
50
- app_logger.info(f"np_img dtype {np_img.dtype}, shape {np_img.shape}.")
51
- app_logger.info(f"geotiff created with size/shape {img.size} and transform matrix {str(matrix)}, start to initialize SamGeo instance:")
52
- app_logger.info(f"use ENCODER model {MODEL_ENCODER_NAME} from {MODEL_FOLDER})...")
53
- app_logger.info(f"use DECODER model {MODEL_DECODER_NAME} from {MODEL_FOLDER})...")
54
-
55
- model = SegmentAnythingONNX(
56
- encoder_model_path=MODEL_FOLDER / MODEL_ENCODER_NAME,
57
- decoder_model_path=MODEL_FOLDER / MODEL_DECODER_NAME
58
- )
59
- app_logger.info(f"model instantiated, creating embedding...")
60
- embedding = model.encode(np_img)
61
- app_logger.info(f"embedding created, running predict_masks...")
62
- prediction_masks = model.predict_masks(embedding, prompt)
63
- app_logger.info(f"predict_masks terminated")
64
- app_logger.info(f"prediction masks shape:{prediction_masks.shape}, {prediction_masks.dtype}.")
65
-
66
- mask = np.zeros((prediction_masks.shape[2], prediction_masks.shape[3]), dtype=np.uint8)
67
- for m in prediction_masks[0, :, :, :]:
68
- mask[m > 0.0] = 255
69
-
70
- mask_unique_values, mask_unique_values_count = serialize(np.unique(mask, return_counts=True))
71
- app_logger.info(f"mask_unique_values:{mask_unique_values}.")
72
- app_logger.info(f"mask_unique_values_count:{mask_unique_values_count}.")
73
-
74
- output = {
75
- "img_size": serialize(img.size),
76
- "mask_unique_values_count": zip_arrays(mask_unique_values, mask_unique_values_count),
77
- "masks_dtype": serialize(prediction_masks.dtype),
78
- "masks_shape": serialize(prediction_masks.shape),
79
- "matrix": serialize(matrix)
80
- }
81
- app_logger.info(f"output:{output}.")
82
- return output
 
 
 
 
 
 
 
 
 
 
 
 
1
  # Press the green button in the gutter to run the script.
2
  import os
3
+ from typing import List
4
+
5
  import numpy as np
6
 
7
  from src import app_logger, MODEL_FOLDER
 
10
  from src.utilities.constants import ROOT, MODEL_ENCODER_NAME, ZOOM, SOURCE_TYPE, DEFAULT_TMS, MODEL_DECODER_NAME
11
  from src.utilities.serialize import serialize
12
  from src.utilities.type_hints import input_float_tuples
 
13
 
14
 
15
  def zip_arrays(arr1, arr2):
 
17
  arr2_list = arr2.tolist()
18
  # return {serialize(k): serialize(v) for k, v in zip(arr1_list, arr2_list)}
19
  d = {}
20
+ for n1, n2 in zip(arr1_list, arr2_list):
21
  app_logger.info(f"n1:{n1}, type {type(n1)}, n2:{n2}, type {type(n2)}.")
22
  n1f = str(n1)
23
  n2f = str(n2)
 
27
  return d
28
 
29
 
30
+ def load_affine_transformation_from_matrix(matrix_source_coeffs: List):
31
+ from affine import Affine
32
+
33
+ if len(matrix_source_coeffs) != 6:
34
+ raise ValueError(f"Expected 6 coefficients, found {len(matrix_source_coeffs)}; argument type: {type(matrix_source_coeffs)}.")
35
+
36
+ try:
37
+ a, d, b, e, c, f = (float(x) for x in matrix_source_coeffs)
38
+ center = tuple.__new__(Affine, [a, b, c, d, e, f, 0.0, 0.0, 1.0])
39
+ return center * Affine.translation(-0.5, -0.5)
40
+ except Exception as e:
41
+ app_logger.error(f"exception:{e}, check https://github.com/rasterio/affine project for updates")
42
+
43
+
44
  def samexporter_predict(bbox: input_float_tuples, prompt: list[dict], zoom: float = ZOOM) -> dict:
45
  import tempfile
46
 
47
  try:
48
+ from rasterio.features import shapes
49
+ from geopandas import GeoDataFrame
50
+
51
+ with tempfile.NamedTemporaryFile(prefix=f"{SOURCE_TYPE}_", suffix=".tif", dir=ROOT) as image_input_tmp:
52
+ for coord in bbox:
53
+ app_logger.info(f"bbox coord:{coord}, type:{type(coord)}.")
54
+ app_logger.info(f"start download_extent using bbox:{bbox}, type:{type(bbox)}, download image...")
55
+
56
+ pt0 = bbox[0]
57
+ pt1 = bbox[1]
58
+ img, matrix = download_extent(DEFAULT_TMS, pt0[0], pt0[1], pt1[0], pt1[1], zoom)
59
+
60
+ app_logger.info(f"img type {type(img)}, matrix type {type(matrix)}.")
61
+ app_logger.info(f"matrix values: {serialize(matrix)}.")
62
+ np_img = np.array(img)
63
+ app_logger.info(f"np_img type {type(np_img)}.")
64
+ app_logger.info(f"np_img dtype {np_img.dtype}, shape {np_img.shape}.")
65
+ app_logger.info(f"geotiff created with size/shape {img.size} and transform matrix {str(matrix)}, start to initialize SamGeo instance:")
66
+ app_logger.info(f"use ENCODER model {MODEL_ENCODER_NAME} from {MODEL_FOLDER})...")
67
+ app_logger.info(f"use DECODER model {MODEL_DECODER_NAME} from {MODEL_FOLDER})...")
68
+
69
+ model = SegmentAnythingONNX(
70
+ encoder_model_path=MODEL_FOLDER / MODEL_ENCODER_NAME,
71
+ decoder_model_path=MODEL_FOLDER / MODEL_DECODER_NAME
72
+ )
73
+ app_logger.info(f"model instantiated, creating embedding...")
74
+ embedding = model.encode(np_img)
75
+ app_logger.info(f"embedding created, running predict_masks...")
76
+ prediction_masks = model.predict_masks(embedding, prompt)
77
+ app_logger.info(f"predict_masks terminated")
78
+ app_logger.info(f"prediction masks shape:{prediction_masks.shape}, {prediction_masks.dtype}.")
79
+
80
+ mask = np.zeros((prediction_masks.shape[2], prediction_masks.shape[3]), dtype=np.uint8)
81
+ for m in prediction_masks[0, :, :, :]:
82
+ mask[m > 0.0] = 255
83
+
84
+ mask_unique_values, mask_unique_values_count = serialize(np.unique(mask, return_counts=True))
85
+ app_logger.info(f"mask_unique_values:{mask_unique_values}.")
86
+ app_logger.info(f"mask_unique_values_count:{mask_unique_values_count}.")
87
+
88
+ transform = load_affine_transformation_from_matrix(matrix)
89
+ app_logger.info(f"image/geojson origin matrix:{matrix}, transform:{transform}.")
90
+ shapes_generator = (
91
+ {'properties': {'raster_val': v}, 'geometry': s}
92
+ for i, (s, v)
93
+ in enumerate(
94
+ shapes(mask, mask=mask, transform=transform))
95
+ )
96
+ shapes_list = list(shapes_generator)
97
+ app_logger.info(f"created {len(shapes_list)} polygons.")
98
+ gpd_polygonized_raster = GeoDataFrame.from_features(shapes_list, crs="EPSG:3857")
99
+ geojson = gpd_polygonized_raster.to_json(to_wgs84=True)
100
+
101
+ return {
102
+ "geojson": geojson,
103
+ "n_shapes_geojson": len(shapes_list),
104
+ "n_predictions": len(prediction_masks),
105
+ "n_pixels_predictions": zip_arrays(mask_unique_values, mask_unique_values_count),
106
+ }
107
+ except ImportError as e:
108
+ app_logger.error(f"Error trying import module:{e}.")
src/utilities/constants.py CHANGED
@@ -1,7 +1,7 @@
1
  """Project constants"""
2
  CHANNEL_EXAGGERATIONS_LIST = [2.5, 1.1, 2.0]
3
- INPUT_CRS_STRING = "EPSG:4326"
4
- OUTPUT_CRS_STRING = "EPSG:3857"
5
  ROOT = "/tmp"
6
  NODATA_VALUES = -32768
7
  SKIP_CONDITIONS_LIST = [{"skip_key": "confidence", "skip_value": 0.5, "skip_condition": "major"}]
 
1
  """Project constants"""
2
  CHANNEL_EXAGGERATIONS_LIST = [2.5, 1.1, 2.0]
3
+ INPUT_CRS_STRING = "EPSG:3857"
4
+ OUTPUT_CRS_STRING = "EPSG:4326"
5
  ROOT = "/tmp"
6
  NODATA_VALUES = -32768
7
  SKIP_CONDITIONS_LIST = [{"skip_key": "confidence", "skip_value": 0.5, "skip_condition": "major"}]