samgis_core 3.0.4__tar.gz → 3.0.5__tar.gz
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.
- {samgis_core-3.0.4 → samgis_core-3.0.5}/PKG-INFO +1 -1
- {samgis_core-3.0.4 → samgis_core-3.0.5}/pyproject.toml +2 -2
- {samgis_core-3.0.4 → samgis_core-3.0.5}/samgis_core/prediction_api/sam_onnx2.py +45 -8
- {samgis_core-3.0.4 → samgis_core-3.0.5}/samgis_core/prediction_api/sam_onnx_inference.py +4 -0
- {samgis_core-3.0.4 → samgis_core-3.0.5}/samgis_core/utilities/create_folders_if_not_exists.py +20 -0
- samgis_core-3.0.5/samgis_core/utilities/plot_images.py +91 -0
- {samgis_core-3.0.4 → samgis_core-3.0.5}/samgis_core/utilities/session_logger.py +14 -0
- {samgis_core-3.0.4 → samgis_core-3.0.5}/samgis_core/utilities/utilities.py +18 -0
- samgis_core-3.0.4/samgis_core/utilities/plot_images.py +0 -11
- {samgis_core-3.0.4 → samgis_core-3.0.5}/LICENSE +0 -0
- {samgis_core-3.0.4 → samgis_core-3.0.5}/README.md +0 -0
- {samgis_core-3.0.4 → samgis_core-3.0.5}/samgis_core/__init__.py +0 -0
- {samgis_core-3.0.4 → samgis_core-3.0.5}/samgis_core/__version__.py +0 -0
- {samgis_core-3.0.4 → samgis_core-3.0.5}/samgis_core/prediction_api/__init__.py +0 -0
- {samgis_core-3.0.4 → samgis_core-3.0.5}/samgis_core/utilities/__init__.py +0 -0
- {samgis_core-3.0.4 → samgis_core-3.0.5}/samgis_core/utilities/constants.py +0 -0
- {samgis_core-3.0.4 → samgis_core-3.0.5}/samgis_core/utilities/serialize.py +0 -0
- {samgis_core-3.0.4 → samgis_core-3.0.5}/samgis_core/utilities/type_hints.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "samgis_core"
|
3
|
-
version = "3.0.
|
3
|
+
version = "3.0.5"
|
4
4
|
description = "SamGIS CORE"
|
5
5
|
authors = ["alessandro trinca tornidor <alessandro@trinca.tornidor.com>"]
|
6
6
|
license = "MIT license"
|
@@ -8,7 +8,7 @@ readme = "README.md"
|
|
8
8
|
|
9
9
|
[metadata]
|
10
10
|
name = "samgis_core"
|
11
|
-
version = "3.0.
|
11
|
+
version = "3.0.5"
|
12
12
|
|
13
13
|
[tool.poetry.urls]
|
14
14
|
Source = "https://gitlab.com/aletrn/samgis_core"
|
@@ -37,7 +37,7 @@ from samgis_core.utilities.utilities import convert_ndarray_to_pil, apply_coords
|
|
37
37
|
|
38
38
|
class SegmentAnythingONNX2:
|
39
39
|
"""
|
40
|
-
Segmentation model using
|
40
|
+
Segmentation model using Segment Anything.
|
41
41
|
Compatible with onnxruntime 1.17.x and later
|
42
42
|
"""
|
43
43
|
|
@@ -68,8 +68,17 @@ class SegmentAnythingONNX2:
|
|
68
68
|
)
|
69
69
|
|
70
70
|
@staticmethod
|
71
|
-
def get_input_points(prompt: ListDict):
|
72
|
-
"""
|
71
|
+
def get_input_points(prompt: ListDict) -> tuple[ndarray]:
|
72
|
+
"""
|
73
|
+
Get input points from a prompt dict list.
|
74
|
+
|
75
|
+
Args:
|
76
|
+
prompt: dict list
|
77
|
+
|
78
|
+
Returns:
|
79
|
+
tuple of points, labels ndarray ready for Segment Anything inference
|
80
|
+
|
81
|
+
"""
|
73
82
|
points = []
|
74
83
|
labels = []
|
75
84
|
for mark in prompt:
|
@@ -95,11 +104,12 @@ class SegmentAnythingONNX2:
|
|
95
104
|
|
96
105
|
Returns:
|
97
106
|
embedding image dict useful to store and cache image embeddings
|
107
|
+
|
98
108
|
"""
|
99
109
|
resized_image = self.preprocess_image(img)
|
100
110
|
padded_input_tensor = self.padding_tensor(resized_image)
|
101
111
|
|
102
|
-
# 2. GET IMAGE EMBEDDINGS USING IMAGE ENCODER
|
112
|
+
# 2. GET IMAGE EMBEDDINGS USING IMAGE ENCODER (`size` argument here is like ndarray `shape`)
|
103
113
|
outputs = self.encoder_session.run(None, {"images": padded_input_tensor})
|
104
114
|
image_embedding = outputs[0]
|
105
115
|
img = convert_ndarray_to_pil(img)
|
@@ -109,9 +119,17 @@ class SegmentAnythingONNX2:
|
|
109
119
|
"resized_size": resized_image.size
|
110
120
|
}
|
111
121
|
|
112
|
-
def predict_masks(self, embedding: EmbeddingPILImage, prompt: ListDict):
|
122
|
+
def predict_masks(self, embedding: EmbeddingPILImage, prompt: ListDict) -> ndarray:
|
113
123
|
"""
|
114
124
|
Predict masks for a single image.
|
125
|
+
|
126
|
+
Args:
|
127
|
+
embedding: input image embedding dict
|
128
|
+
prompt: Segment Anything input prompt
|
129
|
+
|
130
|
+
Returns:
|
131
|
+
prediction masks ndarray; this should have (1, 1, **image.shape) shape
|
132
|
+
|
115
133
|
"""
|
116
134
|
input_points, input_labels = self.get_input_points(prompt)
|
117
135
|
|
@@ -136,8 +154,17 @@ class SegmentAnythingONNX2:
|
|
136
154
|
})
|
137
155
|
return output_masks
|
138
156
|
|
139
|
-
def preprocess_image(self, img: PIL_Image | ndarray):
|
140
|
-
"""
|
157
|
+
def preprocess_image(self, img: PIL_Image | ndarray) -> ndarray:
|
158
|
+
"""
|
159
|
+
Resize image preserving aspect ratio using `output_size_target` as a long side.
|
160
|
+
|
161
|
+
Args:
|
162
|
+
img: input ndarray/PIL image
|
163
|
+
|
164
|
+
Returns:
|
165
|
+
image ndarray
|
166
|
+
|
167
|
+
"""
|
141
168
|
from PIL import Image
|
142
169
|
|
143
170
|
app_logger.info(f"image type:{type(img)}, shape/size:{img.size}.")
|
@@ -157,7 +184,17 @@ class SegmentAnythingONNX2:
|
|
157
184
|
img = img.resize((resized_width, resized_height), Image.Resampling.BILINEAR)
|
158
185
|
return img
|
159
186
|
|
160
|
-
def padding_tensor(self, img: PIL_Image | ndarray):
|
187
|
+
def padding_tensor(self, img: PIL_Image | ndarray) -> ndarray:
|
188
|
+
"""
|
189
|
+
Pad an image ndarray/tensor to given instance self.target_size
|
190
|
+
|
191
|
+
Args:
|
192
|
+
img: input ndarray/PIL image
|
193
|
+
|
194
|
+
Returns:
|
195
|
+
image ndarray
|
196
|
+
|
197
|
+
"""
|
161
198
|
# Prepare input tensor from image
|
162
199
|
tensor_input = np_array(img)
|
163
200
|
resized_width, resized_height = img.size
|
@@ -20,6 +20,7 @@ def get_raster_inference(
|
|
20
20
|
|
21
21
|
Returns:
|
22
22
|
raster prediction mask, prediction number
|
23
|
+
|
23
24
|
"""
|
24
25
|
np_img = np_array(img)
|
25
26
|
app_logger.info(f"img type {type(np_img)}, prompt:{prompt}.")
|
@@ -49,6 +50,7 @@ def get_inference_embedding(
|
|
49
50
|
|
50
51
|
Returns:
|
51
52
|
raster dict
|
53
|
+
|
52
54
|
"""
|
53
55
|
if embedding_key in embedding_dict:
|
54
56
|
app_logger.info("found embedding in dict...")
|
@@ -80,6 +82,7 @@ def get_raster_inference_using_existing_embedding(
|
|
80
82
|
|
81
83
|
Returns:
|
82
84
|
raster prediction mask, prediction number
|
85
|
+
|
83
86
|
"""
|
84
87
|
app_logger.info(f"using existing embedding of type {type(embedding)}.")
|
85
88
|
inference_out = models_instance.predict_masks(embedding, prompt)
|
@@ -111,6 +114,7 @@ def get_raster_inference_with_embedding_from_dict(
|
|
111
114
|
|
112
115
|
Returns:
|
113
116
|
raster prediction mask, prediction number
|
117
|
+
|
114
118
|
"""
|
115
119
|
app_logger.info(f"handling embedding using key {embedding_key}.")
|
116
120
|
embedding_dict = get_inference_embedding(img, models_instance, model_name, embedding_key, embedding_dict)
|
{samgis_core-3.0.4 → samgis_core-3.0.5}/samgis_core/utilities/create_folders_if_not_exists.py
RENAMED
@@ -10,6 +10,14 @@ def stats_pathname(pathname: Path | str):
|
|
10
10
|
|
11
11
|
|
12
12
|
def create_folder_if_not_exists(pathname: Path | str):
|
13
|
+
"""Create a folder given its path.
|
14
|
+
|
15
|
+
Args:
|
16
|
+
pathname: folder Path or string
|
17
|
+
|
18
|
+
Returns:
|
19
|
+
|
20
|
+
"""
|
13
21
|
current_pathname = Path(pathname)
|
14
22
|
try:
|
15
23
|
print(f"Pathname exists? {current_pathname.exists()}, That's a folder? {current_pathname.is_dir()}...")
|
@@ -32,6 +40,18 @@ def create_folder_if_not_exists(pathname: Path | str):
|
|
32
40
|
|
33
41
|
|
34
42
|
def folders_creation(folders_map: dict | str = None, ignore_errors: bool = True):
|
43
|
+
"""Create all folders listed within the folders_map argument (this argument can be a dict or a json string).
|
44
|
+
If folders_map is None the function will try to load the 'FOLDERS_MAP' env variable, then will load that json into
|
45
|
+
dict. Once loaded and parsed the folders_map variable, the function will loop over the dict to create the folders
|
46
|
+
using the `create_folder_if_not_exists()` function.
|
47
|
+
|
48
|
+
Args:
|
49
|
+
folders_map: dict or string map of folder string
|
50
|
+
ignore_errors: bool needed to eventually ignore errors on folder creation
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
|
54
|
+
"""
|
35
55
|
enforce_validation_with_getenv = folders_map is None
|
36
56
|
if enforce_validation_with_getenv:
|
37
57
|
folders_map = os.getenv("FOLDERS_MAP")
|
@@ -0,0 +1,91 @@
|
|
1
|
+
from numpy import ndarray
|
2
|
+
from matplotlib import pyplot as plt
|
3
|
+
|
4
|
+
from samgis_core.utilities.type_hints import ListStr, TupleInt
|
5
|
+
|
6
|
+
|
7
|
+
FigAxes = tuple[plt.Figure, plt.Axes]
|
8
|
+
|
9
|
+
|
10
|
+
def helper_imshow_output_expected(
|
11
|
+
img_list: list[ndarray], titles_list: ListStr, cmap: str = "gist_rainbow", plot_size: int = 5,
|
12
|
+
show=False, debug: bool = False, close_after: float = 0.0) -> FigAxes:
|
13
|
+
"""
|
14
|
+
Simple way to display a list of images with their titles, color map.
|
15
|
+
Should work also in an automate environments, like tests (use a `close_after` argument > 0)
|
16
|
+
|
17
|
+
Args:
|
18
|
+
img_list: ndarray images to display
|
19
|
+
titles_list: title images
|
20
|
+
cmap: color map
|
21
|
+
plot_size: figure plot size
|
22
|
+
show: fire plt.show() action if needed
|
23
|
+
debug: workaround useful in an interactive context, like Pycharm debugger
|
24
|
+
close_after: close after give seconds (useful in tests, contrasted to 'debug' option)
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
tuple of matplotlib Figure, Axes
|
28
|
+
|
29
|
+
"""
|
30
|
+
n = len(img_list)
|
31
|
+
assert len(titles_list) == n
|
32
|
+
fig, ax = plt.subplot_mosaic([
|
33
|
+
titles_list
|
34
|
+
], figsize=(n * plot_size, plot_size))
|
35
|
+
|
36
|
+
for title, img in zip(titles_list, img_list):
|
37
|
+
ax[title].imshow(img, cmap=cmap)
|
38
|
+
ax[title].legend()
|
39
|
+
if show:
|
40
|
+
if debug:
|
41
|
+
plt.pause(0.01)
|
42
|
+
plt.show()
|
43
|
+
if close_after > 0:
|
44
|
+
plt.pause(close_after)
|
45
|
+
plt.show(block=False)
|
46
|
+
plt.close("all")
|
47
|
+
return fig, ax
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
def imshow_raster(
|
52
|
+
raster, title, cmap: str = "gist_rainbow", interpolation: str = None, alpha=None, transform=None, plot_size=5,
|
53
|
+
show=False, debug: bool = False, close_after: float = 0.0) -> FigAxes:
|
54
|
+
"""
|
55
|
+
Displays raster images lists/arrays with titles, legend, alpha transparency, figure sizes
|
56
|
+
and geographic transformations, if not none (leveraging rasterio.plot)
|
57
|
+
|
58
|
+
Args:
|
59
|
+
raster: image to display
|
60
|
+
title: title image
|
61
|
+
cmap: color map
|
62
|
+
interpolation: interpolation type
|
63
|
+
alpha: alpha transparency
|
64
|
+
transform: geographic transform, eventually used for map representation by rasterio
|
65
|
+
plot_size: figure plot size
|
66
|
+
show: fire plt.show() action if needed
|
67
|
+
debug: workaround useful in an interactive context, like Pycharm debugger
|
68
|
+
close_after: close after give seconds (useful in tests, contrasted to 'debug' option)
|
69
|
+
|
70
|
+
Returns:
|
71
|
+
tuple of matplotlib Figure, Axes
|
72
|
+
|
73
|
+
"""
|
74
|
+
from rasterio import plot
|
75
|
+
|
76
|
+
fig, ax = plt.subplots(figsize=(plot_size, plot_size))
|
77
|
+
raster_ax = raster[0] if transform is not None else raster
|
78
|
+
image_hidden = ax.imshow(raster_ax, cmap=cmap, interpolation=interpolation, alpha=alpha)
|
79
|
+
if transform is not None:
|
80
|
+
plot.show(raster, transform=transform, ax=ax, cmap=cmap, interpolation=interpolation, alpha=alpha)
|
81
|
+
fig.colorbar(image_hidden, ax=ax)
|
82
|
+
ax.set_title(title)
|
83
|
+
if show:
|
84
|
+
if debug:
|
85
|
+
plt.pause(0.01)
|
86
|
+
plt.show()
|
87
|
+
if close_after > 0:
|
88
|
+
plt.pause(close_after)
|
89
|
+
plt.show(block=False)
|
90
|
+
plt.close("all")
|
91
|
+
return fig, ax
|
@@ -27,6 +27,20 @@ def drop_color_message_key(_, __, event_dict: EventDict) -> EventDict:
|
|
27
27
|
|
28
28
|
|
29
29
|
def setup_logging(json_logs: bool = False, log_level: str = "INFO"):
|
30
|
+
"""Enhance the configuration of structlog.
|
31
|
+
Needed for correlation id injection with fastapi middleware in samgis-web.
|
32
|
+
After the use of logging_middleware() in samgis_web.web.middlewares, add also the CorrelationIdMiddleware from
|
33
|
+
'asgi_correlation_id' package. (See 'tests/web/test_middlewares.py' in samgis_web).
|
34
|
+
To change an input parameter like the log level, re-run the function changing the parameter
|
35
|
+
(no need to re-instantiate the logger instance: it's a hot change)
|
36
|
+
|
37
|
+
Args:
|
38
|
+
json_logs: set logs in json format
|
39
|
+
log_level: log level string
|
40
|
+
|
41
|
+
Returns:
|
42
|
+
|
43
|
+
"""
|
30
44
|
timestamper = structlog.processors.TimeStamper(fmt="iso")
|
31
45
|
|
32
46
|
shared_processors: list[Processor] = [
|
@@ -98,6 +98,16 @@ def hash_calculate(arr) -> str | bytes:
|
|
98
98
|
|
99
99
|
|
100
100
|
def convert_ndarray_to_pil(pil_image: PIL_Image | ndarray):
|
101
|
+
"""
|
102
|
+
Check if an image is a ndarray and then convert to a PIL Image instance.
|
103
|
+
|
104
|
+
Args:
|
105
|
+
pil_image: PIL image or ndarray
|
106
|
+
|
107
|
+
Returns:
|
108
|
+
PIL Image
|
109
|
+
|
110
|
+
"""
|
101
111
|
from PIL import Image
|
102
112
|
|
103
113
|
if isinstance(pil_image, ndarray):
|
@@ -109,6 +119,14 @@ def apply_coords(coords: ndarray, embedding: EmbeddingPILImage):
|
|
109
119
|
"""
|
110
120
|
Expects a numpy np_array of length 2 in the final dimension. Requires the
|
111
121
|
original image size in (H, W) format.
|
122
|
+
|
123
|
+
Args:
|
124
|
+
coords: coordinates ndarray
|
125
|
+
embedding: PIL image embedding dict
|
126
|
+
|
127
|
+
Returns:
|
128
|
+
coordinates ndarray
|
129
|
+
|
112
130
|
"""
|
113
131
|
orig_width, orig_height = embedding["original_size"]
|
114
132
|
resized_width, resized_height = embedding["resized_size"]
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|