[feat] add option to donwload files written in custom path folder
Browse files- .gitignore +1 -0
- Dockerfile +2 -0
- samgis/io/raster_helpers.py +36 -0
- samgis/prediction_api/predictors.py +17 -3
- static/list_files.html +13 -0
- wrappers/fastapi_wrapper.py +21 -1
.gitignore
CHANGED
|
@@ -196,6 +196,7 @@ tmp
|
|
| 196 |
nohup.out
|
| 197 |
/tests/events.tar
|
| 198 |
function_dump_*.json
|
|
|
|
| 199 |
|
| 200 |
# onnx models
|
| 201 |
*.onnx
|
|
|
|
| 196 |
nohup.out
|
| 197 |
/tests/events.tar
|
| 198 |
function_dump_*.json
|
| 199 |
+
vis_output/*
|
| 200 |
|
| 201 |
# onnx models
|
| 202 |
*.onnx
|
Dockerfile
CHANGED
|
@@ -14,6 +14,7 @@ COPY samgis ${WORKDIR_ROOT}/samgis
|
|
| 14 |
COPY wrappers ${WORKDIR_ROOT}/wrappers
|
| 15 |
COPY pyproject.toml poetry.lock README.md ${WORKDIR_ROOT}
|
| 16 |
RUN echo "# install samgis #" && pip install .
|
|
|
|
| 17 |
|
| 18 |
RUN ls -l /usr/bin/which
|
| 19 |
RUN /usr/bin/which python
|
|
@@ -38,5 +39,6 @@ RUN ls -l ${WORKDIR_ROOT}/wrappers/
|
|
| 38 |
RUN ls -l ${WORKDIR_ROOT}/static/
|
| 39 |
RUN ls -l ${WORKDIR_ROOT}/static/dist
|
| 40 |
RUN ls -l ${WORKDIR_ROOT}/static/node_modules
|
|
|
|
| 41 |
|
| 42 |
CMD ["uvicorn", "wrappers.fastapi_wrapper:app", "--host", "0.0.0.0", "--port", "7860"]
|
|
|
|
| 14 |
COPY wrappers ${WORKDIR_ROOT}/wrappers
|
| 15 |
COPY pyproject.toml poetry.lock README.md ${WORKDIR_ROOT}
|
| 16 |
RUN echo "# install samgis #" && pip install .
|
| 17 |
+
RUN mkdir ${WORKDIR_ROOT}/vis_output
|
| 18 |
|
| 19 |
RUN ls -l /usr/bin/which
|
| 20 |
RUN /usr/bin/which python
|
|
|
|
| 39 |
RUN ls -l ${WORKDIR_ROOT}/static/
|
| 40 |
RUN ls -l ${WORKDIR_ROOT}/static/dist
|
| 41 |
RUN ls -l ${WORKDIR_ROOT}/static/node_modules
|
| 42 |
+
RUN ls -l ${WORKDIR_ROOT}/vis_output
|
| 43 |
|
| 44 |
CMD ["uvicorn", "wrappers.fastapi_wrapper:app", "--host", "0.0.0.0", "--port", "7860"]
|
samgis/io/raster_helpers.py
CHANGED
|
@@ -1,9 +1,11 @@
|
|
| 1 |
"""helpers for computer vision duties"""
|
| 2 |
import numpy as np
|
| 3 |
from numpy import ndarray, bitwise_not
|
|
|
|
| 4 |
|
| 5 |
from samgis import app_logger
|
| 6 |
from samgis.utilities.type_hints import XYZTerrainProvidersNames
|
|
|
|
| 7 |
|
| 8 |
|
| 9 |
def get_nextzen_terrain_rgb_formula(red: ndarray, green: ndarray, blue: ndarray) -> ndarray:
|
|
@@ -292,3 +294,37 @@ def check_empty_array(arr: ndarray, val: float) -> bool:
|
|
| 292 |
check5 = np.array_equal(arr_check5_tmp, arr_check5)
|
| 293 |
app_logger.debug(f"array checks:{check1}, {check2}, {check3}, {check4}, {check5}.")
|
| 294 |
return check1 or check2 or check3 or check4 or check5
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
"""helpers for computer vision duties"""
|
| 2 |
import numpy as np
|
| 3 |
from numpy import ndarray, bitwise_not
|
| 4 |
+
from rasterio import open as rasterio_open
|
| 5 |
|
| 6 |
from samgis import app_logger
|
| 7 |
from samgis.utilities.type_hints import XYZTerrainProvidersNames
|
| 8 |
+
from samgis.utilities.constants import OUTPUT_CRS_STRING
|
| 9 |
|
| 10 |
|
| 11 |
def get_nextzen_terrain_rgb_formula(red: ndarray, green: ndarray, blue: ndarray) -> ndarray:
|
|
|
|
| 294 |
check5 = np.array_equal(arr_check5_tmp, arr_check5)
|
| 295 |
app_logger.debug(f"array checks:{check1}, {check2}, {check3}, {check4}, {check5}.")
|
| 296 |
return check1 or check2 or check3 or check4 or check5
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
def write_raster_png(arr, transform, prefix: str, suffix: str, folder_output_path="/tmp"):
|
| 300 |
+
from pathlib import Path
|
| 301 |
+
from rasterio.plot import reshape_as_raster
|
| 302 |
+
|
| 303 |
+
output_filename = Path(folder_output_path) / f"{prefix}_{suffix}.png"
|
| 304 |
+
|
| 305 |
+
with rasterio_open(
|
| 306 |
+
output_filename, 'w', driver='PNG',
|
| 307 |
+
height=arr.shape[0],
|
| 308 |
+
width=arr.shape[1],
|
| 309 |
+
count=3,
|
| 310 |
+
dtype=str(arr.dtype),
|
| 311 |
+
crs=OUTPUT_CRS_STRING,
|
| 312 |
+
transform=transform) as dst:
|
| 313 |
+
dst.write(reshape_as_raster(arr))
|
| 314 |
+
app_logger.info(f"written:{output_filename} as PNG, use {OUTPUT_CRS_STRING} as CRS.")
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
def write_raster_tiff(arr, transform, prefix: str, suffix: str, folder_output_path="/tmp"):
|
| 318 |
+
from pathlib import Path
|
| 319 |
+
output_filename = Path(folder_output_path) / f"{prefix}_{suffix}.tiff"
|
| 320 |
+
|
| 321 |
+
with rasterio_open(
|
| 322 |
+
output_filename, 'w', driver='GTiff',
|
| 323 |
+
height=arr.shape[0],
|
| 324 |
+
width=arr.shape[1],
|
| 325 |
+
count=1,
|
| 326 |
+
dtype=str(arr.dtype),
|
| 327 |
+
crs=OUTPUT_CRS_STRING,
|
| 328 |
+
transform=transform) as dst:
|
| 329 |
+
dst.write(arr, 1)
|
| 330 |
+
app_logger.info(f"written:{output_filename} as TIFF, use {OUTPUT_CRS_STRING} as CRS.")
|
samgis/prediction_api/predictors.py
CHANGED
|
@@ -1,18 +1,21 @@
|
|
| 1 |
"""functions using machine learning instance model(s)"""
|
|
|
|
|
|
|
|
|
|
| 2 |
from samgis import app_logger, MODEL_FOLDER
|
| 3 |
from samgis.io.geo_helpers import get_vectorized_raster_as_geojson
|
| 4 |
-
from samgis.io.raster_helpers import get_raster_terrain_rgb_like, get_rgb_prediction_image
|
| 5 |
from samgis.io.tms2geotiff import download_extent
|
| 6 |
from samgis.io.wrappers_helpers import check_source_type_is_terrain
|
| 7 |
from samgis.utilities.constants import DEFAULT_URL_TILES, SLOPE_CELLSIZE
|
| 8 |
-
from samgis_core.prediction_api.sam_onnx import SegmentAnythingONNX
|
| 9 |
-
from samgis_core.prediction_api.sam_onnx import get_raster_inference, get_raster_inference_with_embedding_from_dict
|
| 10 |
from samgis_core.utilities.constants import MODEL_ENCODER_NAME, MODEL_DECODER_NAME, DEFAULT_INPUT_SHAPE
|
| 11 |
from samgis_core.utilities.type_hints import LlistFloat, DictStrInt, ListDict
|
| 12 |
|
| 13 |
|
| 14 |
models_dict = {"fastsam": {"instance": None}}
|
| 15 |
embedding_dict = {}
|
|
|
|
| 16 |
|
| 17 |
|
| 18 |
def samexporter_predict(
|
|
@@ -63,6 +66,17 @@ def samexporter_predict(
|
|
| 63 |
app_logger.info(f"terrain-rgb like raster: compute slope, curvature using {slope_cellsize} as cell size.")
|
| 64 |
img = get_rgb_prediction_image(dem, slope_cellsize)
|
| 65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
app_logger.info(
|
| 67 |
f"img type {type(img)} with shape/size:{img.size}, transform type: {type(transform)}, transform:{transform}.")
|
| 68 |
app_logger.info(f"source_name:{source_name}, source_name type:{type(source_name)}.")
|
|
|
|
| 1 |
"""functions using machine learning instance model(s)"""
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
from os import getenv
|
| 4 |
+
|
| 5 |
from samgis import app_logger, MODEL_FOLDER
|
| 6 |
from samgis.io.geo_helpers import get_vectorized_raster_as_geojson
|
| 7 |
+
from samgis.io.raster_helpers import get_raster_terrain_rgb_like, get_rgb_prediction_image, write_raster_png, write_raster_tiff
|
| 8 |
from samgis.io.tms2geotiff import download_extent
|
| 9 |
from samgis.io.wrappers_helpers import check_source_type_is_terrain
|
| 10 |
from samgis.utilities.constants import DEFAULT_URL_TILES, SLOPE_CELLSIZE
|
| 11 |
+
from samgis_core.prediction_api.sam_onnx import SegmentAnythingONNX, get_raster_inference_with_embedding_from_dict
|
|
|
|
| 12 |
from samgis_core.utilities.constants import MODEL_ENCODER_NAME, MODEL_DECODER_NAME, DEFAULT_INPUT_SHAPE
|
| 13 |
from samgis_core.utilities.type_hints import LlistFloat, DictStrInt, ListDict
|
| 14 |
|
| 15 |
|
| 16 |
models_dict = {"fastsam": {"instance": None}}
|
| 17 |
embedding_dict = {}
|
| 18 |
+
msg_write_tmp_on_disk = "found option to write images and geojson output..."
|
| 19 |
|
| 20 |
|
| 21 |
def samexporter_predict(
|
|
|
|
| 66 |
app_logger.info(f"terrain-rgb like raster: compute slope, curvature using {slope_cellsize} as cell size.")
|
| 67 |
img = get_rgb_prediction_image(dem, slope_cellsize)
|
| 68 |
|
| 69 |
+
folder_write_tmp_on_disk = getenv("WRITE_TMP_ON_DISK", "")
|
| 70 |
+
app_logger.info(f"folder_write_tmp_on_disk:{folder_write_tmp_on_disk}.")
|
| 71 |
+
prefix = f"w{pt1[1]},s{pt1[0]},e{pt0[1]},n{pt0[0]}_"
|
| 72 |
+
if bool(folder_write_tmp_on_disk):
|
| 73 |
+
now = datetime.now().strftime('%Y%m%d_%H%M%S')
|
| 74 |
+
app_logger.info(msg_write_tmp_on_disk + f"with coords {prefix}, shape:{img.shape}, {len(img.shape)}.")
|
| 75 |
+
if img.shape and len(img.shape) == 2:
|
| 76 |
+
write_raster_tiff(img, transform, f"{prefix}_{now}_", f"raw_tiff", folder_write_tmp_on_disk)
|
| 77 |
+
if img.shape and len(img.shape) == 3 and img.shape[2] == 3:
|
| 78 |
+
write_raster_png(img, transform, f"{prefix}_{now}_", f"raw_img", folder_write_tmp_on_disk)
|
| 79 |
+
|
| 80 |
app_logger.info(
|
| 81 |
f"img type {type(img)} with shape/size:{img.size}, transform type: {type(transform)}, transform:{transform}.")
|
| 82 |
app_logger.info(f"source_name:{source_name}, source_name type:{type(source_name)}.")
|
static/list_files.html
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<html>
|
| 2 |
+
<head>
|
| 3 |
+
<title>Files</title>
|
| 4 |
+
</head>
|
| 5 |
+
<body>
|
| 6 |
+
<h1>Files:</h1>
|
| 7 |
+
<ul>
|
| 8 |
+
{% for file in files %}
|
| 9 |
+
<li><a href="{{file}}">{{file}}</a></li>
|
| 10 |
+
{% endfor %}
|
| 11 |
+
</ul>
|
| 12 |
+
</body>
|
| 13 |
+
</html>
|
wrappers/fastapi_wrapper.py
CHANGED
|
@@ -1,10 +1,12 @@
|
|
| 1 |
import json
|
|
|
|
| 2 |
import uuid
|
| 3 |
|
| 4 |
from fastapi import FastAPI, HTTPException, Request, status
|
| 5 |
from fastapi.exceptions import RequestValidationError
|
| 6 |
-
from fastapi.responses import FileResponse, JSONResponse
|
| 7 |
from fastapi.staticfiles import StaticFiles
|
|
|
|
| 8 |
from pydantic import ValidationError
|
| 9 |
|
| 10 |
from samgis import PROJECT_ROOT_FOLDER
|
|
@@ -123,6 +125,24 @@ async def http_exception_handler(request: Request, exc: HTTPException) -> JSONRe
|
|
| 123 |
)
|
| 124 |
|
| 125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
# important: the index() function and the app.mount MUST be at the end
|
| 127 |
app.mount("/", StaticFiles(directory=PROJECT_ROOT_FOLDER / "static" / "dist", html=True), name="static")
|
| 128 |
|
|
|
|
| 1 |
import json
|
| 2 |
+
import os
|
| 3 |
import uuid
|
| 4 |
|
| 5 |
from fastapi import FastAPI, HTTPException, Request, status
|
| 6 |
from fastapi.exceptions import RequestValidationError
|
| 7 |
+
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse
|
| 8 |
from fastapi.staticfiles import StaticFiles
|
| 9 |
+
from fastapi.templating import Jinja2Templates
|
| 10 |
from pydantic import ValidationError
|
| 11 |
|
| 12 |
from samgis import PROJECT_ROOT_FOLDER
|
|
|
|
| 125 |
)
|
| 126 |
|
| 127 |
|
| 128 |
+
write_tmp_on_disk = os.getenv("WRITE_TMP_ON_DISK", "")
|
| 129 |
+
app_logger.info(f"write_tmp_on_disk:{write_tmp_on_disk}.")
|
| 130 |
+
if bool(write_tmp_on_disk):
|
| 131 |
+
app.mount("/vis_output", StaticFiles(directory=write_tmp_on_disk), name="vis_output")
|
| 132 |
+
templates = Jinja2Templates(directory=PROJECT_ROOT_FOLDER / "static")
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
@app.get("/vis_output", response_class=HTMLResponse)
|
| 136 |
+
def list_files(request: Request):
|
| 137 |
+
|
| 138 |
+
files = os.listdir(write_tmp_on_disk)
|
| 139 |
+
files_paths = sorted([f"{request.url._url}/{f}" for f in files])
|
| 140 |
+
print(files_paths)
|
| 141 |
+
return templates.TemplateResponse(
|
| 142 |
+
"list_files.html", {"request": request, "files": files_paths}
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
|
| 146 |
# important: the index() function and the app.mount MUST be at the end
|
| 147 |
app.mount("/", StaticFiles(directory=PROJECT_ROOT_FOLDER / "static" / "dist", html=True), name="static")
|
| 148 |
|