segment-geospatial 1.3.1__tar.gz → 1.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/workflows/docs-build.yml +2 -2
  2. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/workflows/macos.yml +1 -1
  3. segment_geospatial-1.3.3/.github/workflows/publish.yml +54 -0
  4. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/workflows/ubuntu.yml +1 -1
  5. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/workflows/windows.yml +1 -1
  6. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.pre-commit-config.yaml +1 -1
  7. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/PKG-INFO +1 -1
  8. segment_geospatial-1.3.3/agent-harness/SAMGEO.md +59 -0
  9. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/README.md +148 -0
  10. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/__init__.py +3 -0
  11. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/__main__.py +6 -0
  12. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/core/__init__.py +1 -0
  13. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/core/data.py +229 -0
  14. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/core/export.py +201 -0
  15. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/core/model.py +262 -0
  16. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/core/project.py +266 -0
  17. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/core/segment.py +369 -0
  18. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/core/session.py +182 -0
  19. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/core/vector.py +155 -0
  20. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/samgeo_cli.py +748 -0
  21. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/skills/SKILL.md +123 -0
  22. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/tests/TEST.md +198 -0
  23. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/tests/__init__.py +0 -0
  24. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/tests/test_core.py +415 -0
  25. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/tests/test_full_e2e.py +480 -0
  26. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/utils/__init__.py +1 -0
  27. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/utils/repl_skin.py +185 -0
  28. segment_geospatial-1.3.3/agent-harness/cli_anything/samgeo/utils/samgeo_backend.py +155 -0
  29. segment_geospatial-1.3.3/agent-harness/setup.py +30 -0
  30. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam2_automatic.ipynb +1 -1
  31. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/usage.md +2 -1
  32. segment_geospatial-1.3.3/package_plugin.py +118 -0
  33. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/pyproject.toml +2 -2
  34. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/qgis-samgeo-plugin/samgeo_plugin.py +97 -1
  35. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/requirements_docs.txt +2 -2
  36. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/samgeo/__init__.py +1 -1
  37. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/samgeo/api.py +66 -22
  38. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/samgeo/common.py +123 -6
  39. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/samgeo/hq_sam.py +19 -7
  40. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/samgeo/samgeo.py +19 -7
  41. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/samgeo/samgeo2.py +24 -11
  42. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/samgeo/samgeo3.py +95 -51
  43. segment_geospatial-1.3.3/scripts/upload_to_qgis_plugin_repo.py +74 -0
  44. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/segment_geospatial.egg-info/PKG-INFO +1 -1
  45. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/segment_geospatial.egg-info/SOURCES.txt +25 -0
  46. segment_geospatial-1.3.3/tests/test_api.py +274 -0
  47. segment_geospatial-1.3.3/tests/test_common.py +151 -0
  48. segment_geospatial-1.3.1/tests/test_api.py +0 -161
  49. segment_geospatial-1.3.1/tests/test_common.py +0 -62
  50. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.editorconfig +0 -0
  51. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/FUNDING.yml +0 -0
  52. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  53. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  54. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  55. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/dependabot.yaml +0 -0
  56. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/workflows/docker-image.yml +0 -0
  57. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/workflows/docker-publish.yml +0 -0
  58. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/workflows/docs.yml +0 -0
  59. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/workflows/draft-pdf.yml +0 -0
  60. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.github/workflows/pypi.yml +0 -0
  61. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/.gitignore +0 -0
  62. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/CITATION.cff +0 -0
  63. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/CODE_OF_CONDUCT.md +0 -0
  64. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/Dockerfile +0 -0
  65. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/LICENSE +0 -0
  66. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/MANIFEST.in +0 -0
  67. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/README.md +0 -0
  68. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/CNAME +0 -0
  69. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/api.md +0 -0
  70. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/assets/README.md +0 -0
  71. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/assets/favicon.png +0 -0
  72. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/assets/logo.png +0 -0
  73. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/assets/logo_rect.png +0 -0
  74. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/caption.md +0 -0
  75. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/changelog.md +0 -0
  76. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/changelog_update.py +0 -0
  77. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/common.md +0 -0
  78. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/contributing.md +0 -0
  79. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/detectree2.md +0 -0
  80. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/arcgis.ipynb +0 -0
  81. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/automatic_mask_generator.ipynb +0 -0
  82. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/automatic_mask_generator_hq.ipynb +0 -0
  83. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/box_prompts.ipynb +0 -0
  84. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/data/tree_boxes.geojson +0 -0
  85. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/detectree2.ipynb +0 -0
  86. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/fast_sam.ipynb +0 -0
  87. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/image_captioning.ipynb +0 -0
  88. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/input_prompts.ipynb +0 -0
  89. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/input_prompts_hq.ipynb +0 -0
  90. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/maxar_open_data.ipynb +0 -0
  91. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam2_box_prompts.ipynb +0 -0
  92. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam2_point_prompts.ipynb +0 -0
  93. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam2_predictor.ipynb +0 -0
  94. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam2_text_prompts.ipynb +0 -0
  95. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam2_video.ipynb +0 -0
  96. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam3_automated_segmentation.ipynb +0 -0
  97. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam3_batch_segmentation.ipynb +0 -0
  98. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam3_box_prompts.ipynb +0 -0
  99. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam3_image_segmentation.ipynb +0 -0
  100. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam3_image_segmentation_jpg.ipynb +0 -0
  101. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam3_interactive.ipynb +0 -0
  102. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam3_object_tracking.ipynb +0 -0
  103. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam3_point_prompts.ipynb +0 -0
  104. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam3_point_prompts_batch.ipynb +0 -0
  105. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam3_tiled_segmentation.ipynb +0 -0
  106. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam3_video_masks.ipynb +0 -0
  107. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam3_video_prompts.ipynb +0 -0
  108. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/sam3_video_segmentation.ipynb +0 -0
  109. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/satellite-predictor.ipynb +0 -0
  110. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/satellite.ipynb +0 -0
  111. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/text_prompts.ipynb +0 -0
  112. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/text_prompts_batch.ipynb +0 -0
  113. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/text_swimming_pools.ipynb +0 -0
  114. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/examples/tree_mapping.ipynb +0 -0
  115. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/faq.md +0 -0
  116. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/fast_sam.md +0 -0
  117. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/hq_sam.md +0 -0
  118. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/index.md +0 -0
  119. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/installation.md +0 -0
  120. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/overrides/main.html +0 -0
  121. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/samgeo.md +0 -0
  122. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/samgeo2.md +0 -0
  123. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/samgeo3.md +0 -0
  124. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/text_sam.md +0 -0
  125. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/workshops/AIforGood_2025.ipynb +0 -0
  126. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/workshops/IPPN_2024.ipynb +0 -0
  127. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/workshops/cn_workshop.ipynb +0 -0
  128. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/workshops/jupytext.toml +0 -0
  129. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/docs/workshops/purdue.ipynb +0 -0
  130. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/mkdocs.yml +0 -0
  131. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/paper/10.21105.joss.05663.pdf +0 -0
  132. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/paper/paper.bib +0 -0
  133. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/paper/paper.md +0 -0
  134. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/qgis-samgeo-plugin/LICENSE +0 -0
  135. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/qgis-samgeo-plugin/README.md +0 -0
  136. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/qgis-samgeo-plugin/__init__.py +0 -0
  137. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/qgis-samgeo-plugin/icons/icon.png +0 -0
  138. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/qgis-samgeo-plugin/install_plugin.py +0 -0
  139. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/qgis-samgeo-plugin/install_plugin.sh +0 -0
  140. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/qgis-samgeo-plugin/map_tools.py +0 -0
  141. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/qgis-samgeo-plugin/metadata.txt +0 -0
  142. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/qgis-samgeo-plugin/resources.py +0 -0
  143. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/qgis-samgeo-plugin/test_plugin.py +0 -0
  144. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/requirements.txt +0 -0
  145. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/requirements_dev.txt +0 -0
  146. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/samgeo/caption.py +0 -0
  147. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/samgeo/detectree2.py +0 -0
  148. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/samgeo/fast_sam.py +0 -0
  149. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/samgeo/fer.py +0 -0
  150. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/samgeo/text_sam.py +0 -0
  151. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/samgeo/utmconv.py +0 -0
  152. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/segment_geospatial.egg-info/dependency_links.txt +0 -0
  153. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/segment_geospatial.egg-info/entry_points.txt +0 -0
  154. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/segment_geospatial.egg-info/requires.txt +0 -0
  155. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/segment_geospatial.egg-info/top_level.txt +0 -0
  156. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/setup.cfg +0 -0
  157. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/tests/__init__.py +0 -0
  158. {segment_geospatial-1.3.1 → segment_geospatial-1.3.3}/tests/test_samgeo.py +0 -0
@@ -14,7 +14,7 @@ jobs:
14
14
  with:
15
15
  fetch-depth: 0
16
16
  - name: Setup micromamba
17
- uses: mamba-org/setup-micromamba@v2
17
+ uses: mamba-org/setup-micromamba@v3
18
18
  with:
19
19
  environment-name: docs-env
20
20
  create-args: >-
@@ -34,7 +34,7 @@ jobs:
34
34
  pip install .
35
35
  - run: mkdocs build
36
36
  - name: Deploy to Netlify
37
- uses: nwtgck/actions-netlify@v3.0
37
+ uses: nwtgck/actions-netlify@v4.0
38
38
  with:
39
39
  publish-dir: "./site"
40
40
  production-branch: master
@@ -25,7 +25,7 @@ jobs:
25
25
  - uses: actions/checkout@v6
26
26
 
27
27
  - name: Setup micromamba
28
- uses: mamba-org/setup-micromamba@v2
28
+ uses: mamba-org/setup-micromamba@v3
29
29
  with:
30
30
  environment-name: test-env
31
31
  create-args: >-
@@ -0,0 +1,54 @@
1
+ name: Publish
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+ inputs:
8
+ tag:
9
+ description: "Release tag to publish (must already exist on GitHub)"
10
+ required: true
11
+ type: string
12
+
13
+ permissions:
14
+ contents: write
15
+
16
+ jobs:
17
+ publish:
18
+ name: Publish plugin to plugins.qgis.org
19
+ runs-on: ubuntu-latest
20
+ env:
21
+ TAG: ${{ github.event.release.tag_name || inputs.tag }}
22
+ PLUGIN_DIR: qgis-samgeo-plugin
23
+ PLUGIN_NAME: samgeo_plugin
24
+ ZIP_PATH: dist/samgeo_plugin.zip
25
+ steps:
26
+ - uses: actions/checkout@v6
27
+
28
+ - uses: actions/setup-python@v6
29
+ with:
30
+ python-version: "3.13"
31
+
32
+ - name: Build plugin zip
33
+ run: python "package_plugin.py" --source "$PLUGIN_DIR" --name "$PLUGIN_NAME" --output "$ZIP_PATH"
34
+
35
+ - name: Verify metadata version matches release tag
36
+ run: |
37
+ metadata_version=$(grep '^version=' "$PLUGIN_DIR/metadata.txt" | cut -d'=' -f2 | tr -d '[:space:]')
38
+ tag_version="${TAG#v}"
39
+ if [ "$metadata_version" != "$tag_version" ]; then
40
+ echo "::error::metadata.txt version ($metadata_version) does not match release tag ($tag_version)"
41
+ exit 1
42
+ fi
43
+
44
+ - name: Attach zip to GitHub release
45
+ env:
46
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
47
+ run: |
48
+ gh release upload "$TAG" "$ZIP_PATH" --clobber
49
+
50
+ - name: Upload to plugins.qgis.org
51
+ env:
52
+ QGIS_PLUGIN_REPO_USERNAME: ${{ secrets.QGIS_PLUGIN_REPO_USERNAME }}
53
+ QGIS_PLUGIN_REPO_PASSWORD: ${{ secrets.QGIS_PLUGIN_REPO_PASSWORD }}
54
+ run: python scripts/upload_to_qgis_plugin_repo.py "$ZIP_PATH"
@@ -28,7 +28,7 @@ jobs:
28
28
  - name: CHECKOUT CODE
29
29
  uses: actions/checkout@v6
30
30
  - name: Setup micromamba
31
- uses: mamba-org/setup-micromamba@v2
31
+ uses: mamba-org/setup-micromamba@v3
32
32
  with:
33
33
  environment-name: test-env
34
34
  create-args: >-
@@ -16,7 +16,7 @@ jobs:
16
16
  steps:
17
17
  - uses: actions/checkout@v6
18
18
  - name: Setup micromamba
19
- uses: mamba-org/setup-micromamba@v2
19
+ uses: mamba-org/setup-micromamba@v3
20
20
  with:
21
21
  environment-name: test-env
22
22
  create-args: >-
@@ -12,7 +12,7 @@ repos:
12
12
  args: ["--maxkb=500"]
13
13
 
14
14
  - repo: https://github.com/astral-sh/ruff-pre-commit
15
- rev: v0.15.6
15
+ rev: v0.15.16
16
16
  hooks:
17
17
  - id: ruff
18
18
  types_or: [pyi, jupyter]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: segment-geospatial
3
- Version: 1.3.1
3
+ Version: 1.3.3
4
4
  Summary: Meta AI's Segment Anything Model (SAM) for Geospatial Data.
5
5
  Author-email: Qiusheng Wu <giswqs@gmail.com>
6
6
  License: MIT license
@@ -0,0 +1,59 @@
1
+ # SAMGEO: Agent Harness SOP
2
+
3
+ ## Software Overview
4
+
5
+ **segment-geospatial** (samgeo) is a Python package for segmenting geospatial data
6
+ using Meta AI's Segment Anything Model (SAM) family. It wraps SAM v1, SAM 2, SAM 3,
7
+ FastSAM, HQ-SAM, and LangSAM with geospatial-aware I/O (GeoTIFF, GeoPackage, etc.).
8
+
9
+ ## Backend
10
+
11
+ The backend is the `samgeo` Python library itself. Unlike GUI applications that need
12
+ a headless CLI invocation, samgeo is already a Python library — the CLI harness imports
13
+ and calls its classes/functions directly.
14
+
15
+ **Key classes:**
16
+ - `SamGeo` (v1) — `samgeo.samgeo.SamGeo`
17
+ - `SamGeo2` (v2) — `samgeo.samgeo2.SamGeo2`
18
+ - `SamGeo3` (v3) — `samgeo.samgeo3.SamGeo3`
19
+ - `LangSAM` — `samgeo.text_sam.LangSAM`
20
+
21
+ **Key utility functions** (from `samgeo.common`):
22
+ - `tms_to_geotiff()` — Download TMS tiles as GeoTIFF
23
+ - `raster_to_vector()` / `raster_to_gpkg()` / `raster_to_shp()` / `raster_to_geojson()`
24
+ - `reproject()`, `split_raster()`, `image_to_cog()`
25
+ - `get_profile()`, `get_basemaps()`
26
+
27
+ ## Data Model
28
+
29
+ **Project state** is a JSON file tracking:
30
+ - Source image path, CRS, bounds
31
+ - Active model type and parameters
32
+ - Generated mask paths
33
+ - Vector output paths
34
+ - Operation history (for undo/redo)
35
+
36
+ **File formats:**
37
+ - Input: GeoTIFF, PNG, JPG, NumPy arrays, URLs
38
+ - Mask output: GeoTIFF (raster masks)
39
+ - Vector output: GeoPackage (.gpkg), Shapefile (.shp), GeoJSON (.geojson)
40
+ - Project: JSON (.json)
41
+
42
+ ## CLI Command Groups
43
+
44
+ | Group | Purpose |
45
+ |-------|---------|
46
+ | `project` | Create, open, save, inspect projects |
47
+ | `model` | List, download, inspect SAM models |
48
+ | `segment` | Automatic, point, box, and text segmentation |
49
+ | `data` | Download tiles, inspect rasters, reproject, split |
50
+ | `vector` | Convert masks to vectors, inspect, filter |
51
+ | `export` | Export masks and vectors to various formats |
52
+ | `session` | Undo/redo, history, session state |
53
+
54
+ ## Dependencies
55
+
56
+ - `segment-geospatial` (the package itself — hard dependency)
57
+ - `click` (CLI framework)
58
+ - `prompt_toolkit` (REPL)
59
+ - PyTorch + SAM model weights (downloaded on first use)
@@ -0,0 +1,148 @@
1
+ # cli-anything-samgeo
2
+
3
+ CLI harness for [segment-geospatial](https://github.com/opengeos/segment-geospatial) — segment geospatial imagery using SAM models from the command line.
4
+
5
+ ## Prerequisites
6
+
7
+ - Python 3.10+
8
+ - segment-geospatial: `pip install segment-geospatial[all]`
9
+ - PyTorch with CUDA (recommended) or CPU
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ cd agent-harness
15
+ pip install -e .
16
+ ```
17
+
18
+ This installs the `cli-anything-samgeo` command in your PATH.
19
+
20
+ ## Quick Start
21
+
22
+ ```bash
23
+ # Create a project
24
+ cli-anything-samgeo project new -n my-seg -o project.json -s image.tif
25
+
26
+ # Run automatic segmentation
27
+ cli-anything-samgeo --project project.json segment automatic -o masks.tif
28
+
29
+ # Convert masks to vectors
30
+ cli-anything-samgeo --project project.json vector convert masks.tif output.gpkg
31
+
32
+ # Export as GeoJSON
33
+ cli-anything-samgeo --project project.json export render output.geojson -f geojson
34
+
35
+ # All commands support --json for machine-readable output
36
+ cli-anything-samgeo --json model list
37
+ ```
38
+
39
+ ## Command Groups
40
+
41
+ | Command | Description |
42
+ |---------|-------------|
43
+ | `project` | Create, open, inspect projects |
44
+ | `model` | List, inspect, check SAM models |
45
+ | `segment` | Automatic, point, box, text segmentation |
46
+ | `data` | Download tiles, raster info, reproject, split |
47
+ | `vector` | Convert masks to vectors, inspect, filter |
48
+ | `export` | Export masks to various formats |
49
+ | `session` | Session status and history |
50
+
51
+ ## Interactive REPL
52
+
53
+ Run without arguments to enter the interactive REPL:
54
+
55
+ ```bash
56
+ cli-anything-samgeo
57
+ ```
58
+
59
+ ## JSON Output
60
+
61
+ Add `--json` before any command for machine-readable output:
62
+
63
+ ```bash
64
+ cli-anything-samgeo --json data info image.tif
65
+ cli-anything-samgeo --json model list
66
+ ```
67
+
68
+ ## Using with Claude Code
69
+
70
+ This CLI ships with a `SKILL.md` file that lets Claude Code discover and use all
71
+ commands automatically. There are two ways to enable it.
72
+
73
+ ### Option 1: Add SKILL.md to your CLAUDE.md
74
+
75
+ Append a reference to the skill file in your project or user `CLAUDE.md`:
76
+
77
+ ```markdown
78
+ # In your CLAUDE.md
79
+ Read the skill file at /path/to/agent-harness/cli_anything/samgeo/skills/SKILL.md
80
+ for the full cli-anything-samgeo command reference. Use `--json` for all
81
+ cli-anything-samgeo commands so output is machine-readable.
82
+ ```
83
+
84
+ Replace `/path/to/` with the actual absolute path. Claude Code reads `CLAUDE.md`
85
+ at the start of every conversation, so it will know the CLI exists and how to
86
+ call it.
87
+
88
+ ### Option 2: Point Claude Code at the skill on the fly
89
+
90
+ In any Claude Code conversation, paste:
91
+
92
+ ```
93
+ Read agent-harness/cli_anything/samgeo/skills/SKILL.md and use that CLI
94
+ to segment this satellite image.
95
+ ```
96
+
97
+ Claude Code will read the skill file, learn the command syntax, and start
98
+ using `cli-anything-samgeo` with `--json` output.
99
+
100
+ ### Example Claude Code session
101
+
102
+ Once Claude Code knows about the skill, you can give it natural-language tasks:
103
+
104
+ ```
105
+ > Segment all buildings in satellite.tif and export the results as a GeoPackage.
106
+
107
+ # Claude Code will run:
108
+ cli-anything-samgeo --json project new -n buildings -o project.json -s satellite.tif -t sam2
109
+ cli-anything-samgeo --json --project project.json segment automatic -o masks.tif
110
+ cli-anything-samgeo --json vector convert masks.tif buildings.gpkg
111
+ ```
112
+
113
+ ```
114
+ > Download OpenStreetMap tiles for downtown Portland and tell me about the image.
115
+
116
+ # Claude Code will run:
117
+ cli-anything-samgeo --json data download-tiles -o portland.tif -b "-122.68,45.51,-122.66,45.53" -z 17
118
+ cli-anything-samgeo --json data info portland.tif
119
+ ```
120
+
121
+ ### Tips for Claude Code usage
122
+
123
+ - The `--json` flag is essential — it gives Claude Code structured output it can
124
+ parse and reason about, rather than human-formatted tables.
125
+ - The `--project` flag must appear *before* the command group (e.g.,
126
+ `--project proj.json segment automatic`, not `segment automatic --project proj.json`).
127
+ - Claude Code can chain multiple commands in sequence to build full pipelines
128
+ (download → segment → vectorize → export).
129
+ - Use `model check sam2` to let Claude Code verify a model backend is installed
130
+ before attempting segmentation.
131
+
132
+ ## Running Tests
133
+
134
+ ```bash
135
+ cd agent-harness
136
+ python -m pytest cli_anything/samgeo/tests/ -v -s
137
+ ```
138
+
139
+ ## Supported Models
140
+
141
+ | Type | Models | Install |
142
+ |------|--------|---------|
143
+ | SAM v1 | vit_h, vit_l, vit_b | `pip install segment-geospatial` |
144
+ | SAM 2 | hiera-tiny/small/base-plus/large | `pip install segment-geospatial[samgeo2]` |
145
+ | SAM 3 | facebook/sam3 | `pip install segment-geospatial[samgeo3]` |
146
+ | FastSAM | FastSAM-x, FastSAM-s | `pip install segment-geospatial[fast]` |
147
+ | HQ-SAM | vit_h, vit_l, vit_b, vit_tiny | `pip install segment-geospatial[hq]` |
148
+ | LangSAM | text-based (SAM2 backend) | `pip install segment-geospatial[text]` |
@@ -0,0 +1,3 @@
1
+ """cli-anything-samgeo: CLI harness for segment-geospatial."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,6 @@
1
+ """Allow running as python -m cli_anything.samgeo."""
2
+
3
+ from cli_anything.samgeo.samgeo_cli import cli
4
+
5
+ if __name__ == "__main__":
6
+ cli()
@@ -0,0 +1 @@
1
+ """Core modules for cli-anything-samgeo."""
@@ -0,0 +1,229 @@
1
+ """Data operations: download tiles, inspect rasters, reproject, split."""
2
+
3
+ import os
4
+
5
+ from cli_anything.samgeo.utils.samgeo_backend import (
6
+ get_common_module,
7
+ get_rasterio,
8
+ )
9
+
10
+
11
+ def raster_info(path):
12
+ """Get information about a raster file.
13
+
14
+ Args:
15
+ path: Path to the raster file.
16
+
17
+ Returns:
18
+ dict: Raster metadata.
19
+ """
20
+ rasterio = get_rasterio()
21
+ path = os.path.abspath(path)
22
+
23
+ if not os.path.exists(path):
24
+ raise FileNotFoundError(f"Raster file not found: {path}")
25
+
26
+ with rasterio.open(path) as src:
27
+ info = {
28
+ "path": path,
29
+ "driver": src.driver,
30
+ "crs": str(src.crs) if src.crs else None,
31
+ "width": src.width,
32
+ "height": src.height,
33
+ "bands": src.count,
34
+ "dtype": str(src.dtypes[0]) if src.dtypes else None,
35
+ "bounds": {
36
+ "left": src.bounds.left,
37
+ "bottom": src.bounds.bottom,
38
+ "right": src.bounds.right,
39
+ "top": src.bounds.top,
40
+ },
41
+ "transform": list(src.transform)[:6],
42
+ "nodata": src.nodata,
43
+ "file_size": os.path.getsize(path),
44
+ }
45
+
46
+ return info
47
+
48
+
49
+ def download_tiles(
50
+ output,
51
+ bbox,
52
+ zoom=None,
53
+ resolution=None,
54
+ source="OpenStreetMap",
55
+ crs="EPSG:3857",
56
+ to_cog=False,
57
+ **kwargs,
58
+ ):
59
+ """Download TMS tiles as a GeoTIFF.
60
+
61
+ Args:
62
+ output: Output file path.
63
+ bbox: Bounding box as [west, south, east, north].
64
+ zoom: Zoom level. If None, auto-detected from resolution.
65
+ resolution: Resolution in meters. Alternative to zoom.
66
+ source: Tile source name or URL.
67
+ crs: Output CRS.
68
+ to_cog: Whether to convert to Cloud-Optimized GeoTIFF.
69
+ **kwargs: Additional kwargs.
70
+
71
+ Returns:
72
+ dict: Result with output path and file size.
73
+ """
74
+ common = get_common_module()
75
+ output = os.path.abspath(output)
76
+ parent = os.path.dirname(output)
77
+ if parent:
78
+ os.makedirs(parent, exist_ok=True)
79
+
80
+ common.tms_to_geotiff(
81
+ output=output,
82
+ bbox=bbox,
83
+ zoom=zoom,
84
+ resolution=resolution,
85
+ source=source,
86
+ crs=crs,
87
+ to_cog=to_cog,
88
+ **kwargs,
89
+ )
90
+
91
+ result = {
92
+ "output": output,
93
+ "file_size": os.path.getsize(output) if os.path.exists(output) else 0,
94
+ "bbox": bbox,
95
+ "zoom": zoom,
96
+ "source": source,
97
+ "crs": crs,
98
+ }
99
+
100
+ return result
101
+
102
+
103
+ def reproject_raster(
104
+ input_path, output_path, dst_crs="EPSG:4326", resampling="nearest", to_cog=True
105
+ ):
106
+ """Reproject a raster file to a new CRS.
107
+
108
+ Args:
109
+ input_path: Input raster path.
110
+ output_path: Output raster path.
111
+ dst_crs: Target CRS.
112
+ resampling: Resampling method.
113
+ to_cog: Whether to output as COG.
114
+
115
+ Returns:
116
+ dict: Result with output path and new CRS.
117
+ """
118
+ common = get_common_module()
119
+ input_path = os.path.abspath(input_path)
120
+ output_path = os.path.abspath(output_path)
121
+
122
+ if not os.path.exists(input_path):
123
+ raise FileNotFoundError(f"Input raster not found: {input_path}")
124
+
125
+ parent = os.path.dirname(output_path)
126
+ if parent:
127
+ os.makedirs(parent, exist_ok=True)
128
+
129
+ common.reproject(
130
+ image=input_path,
131
+ output=output_path,
132
+ dst_crs=dst_crs,
133
+ resampling=resampling,
134
+ to_cog=to_cog,
135
+ )
136
+
137
+ result = {
138
+ "input": input_path,
139
+ "output": output_path,
140
+ "dst_crs": dst_crs,
141
+ "file_size": os.path.getsize(output_path) if os.path.exists(output_path) else 0,
142
+ }
143
+
144
+ return result
145
+
146
+
147
+ def split_raster_tiles(input_path, out_dir, tile_size=256, overlap=0):
148
+ """Split a raster into tiles.
149
+
150
+ Args:
151
+ input_path: Input raster path.
152
+ out_dir: Output directory for tiles.
153
+ tile_size: Tile size in pixels (int or [width, height]).
154
+ overlap: Overlap in pixels.
155
+
156
+ Returns:
157
+ dict: Result with tile count and output directory.
158
+ """
159
+ common = get_common_module()
160
+ input_path = os.path.abspath(input_path)
161
+ out_dir = os.path.abspath(out_dir)
162
+
163
+ if not os.path.exists(input_path):
164
+ raise FileNotFoundError(f"Input raster not found: {input_path}")
165
+
166
+ os.makedirs(out_dir, exist_ok=True)
167
+
168
+ common.split_raster(
169
+ filename=input_path,
170
+ out_dir=out_dir,
171
+ tile_size=tile_size,
172
+ overlap=overlap,
173
+ )
174
+
175
+ tiles = [f for f in os.listdir(out_dir) if f.endswith((".tif", ".tiff"))]
176
+
177
+ result = {
178
+ "input": input_path,
179
+ "output_dir": out_dir,
180
+ "tile_count": len(tiles),
181
+ "tile_size": tile_size,
182
+ "overlap": overlap,
183
+ }
184
+
185
+ return result
186
+
187
+
188
+ def image_to_cog(source, output=None, profile="deflate"):
189
+ """Convert a raster to Cloud-Optimized GeoTIFF.
190
+
191
+ Args:
192
+ source: Input raster path.
193
+ output: Output path. If None, writes to a new *_cog.tif file
194
+ alongside the source.
195
+ profile: COG profile.
196
+
197
+ Returns:
198
+ dict: Result with output path.
199
+ """
200
+ common = get_common_module()
201
+ source = os.path.abspath(source)
202
+
203
+ if not os.path.exists(source):
204
+ raise FileNotFoundError(f"Source raster not found: {source}")
205
+
206
+ common.image_to_cog(source=source, dst_path=output, profile=profile)
207
+
208
+ out = output or source
209
+ result = {
210
+ "output": os.path.abspath(out),
211
+ "file_size": os.path.getsize(out) if os.path.exists(out) else 0,
212
+ "profile": profile,
213
+ }
214
+
215
+ return result
216
+
217
+
218
+ def list_basemaps(free_only=True):
219
+ """List available TMS basemap sources.
220
+
221
+ Args:
222
+ free_only: Only list free tile services.
223
+
224
+ Returns:
225
+ list: List of basemap names.
226
+ """
227
+ common = get_common_module()
228
+ basemaps = common.get_basemaps(free_only=free_only)
229
+ return sorted(basemaps.keys()) if isinstance(basemaps, dict) else sorted(basemaps)