Skip to content

Commit 38c7346

Browse files
authored
Added regularized option for vector output (#104)
* Add rectangularize option for vector output * Rename regularize function
1 parent ec2ec70 commit 38c7346

File tree

1 file changed

+110
-5
lines changed

1 file changed

+110
-5
lines changed

samgeo/common.py

Lines changed: 110 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1714,11 +1714,28 @@ def sam_map_gui(sam, basemap="SATELLITE", repeat_mode=True, out_dir=None, **kwar
17141714
layout=widgets.Layout(width=widget_width, padding=padding),
17151715
style=style,
17161716
)
1717+
1718+
rectangular = widgets.Checkbox(
1719+
value=False,
1720+
description="Regularize",
1721+
layout=widgets.Layout(width="130px", padding=padding),
1722+
style=style,
1723+
)
1724+
1725+
colorpicker = widgets.ColorPicker(
1726+
concise=False,
1727+
description="Color",
1728+
value="#ffff00",
1729+
layout=widgets.Layout(width="140px", padding=padding),
1730+
style=style,
1731+
)
1732+
17171733
buttons = widgets.VBox(
17181734
[
17191735
radio_buttons,
17201736
widgets.HBox([fg_count, bg_count]),
17211737
opacity_slider,
1738+
widgets.HBox([rectangular, colorpicker]),
17221739
widgets.HBox(
17231740
[segment_button, save_button, reset_button],
17241741
layout=widgets.Layout(padding="0px 4px 0px 4px"),
@@ -1950,6 +1967,8 @@ def segment_button_click(change):
19501967
)
19511968
if m.find_layer("Masks") is not None:
19521969
m.remove_layer(m.find_layer("Masks"))
1970+
if m.find_layer("Regularized") is not None:
1971+
m.remove_layer(m.find_layer("Regularized"))
19531972

19541973
if hasattr(sam, "prediction_fp") and os.path.exists(
19551974
sam.prediction_fp
@@ -1966,6 +1985,21 @@ def segment_button_click(change):
19661985
layer_name="Masks",
19671986
zoom_to_layer=False,
19681987
)
1988+
1989+
if rectangular.value:
1990+
vector = filename.replace(".tif", ".gpkg")
1991+
vector_rec = filename.replace(".tif", "_rect.gpkg")
1992+
raster_to_vector(filename, vector)
1993+
regularize(vector, vector_rec)
1994+
vector_style = {"color": colorpicker.value}
1995+
m.add_vector(
1996+
vector_rec,
1997+
layer_name="Regularized",
1998+
style=vector_style,
1999+
info_mode=None,
2000+
zoom_to_layer=False,
2001+
)
2002+
19692003
except:
19702004
pass
19712005
output.clear_output()
@@ -1984,7 +2018,10 @@ def filechooser_callback(chooser):
19842018
filename = chooser.selected
19852019
shutil.copy(sam.prediction_fp, filename)
19862020
vector = filename.replace(".tif", ".gpkg")
1987-
raster_to_gpkg(filename, vector)
2021+
raster_to_vector(filename, vector)
2022+
if rectangular.value:
2023+
vector_rec = filename.replace(".tif", "_rect.gpkg")
2024+
regularize(vector, vector_rec)
19882025

19892026
fg_points = [
19902027
[marker.location[1], marker.location[0]]
@@ -2040,9 +2077,13 @@ def reset_button_click(change):
20402077
segment_button.value = False
20412078
reset_button.value = False
20422079
opacity_slider.value = 0.5
2080+
rectangular.value = False
2081+
colorpicker.value = "#ffff00"
20432082
output.clear_output()
20442083
try:
20452084
m.remove_layer(m.find_layer("Masks"))
2085+
if m.find_layer("Regularized") is not None:
2086+
m.remove_layer(m.find_layer("Regularized"))
20462087
m.clear_drawings()
20472088
if hasattr(m, "fg_markers"):
20482089
m.user_rois = None
@@ -2284,7 +2325,7 @@ def text_sam_gui(sam, basemap="SATELLITE", out_dir=None, **kwargs):
22842325
description="Box threshold:",
22852326
min=0,
22862327
max=1,
2287-
value=0.5,
2328+
value=0.25,
22882329
step=0.01,
22892330
readout=True,
22902331
continuous_update=True,
@@ -2297,7 +2338,7 @@ def text_sam_gui(sam, basemap="SATELLITE", out_dir=None, **kwargs):
22972338
min=0,
22982339
max=1,
22992340
step=0.01,
2300-
value=0.5,
2341+
value=0.25,
23012342
readout=True,
23022343
continuous_update=True,
23032344
layout=widgets.Layout(width=widget_width, padding=padding),
@@ -2332,6 +2373,21 @@ def opacity_changed(change):
23322373

23332374
opacity_slider.observe(opacity_changed, "value")
23342375

2376+
rectangular = widgets.Checkbox(
2377+
value=False,
2378+
description="Regularize",
2379+
layout=widgets.Layout(width="130px", padding=padding),
2380+
style=style,
2381+
)
2382+
2383+
colorpicker = widgets.ColorPicker(
2384+
concise=False,
2385+
description="Color",
2386+
value="#ffff00",
2387+
layout=widgets.Layout(width="140px", padding=padding),
2388+
style=style,
2389+
)
2390+
23352391
segment_button = widgets.ToggleButton(
23362392
description="Segment",
23372393
value=False,
@@ -2365,6 +2421,7 @@ def opacity_changed(change):
23652421
text_slider,
23662422
cmap_dropdown,
23672423
opacity_slider,
2424+
widgets.HBox([rectangular, colorpicker]),
23682425
widgets.HBox(
23692426
[segment_button, save_button, reset_button],
23702427
layout=widgets.Layout(padding="0px 4px 0px 4px"),
@@ -2433,6 +2490,8 @@ def segment_button_click(change):
24332490
sam.output = filename
24342491
if m.find_layer(layer_name) is not None:
24352492
m.remove_layer(m.find_layer(layer_name))
2493+
if m.find_layer(f"{layer_name}_rect") is not None:
2494+
m.remove_layer(m.find_layer(f"{layer_name} Regularized"))
24362495
if os.path.exists(filename):
24372496
try:
24382497
m.add_raster(
@@ -2444,6 +2503,21 @@ def segment_button_click(change):
24442503
zoom_to_layer=False,
24452504
)
24462505
m.layer_name = layer_name
2506+
2507+
if rectangular.value:
2508+
vector = filename.replace(".tif", ".gpkg")
2509+
vector_rec = filename.replace(".tif", "_rect.gpkg")
2510+
raster_to_vector(filename, vector)
2511+
regularize(vector, vector_rec)
2512+
vector_style = {"color": colorpicker.value}
2513+
m.add_vector(
2514+
vector_rec,
2515+
layer_name=f"{layer_name} Regularized",
2516+
style=vector_style,
2517+
info_mode=None,
2518+
zoom_to_layer=False,
2519+
)
2520+
24472521
output.clear_output()
24482522
except Exception as e:
24492523
print(e)
@@ -2456,9 +2530,11 @@ def filechooser_callback(chooser):
24562530
try:
24572531
filename = chooser.selected
24582532
shutil.copy(sam.output, filename)
2459-
vector = filename.replace(".tif", ".shp")
2533+
vector = filename.replace(".tif", ".gpkg")
24602534
raster_to_vector(filename, vector)
2461-
2535+
if rectangular.value:
2536+
vector_rec = filename.replace(".tif", "_rect.gpkg")
2537+
regularize(vector, vector_rec)
24622538
except Exception as e:
24632539
print(e)
24642540

@@ -2524,3 +2600,32 @@ def reset_button_click(change):
25242600
m.toolbar_control = toolbar_control
25252601

25262602
return m
2603+
2604+
2605+
def regularize(source, output=None, crs="EPSG:4326", **kwargs):
2606+
"""Regularize a polygon GeoDataFrame.
2607+
2608+
Args:
2609+
source (str | gpd.GeoDataFrame): The input file path or a GeoDataFrame.
2610+
output (str, optional): The output file path. Defaults to None.
2611+
2612+
2613+
Returns:
2614+
gpd.GeoDataFrame: The output GeoDataFrame.
2615+
"""
2616+
if isinstance(source, str):
2617+
gdf = gpd.read_file(source)
2618+
elif isinstance(source, gpd.GeoDataFrame):
2619+
gdf = source
2620+
else:
2621+
raise ValueError("The input source must be a GeoDataFrame or a file path.")
2622+
2623+
polygons = gdf.geometry.apply(lambda geom: geom.minimum_rotated_rectangle)
2624+
result = gpd.GeoDataFrame(geometry=polygons, data=gdf.drop("geometry", axis=1))
2625+
2626+
if crs is not None:
2627+
result.to_crs(crs, inplace=True)
2628+
if output is not None:
2629+
result.to_file(output, **kwargs)
2630+
else:
2631+
return result

0 commit comments

Comments
 (0)