Skip to content

Commit 60c27bd

Browse files
committed
Add SAM2 notebook examples
1 parent 79f9a31 commit 60c27bd

File tree

6 files changed

+395
-4
lines changed

6 files changed

+395
-4
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
[![image](https://img.shields.io/conda/vn/conda-forge/segment-geospatial.svg)](https://anaconda.org/conda-forge/segment-geospatial)
88
[![Docker Pulls](https://badgen.net/docker/pulls/giswqs/segment-geospatial?icon=docker&label=pulls)](https://hub.docker.com/r/giswqs/segment-geospatial)
99
[![PyPI Downloads](https://static.pepy.tech/badge/segment-geospatial)](https://pepy.tech/project/segment-geospatial)
10-
[![Conda Recipe](https://img.shields.io/badge/recipe-segment--geospatial-green.svg)](https://anaconda.org/conda-forge/segment-geospatial)
10+
[![Conda Recipe](https://img.shields.io/badge/recipe-segment--geospatial-green.svg)](https://github.com/giswqs/segment-geospatial-feedstock)
1111
[![Conda Downloads](https://anaconda.org/conda-forge/segment-geospatial/badges/downloads.svg)](https://anaconda.org/conda-forge/segment-geospatial)
1212
[![DOI](https://joss.theoj.org/papers/10.21105/joss.05663/status.svg)](https://doi.org/10.21105/joss.05663)
1313

docs/examples/sam2_automatic.ipynb

Lines changed: 377 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,377 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# Automatic Mask Generation with SAM 2\n",
8+
"\n",
9+
"[![image](https://studiolab.sagemaker.aws/studiolab.svg)](https://studiolab.sagemaker.aws/import/github/opengeos/segment-geospatial/blob/main/docs/examples/sam2_automatic.ipynb)\n",
10+
"[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/opengeos/segment-geospatial/blob/main/docs/examples/sam2_automatic.ipynb)\n",
11+
"\n",
12+
"This notebook shows how to segment objects from an image using the Segment Anything Model 2 (SAM2) with a few lines of code. \n",
13+
"\n",
14+
"Make sure you use GPU runtime for this notebook. For Google Colab, go to `Runtime` -> `Change runtime type` and select `GPU` as the hardware accelerator. "
15+
]
16+
},
17+
{
18+
"cell_type": "markdown",
19+
"metadata": {},
20+
"source": [
21+
"## Install dependencies\n",
22+
"\n",
23+
"Uncomment and run the following cell to install the required dependencies."
24+
]
25+
},
26+
{
27+
"cell_type": "code",
28+
"execution_count": null,
29+
"metadata": {},
30+
"outputs": [],
31+
"source": [
32+
"# %pip install -U segment-geospatial"
33+
]
34+
},
35+
{
36+
"cell_type": "code",
37+
"execution_count": null,
38+
"metadata": {},
39+
"outputs": [],
40+
"source": [
41+
"import leafmap\n",
42+
"from samgeo import SamGeo2"
43+
]
44+
},
45+
{
46+
"cell_type": "markdown",
47+
"metadata": {},
48+
"source": [
49+
"## Create an interactive map"
50+
]
51+
},
52+
{
53+
"cell_type": "code",
54+
"execution_count": null,
55+
"metadata": {},
56+
"outputs": [],
57+
"source": [
58+
"m = leafmap.Map(center=[29.6768, -95.3692], zoom=19)\n",
59+
"m.add_basemap(\"SATELLITE\")\n",
60+
"m"
61+
]
62+
},
63+
{
64+
"cell_type": "markdown",
65+
"metadata": {},
66+
"source": [
67+
"\n",
68+
"Pan and zoom the map to select the area of interest. Use the draw tools to draw a polygon or rectangle on the map"
69+
]
70+
},
71+
{
72+
"cell_type": "code",
73+
"execution_count": null,
74+
"metadata": {},
75+
"outputs": [],
76+
"source": [
77+
"if m.user_roi_bounds() is not None:\n",
78+
" bbox = m.user_roi_bounds()\n",
79+
"else:\n",
80+
" bbox = [-95.3704, 29.6762, -95.368, 29.6775]"
81+
]
82+
},
83+
{
84+
"cell_type": "markdown",
85+
"metadata": {},
86+
"source": [
87+
"## Download a sample image"
88+
]
89+
},
90+
{
91+
"cell_type": "code",
92+
"execution_count": null,
93+
"metadata": {},
94+
"outputs": [],
95+
"source": [
96+
"image = \"satellite.tif\"\n",
97+
"leafmap.map_tiles_to_geotiff(\n",
98+
" output=image, bbox=bbox, zoom=20, source=\"Satellite\", overwrite=True\n",
99+
")"
100+
]
101+
},
102+
{
103+
"cell_type": "markdown",
104+
"metadata": {},
105+
"source": [
106+
"You can also use your own image. Uncomment and run the following cell to use your own image."
107+
]
108+
},
109+
{
110+
"cell_type": "code",
111+
"execution_count": null,
112+
"metadata": {},
113+
"outputs": [],
114+
"source": [
115+
"# image = '/path/to/your/own/image.tif'"
116+
]
117+
},
118+
{
119+
"cell_type": "markdown",
120+
"metadata": {},
121+
"source": [
122+
"Display the downloaded image on the map."
123+
]
124+
},
125+
{
126+
"cell_type": "code",
127+
"execution_count": null,
128+
"metadata": {},
129+
"outputs": [],
130+
"source": [
131+
"m.layers[-1].visible = False\n",
132+
"m.add_raster(image, layer_name=\"Image\")\n",
133+
"m"
134+
]
135+
},
136+
{
137+
"cell_type": "markdown",
138+
"metadata": {},
139+
"source": [
140+
"## Initialize SAM class"
141+
]
142+
},
143+
{
144+
"cell_type": "code",
145+
"execution_count": null,
146+
"metadata": {},
147+
"outputs": [],
148+
"source": [
149+
"sam2 = SamGeo2(model_id=\"sam2-hiera-large\", automatic=True)"
150+
]
151+
},
152+
{
153+
"cell_type": "markdown",
154+
"metadata": {},
155+
"source": [
156+
"## Automatic mask generation\n",
157+
"\n",
158+
"Segment the image and save the results to a GeoTIFF file. Set `unique=True` to assign a unique ID to each object. "
159+
]
160+
},
161+
{
162+
"cell_type": "code",
163+
"execution_count": null,
164+
"metadata": {},
165+
"outputs": [],
166+
"source": [
167+
"sam2.generate(image)"
168+
]
169+
},
170+
{
171+
"cell_type": "code",
172+
"execution_count": null,
173+
"metadata": {},
174+
"outputs": [],
175+
"source": [
176+
"sam2.save_masks(output=\"masks.tif\")"
177+
]
178+
},
179+
{
180+
"cell_type": "code",
181+
"execution_count": null,
182+
"metadata": {},
183+
"outputs": [],
184+
"source": [
185+
"sam2.show_masks(cmap=\"binary_r\")"
186+
]
187+
},
188+
{
189+
"cell_type": "code",
190+
"execution_count": null,
191+
"metadata": {},
192+
"outputs": [],
193+
"source": [
194+
"sam2.show_masks(cmap=\"jet\")"
195+
]
196+
},
197+
{
198+
"cell_type": "markdown",
199+
"metadata": {},
200+
"source": [
201+
"Show the object annotations (objects with random color) on the map."
202+
]
203+
},
204+
{
205+
"cell_type": "code",
206+
"execution_count": null,
207+
"metadata": {},
208+
"outputs": [],
209+
"source": [
210+
"sam2.show_anns(axis=\"off\", alpha=0.7, output=\"annotations.tif\")"
211+
]
212+
},
213+
{
214+
"cell_type": "markdown",
215+
"metadata": {},
216+
"source": [
217+
"Compare images with a slider."
218+
]
219+
},
220+
{
221+
"cell_type": "code",
222+
"execution_count": null,
223+
"metadata": {},
224+
"outputs": [],
225+
"source": [
226+
"leafmap.image_comparison(\n",
227+
" \"satellite.tif\",\n",
228+
" \"annotations.tif\",\n",
229+
" label1=\"Satellite Image\",\n",
230+
" label2=\"Image Segmentation\",\n",
231+
")"
232+
]
233+
},
234+
{
235+
"cell_type": "markdown",
236+
"metadata": {},
237+
"source": [
238+
"Add image to the map."
239+
]
240+
},
241+
{
242+
"cell_type": "code",
243+
"execution_count": null,
244+
"metadata": {},
245+
"outputs": [],
246+
"source": [
247+
"m.add_raster(\"masks.tif\", colormap=\"jet\", layer_name=\"Masks\", nodata=0, opacity=0.7)\n",
248+
"m"
249+
]
250+
},
251+
{
252+
"cell_type": "markdown",
253+
"metadata": {},
254+
"source": [
255+
"Convert the object annotations to vector format, such as GeoPackage, Shapefile, or GeoJSON."
256+
]
257+
},
258+
{
259+
"cell_type": "code",
260+
"execution_count": null,
261+
"metadata": {},
262+
"outputs": [],
263+
"source": [
264+
"sam2.raster_to_vector(\"masks.tif\", \"masks.gpkg\")"
265+
]
266+
},
267+
{
268+
"cell_type": "code",
269+
"execution_count": null,
270+
"metadata": {},
271+
"outputs": [],
272+
"source": [
273+
"m.add_vector(\"masks.gpkg\", layer_name=\"Objects\")"
274+
]
275+
},
276+
{
277+
"cell_type": "markdown",
278+
"metadata": {},
279+
"source": [
280+
"## Automatic mask generation options\n",
281+
"\n",
282+
"There are several tunable parameters in automatic mask generation that control how densely points are sampled and what the thresholds are for removing low quality or duplicate masks. Additionally, generation can be automatically run on crops of the image to get improved performance on smaller objects, and post-processing can remove stray pixels and holes. Here is an example configuration that samples more masks:"
283+
]
284+
},
285+
{
286+
"cell_type": "code",
287+
"execution_count": null,
288+
"metadata": {},
289+
"outputs": [],
290+
"source": [
291+
"sam2 = SamGeo2(\n",
292+
" model_id=\"sam2-hiera-large\",\n",
293+
" apply_postprocessing=False,\n",
294+
" points_per_side=32,\n",
295+
" points_per_batch=64,\n",
296+
" pred_iou_thresh=0.7,\n",
297+
" stability_score_thresh=0.92,\n",
298+
" stability_score_offset=0.7,\n",
299+
" crop_n_layers=1,\n",
300+
" box_nms_thresh=0.7,\n",
301+
" crop_n_points_downscale_factor=2,\n",
302+
" min_mask_region_area=25.0,\n",
303+
" use_m2m=True,\n",
304+
")"
305+
]
306+
},
307+
{
308+
"cell_type": "code",
309+
"execution_count": null,
310+
"metadata": {},
311+
"outputs": [],
312+
"source": [
313+
"sam2.generate(image, output=\"masks2.tif\")"
314+
]
315+
},
316+
{
317+
"cell_type": "code",
318+
"execution_count": null,
319+
"metadata": {},
320+
"outputs": [],
321+
"source": [
322+
"sam2.show_masks(cmap=\"jet\")"
323+
]
324+
},
325+
{
326+
"cell_type": "code",
327+
"execution_count": null,
328+
"metadata": {},
329+
"outputs": [],
330+
"source": [
331+
"sam2.show_anns(axis=\"off\", alpha=0.7, output=\"annotations2.tif\")"
332+
]
333+
},
334+
{
335+
"cell_type": "markdown",
336+
"metadata": {},
337+
"source": [
338+
"Compare images with a slider."
339+
]
340+
},
341+
{
342+
"cell_type": "code",
343+
"execution_count": null,
344+
"metadata": {},
345+
"outputs": [],
346+
"source": [
347+
"leafmap.image_comparison(\n",
348+
" image,\n",
349+
" \"annotations2.tif\",\n",
350+
" label1=\"Image\",\n",
351+
" label2=\"Image Segmentation\",\n",
352+
")"
353+
]
354+
}
355+
],
356+
"metadata": {
357+
"kernelspec": {
358+
"display_name": "Python 3 (ipykernel)",
359+
"language": "python",
360+
"name": "python3"
361+
},
362+
"language_info": {
363+
"codemirror_mode": {
364+
"name": "ipython",
365+
"version": 3
366+
},
367+
"file_extension": ".py",
368+
"mimetype": "text/x-python",
369+
"name": "python",
370+
"nbconvert_exporter": "python",
371+
"pygments_lexer": "ipython3",
372+
"version": "3.11.8"
373+
}
374+
},
375+
"nbformat": 4,
376+
"nbformat_minor": 4
377+
}

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
[![image](https://img.shields.io/conda/vn/conda-forge/segment-geospatial.svg)](https://anaconda.org/conda-forge/segment-geospatial)
88
[![Docker Pulls](https://badgen.net/docker/pulls/giswqs/segment-geospatial?icon=docker&label=pulls)](https://hub.docker.com/r/giswqs/segment-geospatial)
99
[![PyPI Downloads](https://static.pepy.tech/badge/segment-geospatial)](https://pepy.tech/project/segment-geospatial)
10-
[![Conda Recipe](https://img.shields.io/badge/recipe-segment--geospatial-green.svg)](https://anaconda.org/conda-forge/segment-geospatial)
10+
[![Conda Recipe](https://img.shields.io/badge/recipe-segment--geospatial-green.svg)](https://github.com/giswqs/segment-geospatial-feedstock)
1111
[![Conda Downloads](https://anaconda.org/conda-forge/segment-geospatial/badges/downloads.svg)](https://anaconda.org/conda-forge/segment-geospatial)
1212
[![DOI](https://joss.theoj.org/papers/10.21105/joss.05663/status.svg)](https://doi.org/10.21105/joss.05663)
1313

0 commit comments

Comments
 (0)