Skip to content

Commit 52f29fa

Browse files
authored
Added ArcGIS notebook example (#63)
1 parent 5212b46 commit 52f29fa

File tree

4 files changed

+368
-0
lines changed

4 files changed

+368
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ The **segment-geospatial** package draws its inspiration from [segment-anything-
3131
- [Segmenting satellite imagery](https://samgeo.gishub.org/examples/satellite)
3232
- [Automatically generating object masks](https://samgeo.gishub.org/examples/automatic_mask_generator)
3333
- [Segmenting satellite imagery with input prompts](https://samgeo.gishub.org/examples/input_prompts)
34+
- [Using segment-geospatial with ArcGIS Pro](https://samgeo.gishub.org/examples/input_prompts)
3435

3536
## Demos
3637

docs/examples/arcgis.ipynb

Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# Using the Segment-Geospatial Python Package with ArcGIS Pro"
8+
]
9+
},
10+
{
11+
"cell_type": "markdown",
12+
"metadata": {},
13+
"source": [
14+
"## Steps to install segment-geospatial\n",
15+
"\n",
16+
"1. Open Windows Registry Editor (`regedit.exe`) and navigate to `Computer\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\FileSystem`. Change the value of `LongPathsEnabled` to `1`. See [this screenshot](https://user-images.githubusercontent.com/46331011/225140182-df32dcfe-dca2-4e7f-9992-4c389af36184.png). This is a [known issue](https://github.com/Esri/deep-learning-frameworks/blob/master/README.md#known-issues) with the deep learning libraries for ArcGIS Pro. A future release might fix this issue.\n",
17+
"2. Download the [Deep Learning Libraries Installer for ArcGIS Pro 3.1](https://github.com/Esri/deep-learning-frameworks/blob/master/README.md#download). Unzip the file and run `ProDeepLearning.msi` to install the libraries.\n",
18+
"3. Open ArcGIS Pro and navigate to **Package Manager**. Clone the `arcgispro-py3` environment and name it `segment` or any other name you prefer. Activate the cloned environment.\n",
19+
"4. Navigate to Start menu - ArcGIS - Python Command Prompt - Right Click - More - Run as administrator.\n",
20+
"5. Run `conda activate base` to activate the base environment.\n",
21+
"6. Run `conda install mamba -n base -c conda-forge` to install mamba in the base environment.\n",
22+
"7. Run `conda activate segment` to activate the cloned environment.\n",
23+
"8. Run `mamba install -c conda-forge leafmap localtileserver segment-geospatial` to install the required package dependencies in the cloned environment.\n",
24+
"9. Download this notebook and run it in ArcGIS Pro."
25+
]
26+
},
27+
{
28+
"cell_type": "code",
29+
"execution_count": null,
30+
"metadata": {},
31+
"outputs": [],
32+
"source": [
33+
"import os\n",
34+
"import leafmap\n",
35+
"from samgeo import SamGeo, tms_to_geotiff\n",
36+
"%matplotlib inline"
37+
]
38+
},
39+
{
40+
"cell_type": "markdown",
41+
"metadata": {},
42+
"source": [
43+
"## Create an interactive map"
44+
]
45+
},
46+
{
47+
"cell_type": "code",
48+
"execution_count": null,
49+
"metadata": {},
50+
"outputs": [],
51+
"source": [
52+
"m = leafmap.Map(center=[37.8713, -122.2580], zoom=17, height=\"800px\")\n",
53+
"m.add_basemap(\"SATELLITE\")\n",
54+
"m"
55+
]
56+
},
57+
{
58+
"cell_type": "markdown",
59+
"metadata": {},
60+
"source": [
61+
"\n",
62+
"Pan and zoom the map to select the area of interest. Use the draw tools to draw a polygon or rectangle on the map"
63+
]
64+
},
65+
{
66+
"cell_type": "code",
67+
"execution_count": null,
68+
"metadata": {},
69+
"outputs": [],
70+
"source": [
71+
"leafmap.arc_zoom_to_bounds(m.bounds)"
72+
]
73+
},
74+
{
75+
"cell_type": "code",
76+
"execution_count": null,
77+
"metadata": {},
78+
"outputs": [],
79+
"source": [
80+
"if m.user_roi_bounds() is not None:\n",
81+
" bbox = m.user_roi_bounds()\n",
82+
"else:\n",
83+
" bbox = [-122.2659, 37.8682, -122.2521, 37.8741]"
84+
]
85+
},
86+
{
87+
"cell_type": "markdown",
88+
"metadata": {},
89+
"source": [
90+
"## Download a sample image"
91+
]
92+
},
93+
{
94+
"cell_type": "code",
95+
"execution_count": null,
96+
"metadata": {},
97+
"outputs": [],
98+
"source": [
99+
"workspace = os.path.dirname(arcpy.env.workspace)\n",
100+
"os.chdir(workspace)"
101+
]
102+
},
103+
{
104+
"cell_type": "code",
105+
"execution_count": null,
106+
"metadata": {},
107+
"outputs": [],
108+
"source": [
109+
"arcpy.env.overwriteOutput = True"
110+
]
111+
},
112+
{
113+
"cell_type": "code",
114+
"execution_count": null,
115+
"metadata": {
116+
"scrolled": false
117+
},
118+
"outputs": [],
119+
"source": [
120+
"image = \"Image.tif\"\n",
121+
"tms_to_geotiff(output=image, bbox=bbox, zoom=17, source=\"Satellite\", overwrite=True)"
122+
]
123+
},
124+
{
125+
"cell_type": "markdown",
126+
"metadata": {},
127+
"source": [
128+
"You can also use your own image. Uncomment and run the following cell to use your own image."
129+
]
130+
},
131+
{
132+
"cell_type": "code",
133+
"execution_count": null,
134+
"metadata": {},
135+
"outputs": [],
136+
"source": [
137+
"# image = '/path/to/your/own/image.tif'"
138+
]
139+
},
140+
{
141+
"cell_type": "markdown",
142+
"metadata": {},
143+
"source": [
144+
"Display the downloaded image on the map."
145+
]
146+
},
147+
{
148+
"cell_type": "code",
149+
"execution_count": null,
150+
"metadata": {},
151+
"outputs": [],
152+
"source": [
153+
"m.layers[-1].visible = False\n",
154+
"m.add_raster(image, layer_name=\"Image\")\n",
155+
"m"
156+
]
157+
},
158+
{
159+
"cell_type": "markdown",
160+
"metadata": {},
161+
"source": [
162+
"## Initialize SAM class\n",
163+
"\n",
164+
"Specify the file path to the model checkpoint. If it is not specified, the model will to downloaded to the working directory."
165+
]
166+
},
167+
{
168+
"cell_type": "code",
169+
"execution_count": null,
170+
"metadata": {},
171+
"outputs": [],
172+
"source": [
173+
"out_dir = os.path.join(os.path.expanduser(\"~\"), \"Downloads\")\n",
174+
"checkpoint = os.path.join(out_dir, \"sam_vit_h_4b8939.pth\")"
175+
]
176+
},
177+
{
178+
"cell_type": "code",
179+
"execution_count": null,
180+
"metadata": {},
181+
"outputs": [],
182+
"source": [
183+
"sam = SamGeo(\n",
184+
" model_type=\"vit_h\",\n",
185+
" checkpoint=checkpoint,\n",
186+
" sam_kwargs=None,\n",
187+
")"
188+
]
189+
},
190+
{
191+
"cell_type": "markdown",
192+
"metadata": {},
193+
"source": [
194+
"## Automatic mask generation\n",
195+
"\n",
196+
"Segment the image and save the results to a GeoTIFF file. Set `unique=True` to assign a unique ID to each object. "
197+
]
198+
},
199+
{
200+
"cell_type": "code",
201+
"execution_count": null,
202+
"metadata": {},
203+
"outputs": [],
204+
"source": [
205+
"sam.generate(image, output=\"masks.tif\", foreground=True, unique=True)"
206+
]
207+
},
208+
{
209+
"cell_type": "code",
210+
"execution_count": null,
211+
"metadata": {},
212+
"outputs": [],
213+
"source": [
214+
"sam.show_masks(cmap=\"binary_r\")"
215+
]
216+
},
217+
{
218+
"cell_type": "markdown",
219+
"metadata": {},
220+
"source": [
221+
"Show the object annotations (objects with random color) on the map."
222+
]
223+
},
224+
{
225+
"cell_type": "code",
226+
"execution_count": null,
227+
"metadata": {
228+
"scrolled": false
229+
},
230+
"outputs": [],
231+
"source": [
232+
"sam.show_anns(axis=\"off\", alpha=1, output=\"annotations.tif\")"
233+
]
234+
},
235+
{
236+
"cell_type": "markdown",
237+
"metadata": {},
238+
"source": [
239+
"Compare images with a slider."
240+
]
241+
},
242+
{
243+
"cell_type": "markdown",
244+
"metadata": {},
245+
"source": [
246+
"Add image to the map."
247+
]
248+
},
249+
{
250+
"cell_type": "code",
251+
"execution_count": null,
252+
"metadata": {},
253+
"outputs": [],
254+
"source": [
255+
"m.add_raster(\"annotations.tif\", alpha=0.5, layer_name=\"Masks\")\n",
256+
"m"
257+
]
258+
},
259+
{
260+
"cell_type": "markdown",
261+
"metadata": {},
262+
"source": [
263+
"Convert the object annotations to vector format, such as GeoPackage, Shapefile, or GeoJSON."
264+
]
265+
},
266+
{
267+
"cell_type": "code",
268+
"execution_count": null,
269+
"metadata": {},
270+
"outputs": [],
271+
"source": [
272+
"in_raster = os.path.join(workspace, 'masks.tif')\n",
273+
"out_shp = os.path.join(workspace, 'masks.shp')"
274+
]
275+
},
276+
{
277+
"cell_type": "code",
278+
"execution_count": null,
279+
"metadata": {},
280+
"outputs": [],
281+
"source": [
282+
"arcpy.conversion.RasterToPolygon(in_raster, out_shp)"
283+
]
284+
},
285+
{
286+
"cell_type": "markdown",
287+
"metadata": {},
288+
"source": [
289+
"## Automatic mask generation options\n",
290+
"\n",
291+
"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:"
292+
]
293+
},
294+
{
295+
"cell_type": "code",
296+
"execution_count": null,
297+
"metadata": {},
298+
"outputs": [],
299+
"source": [
300+
"sam_kwargs = {\n",
301+
" \"points_per_side\": 32,\n",
302+
" \"pred_iou_thresh\": 0.86,\n",
303+
" \"stability_score_thresh\": 0.92,\n",
304+
" \"crop_n_layers\": 1,\n",
305+
" \"crop_n_points_downscale_factor\": 2,\n",
306+
" \"min_mask_region_area\": 100,\n",
307+
"}"
308+
]
309+
},
310+
{
311+
"cell_type": "code",
312+
"execution_count": null,
313+
"metadata": {},
314+
"outputs": [],
315+
"source": [
316+
"sam = SamGeo(\n",
317+
" model_type=\"vit_h\",\n",
318+
" checkpoint=checkpoint,\n",
319+
" sam_kwargs=sam_kwargs,\n",
320+
")"
321+
]
322+
},
323+
{
324+
"cell_type": "code",
325+
"execution_count": null,
326+
"metadata": {},
327+
"outputs": [],
328+
"source": [
329+
"sam.generate(image, output=\"masks2.tif\", foreground=True)"
330+
]
331+
},
332+
{
333+
"cell_type": "code",
334+
"execution_count": null,
335+
"metadata": {},
336+
"outputs": [],
337+
"source": [
338+
"sam.show_masks(cmap=\"binary_r\")"
339+
]
340+
},
341+
{
342+
"cell_type": "code",
343+
"execution_count": null,
344+
"metadata": {},
345+
"outputs": [],
346+
"source": [
347+
"sam.show_anns(axis=\"off\", alpha=0.5, output=\"annotations2.tif\")"
348+
]
349+
}
350+
],
351+
"metadata": {
352+
"kernelspec": {
353+
"display_name": "Python 3 (ipykernel)",
354+
"language": "python",
355+
"name": "python3"
356+
},
357+
"language_info": {
358+
"file_extension": ".py",
359+
"name": "python",
360+
"version": "3"
361+
}
362+
},
363+
"nbformat": 4,
364+
"nbformat_minor": 2
365+
}

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ The **segment-geospatial** package draws its inspiration from [segment-anything-
3131
- [Segmenting satellite imagery](https://samgeo.gishub.org/examples/satellite)
3232
- [Automatically generating object masks](https://samgeo.gishub.org/examples/automatic_mask_generator)
3333
- [Segmenting satellite imagery with input prompts](https://samgeo.gishub.org/examples/input_prompts)
34+
- [Using segment-geospatial with ArcGIS Pro](https://samgeo.gishub.org/examples/input_prompts)
3435

3536
## Demos
3637

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ nav:
5353
- examples/satellite-predictor.ipynb
5454
- examples/automatic_mask_generator.ipynb
5555
- examples/input_prompts.ipynb
56+
- examples/arcgis.ipynb
5657
- API Reference:
5758
- common module: common.md
5859
- samgeo module: samgeo.md

0 commit comments

Comments
 (0)