Open sharoseali opened 2 weeks ago
Hi @sharoseali. On my side I can zoom in/out without any troubles. If tiles are not loading, it can be related to connection problems. Of course you can use the WMS layer of your choice. In a similar project, I used a very high resolution WMS layer and a SAR WMS layer. It is also possible to upload a GeoTiff image. I have done this in another project. I will try to update this repository with the option of uploading a GeoTiff when I have sometime. If you are interested in the pieces of code that allow you to upload your GeoTiff, I can share that with you, with indications where to place them in the code. But unfortunately I will not have time to do end-to-end test on this project for the next month.
hi @AlbughdadiM Thanks for answering. On my side wms link written inside the code isn't loading so many deep detailed tiles. I think the connection is fine. I will check one time more. However, I have my own link as well. I have also opened the link in QGIS as well. But I am not sure how to pick the correct information of layers from QGIS and paste here in the code:
wms_layer = dl.WMSTileLayer(
url="https://tiles.maps.eox.at/wms",
layers="s2cloudless-2020_3857",
format="image/jpeg",
transparent=True,
tileSize=512, # Try a higher tile size for better resolution
minZoom=0,
maxZoom=25, # Increase max zoom level for deeper zoom
attribution="Sentinel-2 cloudless layer for 2020 by EOX",
)
Also, of course, you can share the code for opening the GeoTIFF tile. I will try it on my side. I will be so glad. thanks again for your nice work and response.
@sharoseali I want to also mention that some providers limit the tile size and max zoom to avoid downloading large and detailed areas from WMS tiles. You can test yourself with the original WMS layer and a large ROI that the image download won't work.
Regarding the upload option:
upload_data_card = dbc.Card(
[
dbc.CardHeader(html.H2("Data upload")),
dbc.CardBody(
[
dcc.Upload(
id="upload-tif",
children=html.Div(["Drag and Drop or ", html.A("Select Files")]),
style={
"width": "100%",
"height": "60px",
"lineHeight": "60px",
"borderWidth": "1px",
"borderStyle": "dashed",
"borderRadius": "5px",
"textAlign": "center",
"margin": "10px",
},
multiple=False, # Set to True if multiple file upload is needed
),
dcc.Store(id="output-data-upload", data=None),
]
),
]
)
@app.callback(
[
Output("output-data-upload", "data"),
Output("map-card", "children", allow_duplicate=True),
],
[
Input("upload-tif", "contents"),
Input("upload-tif", "filename"),
],
prevent_initial_call="initial_duplicate",
)
def update_output_upload(contents, filename):
logging.info(filename)
if contents is None and filename is None:
raise PreventUpdate
_, content_string = contents.split(",")
process_id = id_generator()
process_path = os.path.join(WORK_DIR, process_id) # type: ignore
os.makedirs(process_path)
decoded = base64.b64decode(content_string)
file_path = os.path.join(process_path, filename)
with open(file_path, "wb") as f:
f.write(decoded)
reproj_file_path = os.path.join(
process_path, filename.split(".")[0] + "_reproj.tif"
)
reproj_bounds, img_byte_arr, png_path = reproject_to_epsg4326(
file_path, reproj_file_path
)
leaflet_bounds = [
[reproj_bounds[1], reproj_bounds[0]],
[reproj_bounds[3], reproj_bounds[2]],
]
map_center = [
(leaflet_bounds[0][0] + leaflet_bounds[1][0]) / 2,
(leaflet_bounds[0][1] + leaflet_bounds[1][1]) / 2,
]
encoded_img = base64.b64encode(img_byte_arr).decode("ascii")
encoded_img = "{}{}".format("data:image/png;base64, ", encoded_img)
print("also here")
list_children = dl.Map(
[
dl.LayersControl(
[
dl.Overlay(dl.TileLayer(), name="OSM", checked=True),
dl.Overlay(wms_layer, name="Sentinel-2", checked=True),
dl.Overlay(esri_tile_layer, name="ESRI", checked=True),
],
id="layers-control",
collapsed=True,
),
dl.ImageOverlay(opacity=1, url=encoded_img, bounds=leaflet_bounds),
dl.FeatureGroup(
[
dl.LocateControl(
options={"locateOptions": {"enableHighAccuracy": True}}
),
dl.MeasureControl(
position="topleft",
primaryLengthUnit="kilometers",
primaryAreaUnit="sqmeters",
id="measure_control",
),
dl.EditControl(
id="edit_control",
draw={
"polyline": False,
"polygon": False,
"circle": False,
"circlemarker": False,
},
),
]
),
],
id="map",
style={
"width": "100%",
"height": "80vh",
"margin": "auto",
"display": "block",
},
center=map_center,
zoom=12,
bounds=leaflet_bounds,
)
return [[reproj_file_path, png_path, leaflet_bounds]], list_children
@app.callback(
[
Output("downloaded_image_path", "data"),
Output("segment-button", "disabled"),
Output("map-card", "children", allow_duplicate=True),
Output("download-button", "disabled"),
],
[
Input("annotations-table", "data"),
Input("segment-button", "n_clicks"),
Input("sam-model", "value"),
Input("pred-iou-thresh", "value"),
Input("stability-score-thresh", "value"),
Input("output-data-upload", "data"),
],
prevent_initial_call="initial_duplicate",
)
def run_segmentation(
table_data,
n_clicks,
sam_model,
pred_iou_thresh,
stability_score_thresh,
input_data,
):
if n_clicks == 0 or table_data is None:
raise PreventUpdate
if n_clicks == 1 and table_data is not None:
roi = [row for row in table_data if row["type"] == "ROI BBox"][0]
if input_data:
image_bounds = input_data[0][2]
print(input_data)
tmp_img_path = input_data[0][0]
roi_bbox = [
float(image_bounds[0][1]), # x_min (longitude of SW)
float(image_bounds[0][0]), # y_min (latitude of SW)
float(image_bounds[1][1]), # x_max (longitude of NE)
float(image_bounds[1][0]), # y_max (latitude of NE)
]
map_center = [
(image_bounds[0][0] + image_bounds[1][0]) / 2,
(image_bounds[0][1] + image_bounds[1][1]) / 2,
]
else:
roi_bbox = [
float(roi["x_min"]),
float(roi["y_min"]),
float(roi["x_max"]),
float(roi["y_max"]),
]
image_bounds = [[roi_bbox[1], roi_bbox[0]], [roi_bbox[3], roi_bbox[2]]]
map_center = [
(float(roi["y_min"]) + float(roi["y_max"])) / 2.0,
(float(roi["x_min"]) + float(roi["x_max"])) / 2.0,
]
tmp_img_path = download_from_wms(
WMS_URL, roi_bbox, LAYER, IMAGE_FORMAT, WORK_DIR, RESOLUTION # type: ignore
)
types = [row["type"] for row in table_data]
unique_types = list(set(types))
if len(table_data) == 2 and unique_types == ["ROI BBox"]:
segmetnation_path, png_path = generate_automatic_mask(
tmp_img_path, sam_model, pred_iou_thresh, stability_score_thresh
)
else:
bboxes_geo, foreground_points, background_points, stacked_points, labels = (
None,
None,
None,
None,
None,
)
geom_df = pd.DataFrame(table_data)
unique_types = list(set(unique_types) - set("ROI BBox"))
for u_t in unique_types:
tmp_df = geom_df.loc[geom_df["type"] == u_t]
if u_t == "Object BBox":
bboxes_geo = tmp_df[columns[2:]].astype(float).values
if u_t == "Foreground Point":
foreground_points = tmp_df[columns[2:4]].astype(float).values
if u_t == "Background Point":
background_points = tmp_df[columns[2:4]].astype(float).values
if foreground_points is None and background_points is not None:
stacked_points = np.copy(background_points)
labels = np.zeros((stacked_points.shape[0]), dtype=np.uint8)
elif background_points is None and foreground_points is not None:
stacked_points = np.copy(foreground_points)
labels = np.ones((stacked_points.shape[0]), dtype=np.uint8)
elif background_points is not None and foreground_points is not None:
stacked_points = np.vstack((background_points, foreground_points))
labels = np.zeros((stacked_points.shape[0]), dtype=np.uint8)
labels[background_points.shape[0] :] = 1
segmetnation_path, png_path = sam_prompt_bbox(
tmp_img_path, bboxes_geo, stacked_points, labels, sam_model, roi_bbox
)
encoded_img = base64.b64encode(open(png_path, "rb").read()).decode("ascii")
encoded_img = "{}{}".format("data:image/png;base64, ", encoded_img)
list_children_items = [
dl.LayersControl(
[
dl.Overlay(dl.TileLayer(), name="OSM", checked=True),
dl.Overlay(wms_layer, name="Sentinel-2", checked=True),
dl.Overlay(esri_tile_layer, name="ESRI", checked=True),
],
id="layers-control",
collapsed=True,
),
dl.ImageOverlay(opacity=0.5, url=encoded_img, bounds=image_bounds),
dl.FeatureGroup(
[
dl.LocateControl(
options={"locateOptions": {"enableHighAccuracy": True}}
),
dl.MeasureControl(
position="topleft",
primaryLengthUnit="kilometers",
primaryAreaUnit="sqmeters",
id="measure_control",
),
dl.EditControl(
id="edit_control",
draw={
"polyline": False,
"polygon": False,
"circle": False,
"circlemarker": False,
},
),
]
),
]
if input_data:
encoded_img = base64.b64encode(open(input_data[0][1], "rb").read()).decode(
"ascii"
)
encoded_img = "{}{}".format("data:image/png;base64, ", encoded_img)
list_children_items.insert(
0, dl.ImageOverlay(opacity=0.5, url=encoded_img, bounds=image_bounds)
)
list_children = dl.Map(
list_children_items,
id="map",
style={
"width": "100%",
"height": "80vh",
"margin": "auto",
"display": "block",
},
center=map_center,
zoom=15,
bounds=image_bounds,
)
return [tmp_img_path, segmetnation_path, png_path], True, list_children, False
There might be slight changes in variables or new ones but this is the general logic and it shouldn't take a lot of changes to make it work.
Don't forget to use dash==2.18.2
to use prevent_initial_callback
and use allow_duplicate=True
, which allows multiple callbacks to update the same output. Please let me know if this works for you or in case you have other questions.
you would also need this
def reproject_to_epsg4326(input_path, output_path):
with rasterio.open(input_path) as src:
dst_crs = "EPSG:4326"
transform, width, height = calculate_default_transform(
src.crs, dst_crs, src.width, src.height, *src.bounds
)
dst_meta = src.meta.copy()
dst_meta.update(
{"crs": dst_crs, "transform": transform, "width": width, "height": height}
)
reprojected_bounds = transform_bounds(src.crs, dst_crs, *src.bounds)
with rasterio.open(output_path, "w", **dst_meta) as dst:
for i in range(1, src.count + 1):
reproject(
source=rasterio.band(src, i),
destination=rasterio.band(dst, i),
src_transform=src.transform,
src_crs=src.crs,
dst_transform=transform,
dst_crs=dst_crs,
resampling=Resampling.nearest,
)
reprojected_image = tiff.imread(output_path)
# reprojected_image = (
# (reprojected_image - reprojected_image.min())
# / (reprojected_image.max() - reprojected_image.min())
# * 255
# )
reprojected_image = reprojected_image.astype(np.uint8)
# Create a PIL image from the array
png_image = Image.fromarray(reprojected_image)
img_byte_arr = io.BytesIO()
png_image.save(img_byte_arr, format="PNG")
img_byte_arr.seek(0) # Go to the start
png_file_path = output_path.split(".")[0] + ".png"
with open(png_file_path, "wb") as f:
f.write(img_byte_arr.getbuffer())
return reprojected_bounds, img_byte_arr.getvalue(), png_file_path
Hi @AlbughdadiM, in your provided code for uploading TIFF images, will esri_tile_layer will be fine? As it's not
# ESRI base map options
esri_tile_layer = dl.TileLayer(
url="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
attribution="© Esri — Esri, DeLorme, NAVTEQ",)
and what is process_id here id_generator() function is missing. Is it some random ID generator like UUID ?
def update_output_upload(contents, filename):
logging.info(filename)
if contents is None and filename is None:
raise PreventUpdate
_, content_string = contents.split(",")
process_id = id_generator()
Esri layer is another wmts I am using but it is not necessary. The ID generator generates a unique ID for each task to avoid confusion of data in case of multiple requests with same image name at the same time.
This is the ESRI WMTS layer
esri_tile_layer = dl.TileLayer(
url="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
attribution="Esri",
)
and the ID generator
import uuid
def id_generator():
return str(uuid.uuid4())
And some undefined things are also there:
Will be easy if you provide correct imports and missing definitions
import io
import os
from io import BytesIO
from typing import Tuple
import uuid
import tifffile as tiff
from owslib.wms import WebMapService
from pyproj import Transformer, CRS
import rasterio
from rasterio.warp import (
calculate_default_transform,
reproject,
Resampling,
transform_bounds,
)
import numpy as np
from PIL import Image
This should cover the missing imports, and extra imports I am using in my code
Thanks for providing all the details. Once it starts running, I will share the whole working code here with the uploading files feature. Meanwhile, I think we have to update something else as well. I am getting some errors on the interface relating to ID :
Regarding the upload option:
- Place this in the layout of the app.py
upload_data_card = dbc.Card( [ dbc.CardHeader(html.H2("Data upload")), dbc.CardBody( [ dcc.Upload( id="upload-tif", children=html.Div(["Drag and Drop or ", html.A("Select Files")]), style={ "width": "100%", "height": "60px", "lineHeight": "60px", "borderWidth": "1px", "borderStyle": "dashed", "borderRadius": "5px", "textAlign": "center", "margin": "10px", }, multiple=False, # Set to True if multiple file upload is needed ), dcc.Store(id="output-data-upload", data=None), ] ), ] )
- You will also need a callback to save the uploaded image in a temp file in the container and overlay it on the map
@app.callback( [ Output("output-data-upload", "data"), Output("map-card", "children", allow_duplicate=True), ], [ Input("upload-tif", "contents"), Input("upload-tif", "filename"), ], prevent_initial_call="initial_duplicate", ) def update_output_upload(contents, filename): logging.info(filename) if contents is None and filename is None: raise PreventUpdate _, content_string = contents.split(",") process_id = id_generator() process_path = os.path.join(WORK_DIR, process_id) # type: ignore os.makedirs(process_path) decoded = base64.b64decode(content_string) file_path = os.path.join(process_path, filename) with open(file_path, "wb") as f: f.write(decoded) reproj_file_path = os.path.join( process_path, filename.split(".")[0] + "_reproj.tif" ) reproj_bounds, img_byte_arr, png_path = reproject_to_epsg4326( file_path, reproj_file_path ) leaflet_bounds = [ [reproj_bounds[1], reproj_bounds[0]], [reproj_bounds[3], reproj_bounds[2]], ] map_center = [ (leaflet_bounds[0][0] + leaflet_bounds[1][0]) / 2, (leaflet_bounds[0][1] + leaflet_bounds[1][1]) / 2, ] encoded_img = base64.b64encode(img_byte_arr).decode("ascii") encoded_img = "{}{}".format("data:image/png;base64, ", encoded_img) print("also here") list_children = dl.Map( [ dl.LayersControl( [ dl.Overlay(dl.TileLayer(), name="OSM", checked=True), dl.Overlay(wms_layer, name="Sentinel-2", checked=True), dl.Overlay(esri_tile_layer, name="ESRI", checked=True), ], id="layers-control", collapsed=True, ), dl.ImageOverlay(opacity=1, url=encoded_img, bounds=leaflet_bounds), dl.FeatureGroup( [ dl.LocateControl( options={"locateOptions": {"enableHighAccuracy": True}} ), dl.MeasureControl( position="topleft", primaryLengthUnit="kilometers", primaryAreaUnit="sqmeters", id="measure_control", ), dl.EditControl( id="edit_control", draw={ "polyline": False, "polygon": False, "circle": False, "circlemarker": False, }, ), ] ), ], id="map", style={ "width": "100%", "height": "80vh", "margin": "auto", "display": "block", }, center=map_center, zoom=12, bounds=leaflet_bounds, ) return [[reproj_file_path, png_path, leaflet_bounds]], list_children
- Update callback that does image download/or use the uploaded image and do the segmentation and shows result on the map
@app.callback( [ Output("downloaded_image_path", "data"), Output("segment-button", "disabled"), Output("map-card", "children", allow_duplicate=True), Output("download-button", "disabled"), ], [ Input("annotations-table", "data"), Input("segment-button", "n_clicks"), Input("sam-model", "value"), Input("pred-iou-thresh", "value"), Input("stability-score-thresh", "value"), Input("output-data-upload", "data"), ], prevent_initial_call="initial_duplicate", ) def run_segmentation( table_data, n_clicks, sam_model, pred_iou_thresh, stability_score_thresh, input_data, ): if n_clicks == 0 or table_data is None: raise PreventUpdate if n_clicks == 1 and table_data is not None: roi = [row for row in table_data if row["type"] == "ROI BBox"][0] if input_data: image_bounds = input_data[0][2] print(input_data) tmp_img_path = input_data[0][0] roi_bbox = [ float(image_bounds[0][1]), # x_min (longitude of SW) float(image_bounds[0][0]), # y_min (latitude of SW) float(image_bounds[1][1]), # x_max (longitude of NE) float(image_bounds[1][0]), # y_max (latitude of NE) ] map_center = [ (image_bounds[0][0] + image_bounds[1][0]) / 2, (image_bounds[0][1] + image_bounds[1][1]) / 2, ] else: roi_bbox = [ float(roi["x_min"]), float(roi["y_min"]), float(roi["x_max"]), float(roi["y_max"]), ] image_bounds = [[roi_bbox[1], roi_bbox[0]], [roi_bbox[3], roi_bbox[2]]] map_center = [ (float(roi["y_min"]) + float(roi["y_max"])) / 2.0, (float(roi["x_min"]) + float(roi["x_max"])) / 2.0, ] tmp_img_path = download_from_wms( WMS_URL, roi_bbox, LAYER, IMAGE_FORMAT, WORK_DIR, RESOLUTION # type: ignore ) types = [row["type"] for row in table_data] unique_types = list(set(types)) if len(table_data) == 2 and unique_types == ["ROI BBox"]: segmetnation_path, png_path = generate_automatic_mask( tmp_img_path, sam_model, pred_iou_thresh, stability_score_thresh ) else: bboxes_geo, foreground_points, background_points, stacked_points, labels = ( None, None, None, None, None, ) geom_df = pd.DataFrame(table_data) unique_types = list(set(unique_types) - set("ROI BBox")) for u_t in unique_types: tmp_df = geom_df.loc[geom_df["type"] == u_t] if u_t == "Object BBox": bboxes_geo = tmp_df[columns[2:]].astype(float).values if u_t == "Foreground Point": foreground_points = tmp_df[columns[2:4]].astype(float).values if u_t == "Background Point": background_points = tmp_df[columns[2:4]].astype(float).values if foreground_points is None and background_points is not None: stacked_points = np.copy(background_points) labels = np.zeros((stacked_points.shape[0]), dtype=np.uint8) elif background_points is None and foreground_points is not None: stacked_points = np.copy(foreground_points) labels = np.ones((stacked_points.shape[0]), dtype=np.uint8) elif background_points is not None and foreground_points is not None: stacked_points = np.vstack((background_points, foreground_points)) labels = np.zeros((stacked_points.shape[0]), dtype=np.uint8) labels[background_points.shape[0] :] = 1 segmetnation_path, png_path = sam_prompt_bbox( tmp_img_path, bboxes_geo, stacked_points, labels, sam_model, roi_bbox ) encoded_img = base64.b64encode(open(png_path, "rb").read()).decode("ascii") encoded_img = "{}{}".format("data:image/png;base64, ", encoded_img) list_children_items = [ dl.LayersControl( [ dl.Overlay(dl.TileLayer(), name="OSM", checked=True), dl.Overlay(wms_layer, name="Sentinel-2", checked=True), dl.Overlay(esri_tile_layer, name="ESRI", checked=True), ], id="layers-control", collapsed=True, ), dl.ImageOverlay(opacity=0.5, url=encoded_img, bounds=image_bounds), dl.FeatureGroup( [ dl.LocateControl( options={"locateOptions": {"enableHighAccuracy": True}} ), dl.MeasureControl( position="topleft", primaryLengthUnit="kilometers", primaryAreaUnit="sqmeters", id="measure_control", ), dl.EditControl( id="edit_control", draw={ "polyline": False, "polygon": False, "circle": False, "circlemarker": False, }, ), ] ), ] if input_data: encoded_img = base64.b64encode(open(input_data[0][1], "rb").read()).decode( "ascii" ) encoded_img = "{}{}".format("data:image/png;base64, ", encoded_img) list_children_items.insert( 0, dl.ImageOverlay(opacity=0.5, url=encoded_img, bounds=image_bounds) ) list_children = dl.Map( list_children_items, id="map", style={ "width": "100%", "height": "80vh", "margin": "auto", "display": "block", }, center=map_center, zoom=15, bounds=image_bounds, ) return [tmp_img_path, segmetnation_path, png_path], True, list_children, False
There might be slight changes in variables or new ones but this is the general logic and it shouldn't take a lot of changes to make it work. Don't forget to use
dash==2.18.2
to useprevent_initial_callback
and useallow_duplicate=True
, which allows multiple callbacks to update the same output. Please let me know if this works for you or in case you have other questions.
The first piece of code contains the layout updates that should be implemented to make the upload component work
you finally add these components to the layout after declaring them as follows
app.layout = html.Div(
[
dbc.Spinner(
id="loading-1",
type="grow",
color="success",
children=[
dcc.Store(id="downloaded_image_path"),
dcc.Store(id="prev-table-data"),
navbar,
dbc.Container(
[
dbc.Row(
[
dbc.Col(
image_annotation_card,
md=7,
),
dbc.Col(
dbc.Stack([upload_data_card,annotated_data_card, model_card]), # This where upload_data_card is added to the layout
md=5,
),
],
),
],
fluid=True,
),
],
)
]
)
Yeah, @AlbughdadiM I have already written layout updates and e upload component work. However, the app layout wasn't updated. But as soon as the page uploads it gives an exception of an invalid path. Seems it started to process image running even without uploading file-path from user.
This is the CopyPaste-friendlyy version of the traceback.
Traceback (most recent call last):
File "/home/test/projects/segment-geospatial/TKDM/satellite-sam-dashboard/src/app.py", line 414, in reproject_to_epsg4326
with rasterio.open(input_path) as src:
File "/home/test/anaconda3/envs/geo/lib/python3.9/site-packages/rasterio/env.py", line 451, in wrapper
return f(*args, **kwds)
File "/home/test/anaconda3/envs/geo/lib/python3.9/site-packages/rasterio/__init__.py", line 216, in open
raise TypeError("invalid path or file: {0!r}".format(fp))
TypeError: invalid path or file: None
Here is the new app.py. Will be so helpful If you review this to make it work . Thanks again for your continuous suppport
Yeah, @AlbughdadiM I have already written layout updates and e upload component work. However, the app layout wasn't updated. But as soon as the page uploads it gives an exception of an invalid path. Seems it started to process image running even without uploading file-path from user.
This is the CopyPaste-friendlyy version of the traceback. Traceback (most recent call last): File "/home/test/projects/segment-geospatial/TKDM/satellite-sam-dashboard/src/app.py", line 414, in reproject_to_epsg4326 with rasterio.open(input_path) as src: File "/home/test/anaconda3/envs/geo/lib/python3.9/site-packages/rasterio/env.py", line 451, in wrapper return f(*args, **kwds) File "/home/test/anaconda3/envs/geo/lib/python3.9/site-packages/rasterio/__init__.py", line 216, in open raise TypeError("invalid path or file: {0!r}".format(fp)) TypeError: invalid path or file: None
Here is the new app.py. Will be so helpful If you review this to make it work . Thanks again for your continuous suppport
I think you changed the callback function to upload data, you used the auxiliary function reproject_to_espog4326 instead. The reprojection function should be a normal function that can be placed in utils.py call it from the callback function i mentioned above and I will put also here for convince
@app.callback(
[
Output("output-data-upload", "data"),
Output("map-card", "children", allow_duplicate=True),
],
[
Input("upload-tif", "contents"),
Input("upload-tif", "filename"),
],
prevent_initial_call="initial_duplicate",
)
def update_output_upload(contents, filename):
logging.info(filename)
if contents is None and filename is None:
raise PreventUpdate
_, content_string = contents.split(",")
process_id = id_generator()
process_path = os.path.join(WORK_DIR, process_id) # type: ignore
os.makedirs(process_path)
decoded = base64.b64decode(content_string)
file_path = os.path.join(process_path, filename)
with open(file_path, "wb") as f:
f.write(decoded)
reproj_file_path = os.path.join(
process_path, filename.split(".")[0] + "_reproj.tif"
)
reproj_bounds, img_byte_arr, png_path = reproject_to_epsg4326(
file_path, reproj_file_path
)
leaflet_bounds = [
[reproj_bounds[1], reproj_bounds[0]],
[reproj_bounds[3], reproj_bounds[2]],
]
map_center = [
(leaflet_bounds[0][0] + leaflet_bounds[1][0]) / 2,
(leaflet_bounds[0][1] + leaflet_bounds[1][1]) / 2,
]
encoded_img = base64.b64encode(img_byte_arr).decode("ascii")
encoded_img = "{}{}".format("data:image/png;base64, ", encoded_img)
print("also here")
list_children = dl.Map(
[
dl.LayersControl(
[
dl.Overlay(dl.TileLayer(), name="OSM", checked=True),
dl.Overlay(wms_layer, name="Sentinel-2", checked=True),
dl.Overlay(esri_tile_layer, name="ESRI", checked=True),
],
id="layers-control",
collapsed=True,
),
dl.ImageOverlay(opacity=1, url=encoded_img, bounds=leaflet_bounds),
dl.FeatureGroup(
[
dl.LocateControl(
options={"locateOptions": {"enableHighAccuracy": True}}
),
dl.MeasureControl(
position="topleft",
primaryLengthUnit="kilometers",
primaryAreaUnit="sqmeters",
id="measure_control",
),
dl.EditControl(
id="edit_control",
draw={
"polyline": False,
"polygon": False,
"circle": False,
"circlemarker": False,
},
),
]
),
],
id="map",
style={
"width": "100%",
"height": "80vh",
"margin": "auto",
"display": "block",
},
center=map_center,
zoom=12,
bounds=leaflet_bounds,
)
return [[reproj_file_path, png_path, leaflet_bounds]], list_children
HI @AlbughdadiM Thanks for your great work. I was just curious about more zoomed tiles. Zooming it more is not load tile details. Is there any option I can upload my on-tiff imagery? I also have my wms link. I edit in the config file but it isn't loading any tiles.
Any help for this? Thanks