copick-utils 0.6.1__tar.gz → 1.0.0__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.
- {copick_utils-0.6.1 → copick_utils-1.0.0}/.github/workflows/conventional-commits.yml +1 -1
- {copick_utils-0.6.1 → copick_utils-1.0.0}/.github/workflows/py-formatting.yml +2 -2
- {copick_utils-0.6.1 → copick_utils-1.0.0}/.github/workflows/release-please.yml +2 -2
- copick_utils-1.0.0/.release-please.manifest.json +3 -0
- copick_utils-1.0.0/CHANGELOG.md +36 -0
- {copick_utils-0.6.1 → copick_utils-1.0.0}/PKG-INFO +15 -2
- {copick_utils-0.6.1 → copick_utils-1.0.0}/pyproject.toml +44 -1
- {copick_utils-0.6.1 → copick_utils-1.0.0}/src/copick_utils/__init__.py +1 -1
- copick_utils-1.0.0/src/copick_utils/cli/__init__.py +33 -0
- copick_utils-1.0.0/src/copick_utils/cli/clipmesh.py +161 -0
- copick_utils-1.0.0/src/copick_utils/cli/clippicks.py +154 -0
- copick_utils-1.0.0/src/copick_utils/cli/clipseg.py +163 -0
- copick_utils-1.0.0/src/copick_utils/cli/conversion_commands.py +32 -0
- copick_utils-1.0.0/src/copick_utils/cli/enclosed.py +191 -0
- copick_utils-1.0.0/src/copick_utils/cli/filter_components.py +166 -0
- copick_utils-1.0.0/src/copick_utils/cli/fit_spline.py +191 -0
- copick_utils-1.0.0/src/copick_utils/cli/hull.py +138 -0
- copick_utils-1.0.0/src/copick_utils/cli/input_output_selection.py +76 -0
- copick_utils-1.0.0/src/copick_utils/cli/logical_commands.py +29 -0
- copick_utils-1.0.0/src/copick_utils/cli/mesh2picks.py +170 -0
- copick_utils-1.0.0/src/copick_utils/cli/mesh2seg.py +167 -0
- copick_utils-1.0.0/src/copick_utils/cli/meshop.py +262 -0
- copick_utils-1.0.0/src/copick_utils/cli/picks2ellipsoid.py +171 -0
- copick_utils-1.0.0/src/copick_utils/cli/picks2mesh.py +181 -0
- copick_utils-1.0.0/src/copick_utils/cli/picks2plane.py +156 -0
- copick_utils-1.0.0/src/copick_utils/cli/picks2seg.py +134 -0
- copick_utils-1.0.0/src/copick_utils/cli/picks2sphere.py +170 -0
- copick_utils-1.0.0/src/copick_utils/cli/picks2surface.py +164 -0
- copick_utils-1.0.0/src/copick_utils/cli/picksin.py +146 -0
- copick_utils-1.0.0/src/copick_utils/cli/picksout.py +148 -0
- copick_utils-1.0.0/src/copick_utils/cli/processing_commands.py +18 -0
- copick_utils-1.0.0/src/copick_utils/cli/seg2mesh.py +135 -0
- copick_utils-1.0.0/src/copick_utils/cli/seg2picks.py +128 -0
- copick_utils-1.0.0/src/copick_utils/cli/segop.py +248 -0
- copick_utils-1.0.0/src/copick_utils/cli/separate_components.py +155 -0
- copick_utils-1.0.0/src/copick_utils/cli/skeletonize.py +164 -0
- copick_utils-1.0.0/src/copick_utils/cli/util.py +580 -0
- copick_utils-1.0.0/src/copick_utils/cli/validbox.py +155 -0
- copick_utils-1.0.0/src/copick_utils/converters/__init__.py +35 -0
- copick_utils-1.0.0/src/copick_utils/converters/converter_common.py +543 -0
- copick_utils-1.0.0/src/copick_utils/converters/ellipsoid_from_picks.py +335 -0
- copick_utils-1.0.0/src/copick_utils/converters/lazy_converter.py +576 -0
- copick_utils-1.0.0/src/copick_utils/converters/mesh_from_picks.py +209 -0
- copick_utils-1.0.0/src/copick_utils/converters/mesh_from_segmentation.py +119 -0
- copick_utils-1.0.0/src/copick_utils/converters/picks_from_mesh.py +542 -0
- copick_utils-1.0.0/src/copick_utils/converters/picks_from_segmentation.py +168 -0
- copick_utils-1.0.0/src/copick_utils/converters/plane_from_picks.py +251 -0
- copick_utils-1.0.0/src/copick_utils/converters/segmentation_from_mesh.py +291 -0
- {copick_utils-0.6.1/src/copick_utils/segmentation → copick_utils-1.0.0/src/copick_utils/converters}/segmentation_from_picks.py +123 -13
- copick_utils-1.0.0/src/copick_utils/converters/sphere_from_picks.py +306 -0
- copick_utils-1.0.0/src/copick_utils/converters/surface_from_picks.py +337 -0
- copick_utils-1.0.0/src/copick_utils/logical/__init__.py +43 -0
- copick_utils-1.0.0/src/copick_utils/logical/distance_operations.py +604 -0
- copick_utils-1.0.0/src/copick_utils/logical/enclosed_operations.py +222 -0
- copick_utils-1.0.0/src/copick_utils/logical/mesh_operations.py +443 -0
- copick_utils-1.0.0/src/copick_utils/logical/point_operations.py +303 -0
- copick_utils-1.0.0/src/copick_utils/logical/segmentation_operations.py +399 -0
- copick_utils-1.0.0/src/copick_utils/process/__init__.py +47 -0
- copick_utils-1.0.0/src/copick_utils/process/connected_components.py +360 -0
- copick_utils-1.0.0/src/copick_utils/process/filter_components.py +306 -0
- copick_utils-1.0.0/src/copick_utils/process/hull.py +106 -0
- copick_utils-1.0.0/src/copick_utils/process/skeletonize.py +326 -0
- copick_utils-1.0.0/src/copick_utils/process/spline_fitting.py +648 -0
- copick_utils-1.0.0/src/copick_utils/process/validbox.py +333 -0
- copick_utils-1.0.0/src/copick_utils/util/__init__.py +6 -0
- copick_utils-1.0.0/src/copick_utils/util/config_models.py +614 -0
- copick_utils-1.0.0/tests/__init__.py +15 -0
- copick_utils-0.6.1/.release-please.manifest.json +0 -3
- copick_utils-0.6.1/CHANGELOG.md +0 -15
- copick_utils-0.6.1/src/copick_utils/segmentation/picks_from_segmentation.py +0 -81
- copick_utils-0.6.1/tests/__init__.py +0 -3
- {copick_utils-0.6.1 → copick_utils-1.0.0}/.github/dependabot.yml +0 -0
- {copick_utils-0.6.1 → copick_utils-1.0.0}/.gitignore +0 -0
- {copick_utils-0.6.1 → copick_utils-1.0.0}/.pre-commit-config.yaml +0 -0
- {copick_utils-0.6.1 → copick_utils-1.0.0}/LICENSE +0 -0
- {copick_utils-0.6.1 → copick_utils-1.0.0}/README.md +0 -0
- {copick_utils-0.6.1 → copick_utils-1.0.0}/SECURITY.md +0 -0
- {copick_utils-0.6.1 → copick_utils-1.0.0}/examples/segmentation_example.ipynb +0 -0
- {copick_utils-0.6.1 → copick_utils-1.0.0}/release-please.config.json +0 -0
- {copick_utils-0.6.1 → copick_utils-1.0.0}/src/copick_utils/features/__init__.py +0 -0
- {copick_utils-0.6.1 → copick_utils-1.0.0}/src/copick_utils/features/skimage.py +0 -0
- {copick_utils-0.6.1/src/copick_utils/pickers → copick_utils-1.0.0/src/copick_utils/io}/__init__.py +0 -0
- {copick_utils-0.6.1 → copick_utils-1.0.0}/src/copick_utils/io/readers.py +0 -0
- {copick_utils-0.6.1 → copick_utils-1.0.0}/src/copick_utils/io/writers.py +0 -0
- {copick_utils-0.6.1/src/copick_utils/segmentation → copick_utils-1.0.0/src/copick_utils/pickers}/__init__.py +0 -0
- {copick_utils-0.6.1 → copick_utils-1.0.0}/src/copick_utils/pickers/grid_picker.py +0 -0
|
@@ -10,8 +10,8 @@ jobs:
|
|
|
10
10
|
name: pre-commit checks
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
12
|
steps:
|
|
13
|
-
- uses: actions/checkout@
|
|
14
|
-
- uses: actions/setup-python@
|
|
13
|
+
- uses: actions/checkout@v5
|
|
14
|
+
- uses: actions/setup-python@v6
|
|
15
15
|
with:
|
|
16
16
|
python-version: "3.12.5"
|
|
17
17
|
- name: Install action-validator with asdf
|
|
@@ -43,13 +43,13 @@ jobs:
|
|
|
43
43
|
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
|
|
44
44
|
steps:
|
|
45
45
|
- name: Checkout ref branch
|
|
46
|
-
uses: actions/checkout@
|
|
46
|
+
uses: actions/checkout@v5
|
|
47
47
|
with:
|
|
48
48
|
ref: ${{ github.ref }}
|
|
49
49
|
fetch-depth: 0
|
|
50
50
|
|
|
51
51
|
- name: Install uv
|
|
52
|
-
uses: astral-sh/setup-uv@
|
|
52
|
+
uses: astral-sh/setup-uv@v7
|
|
53
53
|
with:
|
|
54
54
|
version: "0.7.13"
|
|
55
55
|
python-version: "3.12"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [1.0.0](https://github.com/copick/copick-utils/compare/copick-utils-v0.6.1...copick-utils-v1.0.0) (2025-10-16)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* Conversion, logical and processing commands for copick-utils CLI ([#24](https://github.com/copick/copick-utils/issues/24))
|
|
9
|
+
|
|
10
|
+
### ✨ Features
|
|
11
|
+
|
|
12
|
+
* Conversion, logical and processing commands for copick-utils CLI ([#24](https://github.com/copick/copick-utils/issues/24)) ([d455fd2](https://github.com/copick/copick-utils/commit/d455fd217f4cd4edf18cfe8da48d951799fa272a))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### 🐞 Bug Fixes
|
|
16
|
+
|
|
17
|
+
* bump actions/checkout from 4 to 5 ([#22](https://github.com/copick/copick-utils/issues/22)) ([287ac56](https://github.com/copick/copick-utils/commit/287ac566545d5c8b496dfdc0ae7e18456337de52))
|
|
18
|
+
* bump actions/setup-python from 5 to 6 ([#25](https://github.com/copick/copick-utils/issues/25)) ([f3ed071](https://github.com/copick/copick-utils/commit/f3ed071dafa9469daee9f62a9a06319de4c76d63))
|
|
19
|
+
* bump astral-sh/setup-uv from 6 to 7 ([#30](https://github.com/copick/copick-utils/issues/30)) ([b3028ef](https://github.com/copick/copick-utils/commit/b3028ef908f0e0d42cf418abb5169ab3a87556eb))
|
|
20
|
+
* bump chanzuckerberg/github-actions from 6.4.0 to 6.5.0 ([#20](https://github.com/copick/copick-utils/issues/20)) ([13056ae](https://github.com/copick/copick-utils/commit/13056ae6ee0fc0132c20b5f0539614c9d4d4aa24))
|
|
21
|
+
* bump chanzuckerberg/github-actions from 6.5.0 to 6.6.0 ([#23](https://github.com/copick/copick-utils/issues/23)) ([2c6a994](https://github.com/copick/copick-utils/commit/2c6a99497098073cecb52b5094da9f6ede040c4a))
|
|
22
|
+
* bump chanzuckerberg/github-actions from 6.6.0 to 6.10.0 ([#29](https://github.com/copick/copick-utils/issues/29)) ([bb50f1e](https://github.com/copick/copick-utils/commit/bb50f1ee9070cf33cee6d78e64aefe5063e5f0eb))
|
|
23
|
+
|
|
24
|
+
## [0.6.1](https://github.com/copick/copick-utils/compare/copick-utils-v0.6.0...copick-utils-v0.6.1) (2025-07-16)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### 🐞 Bug Fixes
|
|
28
|
+
|
|
29
|
+
* bump actions/checkout from 3 to 4 ([#19](https://github.com/copick/copick-utils/issues/19)) ([570072f](https://github.com/copick/copick-utils/commit/570072f708ea47b54d00fcc24451401896c91e25))
|
|
30
|
+
* bump actions/setup-python from 4 to 5 ([#17](https://github.com/copick/copick-utils/issues/17)) ([95c4784](https://github.com/copick/copick-utils/commit/95c47842e6a271ae40f69a9f9a578ef55d3d318b))
|
|
31
|
+
* bump asdf-vm/actions from 3 to 4 ([#18](https://github.com/copick/copick-utils/issues/18)) ([039b576](https://github.com/copick/copick-utils/commit/039b5761c4bc6b128f1bfef1aa2e7bf612f42ea3))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### 🧹 Miscellaneous Chores
|
|
35
|
+
|
|
36
|
+
* Set up CI for copick-utils ([#14](https://github.com/copick/copick-utils/issues/14)) ([0fbcfbb](https://github.com/copick/copick-utils/commit/0fbcfbb5bc12261da52e0850531195049328c2f9))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: copick-utils
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: Utilities for copick
|
|
5
5
|
Project-URL: Repository, https://github.com/KyleHarrington/copick-utils.git
|
|
6
6
|
Project-URL: Issues, https://github.com/KyleHarrington/copick-utils/issues
|
|
@@ -28,7 +28,20 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
28
28
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
29
29
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
30
30
|
Requires-Python: >=3.9
|
|
31
|
-
Requires-Dist:
|
|
31
|
+
Requires-Dist: click
|
|
32
|
+
Requires-Dist: click-option-group
|
|
33
|
+
Requires-Dist: copick>=1.16.0
|
|
34
|
+
Requires-Dist: manifold3d
|
|
35
|
+
Requires-Dist: mapbox-earcut
|
|
36
|
+
Requires-Dist: numpy
|
|
37
|
+
Requires-Dist: rtree
|
|
38
|
+
Requires-Dist: scikit-image
|
|
39
|
+
Requires-Dist: scikit-learn
|
|
40
|
+
Requires-Dist: scipy
|
|
41
|
+
Requires-Dist: shapely
|
|
42
|
+
Requires-Dist: tqdm
|
|
43
|
+
Requires-Dist: trimesh
|
|
44
|
+
Requires-Dist: zarr
|
|
32
45
|
Provides-Extra: dev
|
|
33
46
|
Requires-Dist: black>=25.1.0; extra == 'dev'
|
|
34
47
|
Requires-Dist: hatch-vcs>=0.4.0; extra == 'dev'
|
|
@@ -19,7 +19,20 @@ classifiers = [
|
|
|
19
19
|
]
|
|
20
20
|
dynamic = ["version"]
|
|
21
21
|
dependencies = [
|
|
22
|
-
"copick>=
|
|
22
|
+
"copick>=1.16.0",
|
|
23
|
+
"click",
|
|
24
|
+
"click-option-group",
|
|
25
|
+
"numpy",
|
|
26
|
+
"scipy",
|
|
27
|
+
"scikit-image",
|
|
28
|
+
"zarr",
|
|
29
|
+
"trimesh",
|
|
30
|
+
"manifold3d",
|
|
31
|
+
"mapbox-earcut",
|
|
32
|
+
"tqdm",
|
|
33
|
+
"scikit-learn",
|
|
34
|
+
"shapely",
|
|
35
|
+
"rtree"
|
|
23
36
|
]
|
|
24
37
|
authors = [
|
|
25
38
|
{ name = "Kyle Harrington", email = "czi@kyleharrington.com" },
|
|
@@ -44,6 +57,36 @@ dev = [
|
|
|
44
57
|
"ruff>=0.12.0",
|
|
45
58
|
]
|
|
46
59
|
|
|
60
|
+
[project.entry-points."copick.convert.commands"]
|
|
61
|
+
picks2seg = "copick_utils.cli.conversion_commands:picks2seg"
|
|
62
|
+
seg2picks = "copick_utils.cli.conversion_commands:seg2picks"
|
|
63
|
+
mesh2seg = "copick_utils.cli.conversion_commands:mesh2seg"
|
|
64
|
+
seg2mesh = "copick_utils.cli.conversion_commands:seg2mesh"
|
|
65
|
+
mesh2picks = "copick_utils.cli.conversion_commands:mesh2picks"
|
|
66
|
+
picks2mesh = "copick_utils.cli.conversion_commands:picks2mesh"
|
|
67
|
+
picks2sphere = "copick_utils.cli.conversion_commands:picks2sphere"
|
|
68
|
+
picks2ellipsoid = "copick_utils.cli.conversion_commands:picks2ellipsoid"
|
|
69
|
+
picks2plane = "copick_utils.cli.conversion_commands:picks2plane"
|
|
70
|
+
picks2surface = "copick_utils.cli.conversion_commands:picks2surface"
|
|
71
|
+
|
|
72
|
+
[project.entry-points."copick.process.commands"]
|
|
73
|
+
separate_components = "copick_utils.cli.processing_commands:separate_components"
|
|
74
|
+
filter_components = "copick_utils.cli.processing_commands:filter_components"
|
|
75
|
+
skeletonize = "copick_utils.cli.processing_commands:skeletonize"
|
|
76
|
+
fit_spline = "copick_utils.cli.processing_commands:fit_spline"
|
|
77
|
+
validbox = "copick_utils.cli.processing_commands:validbox"
|
|
78
|
+
hull = "copick_utils.cli.processing_commands:hull"
|
|
79
|
+
|
|
80
|
+
[project.entry-points."copick.logical.commands"]
|
|
81
|
+
meshop = "copick_utils.cli.logical_commands:meshop"
|
|
82
|
+
segop = "copick_utils.cli.logical_commands:segop"
|
|
83
|
+
enclosed = "copick_utils.cli.logical_commands:enclosed"
|
|
84
|
+
clipmesh = "copick_utils.cli.logical_commands:clipmesh"
|
|
85
|
+
clipseg = "copick_utils.cli.logical_commands:clipseg"
|
|
86
|
+
clippicks = "copick_utils.cli.logical_commands:clippicks"
|
|
87
|
+
picksin = "copick_utils.cli.logical_commands:picksin"
|
|
88
|
+
picksout = "copick_utils.cli.logical_commands:picksout"
|
|
89
|
+
|
|
47
90
|
[tool.hatch.version]
|
|
48
91
|
path = "src/copick_utils/__init__.py"
|
|
49
92
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""CLI commands for copick-utils."""
|
|
2
|
+
|
|
3
|
+
from .conversion_commands import (
|
|
4
|
+
mesh2picks,
|
|
5
|
+
mesh2seg,
|
|
6
|
+
picks2ellipsoid,
|
|
7
|
+
picks2mesh,
|
|
8
|
+
picks2plane,
|
|
9
|
+
picks2seg,
|
|
10
|
+
picks2sphere,
|
|
11
|
+
picks2surface,
|
|
12
|
+
seg2mesh,
|
|
13
|
+
seg2picks,
|
|
14
|
+
)
|
|
15
|
+
from .processing_commands import fit_spline, separate_components, skeletonize
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
# Conversion commands
|
|
19
|
+
"picks2seg",
|
|
20
|
+
"seg2picks",
|
|
21
|
+
"mesh2seg",
|
|
22
|
+
"seg2mesh",
|
|
23
|
+
"picks2mesh",
|
|
24
|
+
"mesh2picks",
|
|
25
|
+
"picks2surface",
|
|
26
|
+
"picks2plane",
|
|
27
|
+
"picks2sphere",
|
|
28
|
+
"picks2ellipsoid",
|
|
29
|
+
# Processing commands
|
|
30
|
+
"separate_components",
|
|
31
|
+
"skeletonize",
|
|
32
|
+
"fit_spline",
|
|
33
|
+
]
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import copick
|
|
3
|
+
from click_option_group import optgroup
|
|
4
|
+
from copick.cli.util import add_config_option, add_debug_option
|
|
5
|
+
from copick.util.log import get_logger
|
|
6
|
+
from copick.util.uri import parse_copick_uri
|
|
7
|
+
|
|
8
|
+
from copick_utils.cli.util import (
|
|
9
|
+
add_distance_options,
|
|
10
|
+
add_input_option,
|
|
11
|
+
add_output_option,
|
|
12
|
+
add_reference_mesh_option,
|
|
13
|
+
add_reference_seg_option,
|
|
14
|
+
add_workers_option,
|
|
15
|
+
)
|
|
16
|
+
from copick_utils.util.config_models import create_reference_config
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@click.command(
|
|
20
|
+
context_settings={"show_default": True},
|
|
21
|
+
short_help="Limit meshes to vertices within distance of a reference surface.",
|
|
22
|
+
no_args_is_help=True,
|
|
23
|
+
)
|
|
24
|
+
@add_config_option
|
|
25
|
+
@optgroup.group("\nInput Options", help="Options related to the input meshes.")
|
|
26
|
+
@optgroup.option(
|
|
27
|
+
"--run-names",
|
|
28
|
+
"-r",
|
|
29
|
+
multiple=True,
|
|
30
|
+
help="Specific run names to process (default: all runs).",
|
|
31
|
+
)
|
|
32
|
+
@add_input_option("mesh")
|
|
33
|
+
@optgroup.group("\nReference Options", help="Options for reference surface (provide either mesh or segmentation).")
|
|
34
|
+
@add_reference_mesh_option(required=False)
|
|
35
|
+
@add_reference_seg_option(required=False)
|
|
36
|
+
@optgroup.group("\nTool Options", help="Options related to this tool.")
|
|
37
|
+
@add_distance_options
|
|
38
|
+
@add_workers_option
|
|
39
|
+
@optgroup.group("\nOutput Options", help="Options related to output meshes.")
|
|
40
|
+
@add_output_option("mesh", default_tool="clipmesh")
|
|
41
|
+
@optgroup.option(
|
|
42
|
+
"--individual-meshes/--no-individual-meshes",
|
|
43
|
+
"-im",
|
|
44
|
+
is_flag=True,
|
|
45
|
+
default=False,
|
|
46
|
+
help="Create individual meshes for each instance (enables {instance_id} placeholder).",
|
|
47
|
+
)
|
|
48
|
+
@add_debug_option
|
|
49
|
+
def clipmesh(
|
|
50
|
+
config,
|
|
51
|
+
run_names,
|
|
52
|
+
input_uri,
|
|
53
|
+
ref_mesh_uri,
|
|
54
|
+
ref_seg_uri,
|
|
55
|
+
max_distance,
|
|
56
|
+
mesh_voxel_spacing,
|
|
57
|
+
workers,
|
|
58
|
+
output_uri,
|
|
59
|
+
individual_meshes,
|
|
60
|
+
debug,
|
|
61
|
+
):
|
|
62
|
+
"""
|
|
63
|
+
Limit meshes to vertices within a certain distance of a reference surface.
|
|
64
|
+
|
|
65
|
+
\b
|
|
66
|
+
URI Format:
|
|
67
|
+
Meshes: object_name:user_id/session_id
|
|
68
|
+
Segmentations: name:user_id/session_id@voxel_spacing
|
|
69
|
+
|
|
70
|
+
\b
|
|
71
|
+
The reference surface can be either a mesh or a segmentation.
|
|
72
|
+
Only mesh vertices within the specified distance will be kept.
|
|
73
|
+
|
|
74
|
+
\b
|
|
75
|
+
Examples:
|
|
76
|
+
# Limit mesh to vertices near reference mesh surface
|
|
77
|
+
copick logical clipmesh -i "membrane:user1/full-001" -rm "boundary:user1/boundary-001" -o "membrane:clipmesh/limited-001" --max-distance 50.0
|
|
78
|
+
|
|
79
|
+
# Limit using segmentation as reference
|
|
80
|
+
copick logical clipmesh -i "membrane:user1/full-001" -rs "mask:user1/mask-001@10.0" -o "membrane:clipmesh/limited-001" --max-distance 100.0
|
|
81
|
+
"""
|
|
82
|
+
from copick_utils.logical.distance_operations import limit_mesh_by_distance_lazy_batch
|
|
83
|
+
|
|
84
|
+
logger = get_logger(__name__, debug=debug)
|
|
85
|
+
|
|
86
|
+
# Validate that exactly one reference type is provided
|
|
87
|
+
if not ref_mesh_uri and not ref_seg_uri:
|
|
88
|
+
raise click.BadParameter("Must provide either --ref-mesh or --ref-seg")
|
|
89
|
+
if ref_mesh_uri and ref_seg_uri:
|
|
90
|
+
raise click.BadParameter("Cannot provide both --ref-mesh and --ref-seg")
|
|
91
|
+
|
|
92
|
+
root = copick.from_file(config)
|
|
93
|
+
run_names_list = list(run_names) if run_names else None
|
|
94
|
+
|
|
95
|
+
# Determine reference type and URI
|
|
96
|
+
reference_uri = ref_mesh_uri or ref_seg_uri
|
|
97
|
+
reference_type = "mesh" if ref_mesh_uri else "segmentation"
|
|
98
|
+
|
|
99
|
+
# Create config directly from URIs with additional params for distance operations
|
|
100
|
+
try:
|
|
101
|
+
task_config = create_reference_config(
|
|
102
|
+
input_uri=input_uri,
|
|
103
|
+
input_type="mesh",
|
|
104
|
+
output_uri=output_uri,
|
|
105
|
+
output_type="mesh",
|
|
106
|
+
reference_uri=reference_uri,
|
|
107
|
+
reference_type=reference_type,
|
|
108
|
+
additional_params={"max_distance": max_distance, "mesh_voxel_spacing": mesh_voxel_spacing},
|
|
109
|
+
command_name="clipmesh",
|
|
110
|
+
)
|
|
111
|
+
except ValueError as e:
|
|
112
|
+
raise click.BadParameter(str(e)) from e
|
|
113
|
+
|
|
114
|
+
# Extract parameters for logging
|
|
115
|
+
input_params = parse_copick_uri(input_uri, "mesh")
|
|
116
|
+
output_params = parse_copick_uri(output_uri, "mesh")
|
|
117
|
+
ref_params = parse_copick_uri(reference_uri, reference_type)
|
|
118
|
+
|
|
119
|
+
logger.info(f"Limiting meshes by distance for object '{input_params['object_name']}'")
|
|
120
|
+
logger.info(f"Source mesh pattern: {input_params['user_id']}/{input_params['session_id']}")
|
|
121
|
+
if reference_type == "mesh":
|
|
122
|
+
logger.info(f"Reference mesh: {ref_params['object_name']} ({ref_params['user_id']}/{ref_params['session_id']})")
|
|
123
|
+
else:
|
|
124
|
+
logger.info(
|
|
125
|
+
f"Reference segmentation: {ref_params['name']} ({ref_params['user_id']}/{ref_params['session_id']})",
|
|
126
|
+
)
|
|
127
|
+
logger.info(f"Maximum distance: {max_distance} angstroms")
|
|
128
|
+
logger.info(
|
|
129
|
+
f"Target mesh template: {output_params['object_name']} ({output_params['user_id']}/{output_params['session_id']})",
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Parallel discovery and processing - no sequential bottleneck!
|
|
133
|
+
results = limit_mesh_by_distance_lazy_batch(
|
|
134
|
+
root=root,
|
|
135
|
+
config=task_config,
|
|
136
|
+
run_names=run_names_list,
|
|
137
|
+
workers=workers,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
successful = sum(1 for result in results.values() if result and result.get("processed", 0) > 0)
|
|
141
|
+
total_vertices = sum(result.get("vertices_created", 0) for result in results.values() if result)
|
|
142
|
+
total_faces = sum(result.get("faces_created", 0) for result in results.values() if result)
|
|
143
|
+
total_processed = sum(result.get("processed", 0) for result in results.values() if result)
|
|
144
|
+
|
|
145
|
+
# Collect all errors
|
|
146
|
+
all_errors = []
|
|
147
|
+
for result in results.values():
|
|
148
|
+
if result and result.get("errors"):
|
|
149
|
+
all_errors.extend(result["errors"])
|
|
150
|
+
|
|
151
|
+
logger.info(f"Completed: {successful}/{len(results)} runs processed successfully")
|
|
152
|
+
logger.info(f"Total distance limiting operations completed: {total_processed}")
|
|
153
|
+
logger.info(f"Total vertices created: {total_vertices}")
|
|
154
|
+
logger.info(f"Total faces created: {total_faces}")
|
|
155
|
+
|
|
156
|
+
if all_errors:
|
|
157
|
+
logger.warning(f"Encountered {len(all_errors)} errors during processing")
|
|
158
|
+
for error in all_errors[:5]: # Show first 5 errors
|
|
159
|
+
logger.warning(f" - {error}")
|
|
160
|
+
if len(all_errors) > 5:
|
|
161
|
+
logger.warning(f" ... and {len(all_errors) - 5} more errors")
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""CLI commands for distance-based limiting operations."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
import copick
|
|
5
|
+
from click_option_group import optgroup
|
|
6
|
+
from copick.cli.util import add_config_option, add_debug_option
|
|
7
|
+
from copick.util.log import get_logger
|
|
8
|
+
from copick.util.uri import parse_copick_uri
|
|
9
|
+
|
|
10
|
+
from copick_utils.cli.util import (
|
|
11
|
+
add_distance_options,
|
|
12
|
+
add_input_option,
|
|
13
|
+
add_output_option,
|
|
14
|
+
add_reference_mesh_option,
|
|
15
|
+
add_reference_seg_option,
|
|
16
|
+
add_workers_option,
|
|
17
|
+
)
|
|
18
|
+
from copick_utils.util.config_models import create_reference_config
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@click.command(
|
|
22
|
+
context_settings={"show_default": True},
|
|
23
|
+
short_help="Limit picks to those within distance of a reference surface.",
|
|
24
|
+
no_args_is_help=True,
|
|
25
|
+
)
|
|
26
|
+
@add_config_option
|
|
27
|
+
@optgroup.group("\nInput Options", help="Options related to the input picks.")
|
|
28
|
+
@optgroup.option(
|
|
29
|
+
"--run-names",
|
|
30
|
+
"-r",
|
|
31
|
+
multiple=True,
|
|
32
|
+
help="Specific run names to process (default: all runs).",
|
|
33
|
+
)
|
|
34
|
+
@add_input_option("picks")
|
|
35
|
+
@optgroup.group("\nReference Options", help="Options for reference surface (provide either mesh or segmentation).")
|
|
36
|
+
@add_reference_mesh_option(required=False)
|
|
37
|
+
@add_reference_seg_option(required=False)
|
|
38
|
+
@optgroup.group("\nTool Options", help="Options related to this tool.")
|
|
39
|
+
@add_distance_options
|
|
40
|
+
@add_workers_option
|
|
41
|
+
@optgroup.group("\nOutput Options", help="Options related to output picks.")
|
|
42
|
+
@add_output_option("picks", default_tool="clippicks")
|
|
43
|
+
@add_debug_option
|
|
44
|
+
def clippicks(
|
|
45
|
+
config,
|
|
46
|
+
run_names,
|
|
47
|
+
input_uri,
|
|
48
|
+
ref_mesh_uri,
|
|
49
|
+
ref_seg_uri,
|
|
50
|
+
max_distance,
|
|
51
|
+
mesh_voxel_spacing,
|
|
52
|
+
workers,
|
|
53
|
+
output_uri,
|
|
54
|
+
debug,
|
|
55
|
+
):
|
|
56
|
+
"""
|
|
57
|
+
Limit picks to those within a certain distance of a reference surface.
|
|
58
|
+
|
|
59
|
+
\b
|
|
60
|
+
URI Format:
|
|
61
|
+
Picks: object_name:user_id/session_id
|
|
62
|
+
Meshes: object_name:user_id/session_id
|
|
63
|
+
Segmentations: name:user_id/session_id@voxel_spacing
|
|
64
|
+
|
|
65
|
+
\b
|
|
66
|
+
The reference surface can be either a mesh or a segmentation.
|
|
67
|
+
Only picks within the specified distance will be kept.
|
|
68
|
+
|
|
69
|
+
\b
|
|
70
|
+
Examples:
|
|
71
|
+
# Limit picks to those near reference mesh surface
|
|
72
|
+
copick logical clippicks -i "ribosome:user1/all-001" -rm "boundary:user1/boundary-001" -o "ribosome:clippicks/limited-001" --max-distance 50.0
|
|
73
|
+
|
|
74
|
+
# Limit using segmentation as reference
|
|
75
|
+
copick logical clippicks -i "ribosome:user1/all-001" -rs "mask:user1/mask-001@10.0" -o "ribosome:clippicks/limited-001" --max-distance 100.0
|
|
76
|
+
"""
|
|
77
|
+
from copick_utils.logical.distance_operations import limit_picks_by_distance_lazy_batch
|
|
78
|
+
|
|
79
|
+
logger = get_logger(__name__, debug=debug)
|
|
80
|
+
|
|
81
|
+
# Validate that exactly one reference type is provided
|
|
82
|
+
if not ref_mesh_uri and not ref_seg_uri:
|
|
83
|
+
raise click.BadParameter("Must provide either --ref-mesh or --ref-seg")
|
|
84
|
+
if ref_mesh_uri and ref_seg_uri:
|
|
85
|
+
raise click.BadParameter("Cannot provide both --ref-mesh and --ref-seg")
|
|
86
|
+
|
|
87
|
+
root = copick.from_file(config)
|
|
88
|
+
run_names_list = list(run_names) if run_names else None
|
|
89
|
+
|
|
90
|
+
# Determine reference type and URI
|
|
91
|
+
reference_uri = ref_mesh_uri or ref_seg_uri
|
|
92
|
+
reference_type = "mesh" if ref_mesh_uri else "segmentation"
|
|
93
|
+
|
|
94
|
+
# Create config directly from URIs with additional params
|
|
95
|
+
try:
|
|
96
|
+
task_config = create_reference_config(
|
|
97
|
+
input_uri=input_uri,
|
|
98
|
+
input_type="picks",
|
|
99
|
+
output_uri=output_uri,
|
|
100
|
+
output_type="picks",
|
|
101
|
+
reference_uri=reference_uri,
|
|
102
|
+
reference_type=reference_type,
|
|
103
|
+
additional_params={"max_distance": max_distance, "mesh_voxel_spacing": mesh_voxel_spacing},
|
|
104
|
+
command_name="clippicks",
|
|
105
|
+
)
|
|
106
|
+
except ValueError as e:
|
|
107
|
+
raise click.BadParameter(str(e)) from e
|
|
108
|
+
|
|
109
|
+
# Extract parameters for logging
|
|
110
|
+
input_params = parse_copick_uri(input_uri, "picks")
|
|
111
|
+
output_params = parse_copick_uri(output_uri, "picks")
|
|
112
|
+
ref_params = parse_copick_uri(reference_uri, reference_type)
|
|
113
|
+
|
|
114
|
+
logger.info(f"Limiting picks by distance for object '{input_params['object_name']}'")
|
|
115
|
+
logger.info(f"Source picks pattern: {input_params['user_id']}/{input_params['session_id']}")
|
|
116
|
+
if reference_type == "mesh":
|
|
117
|
+
logger.info(f"Reference mesh: {ref_params['object_name']} ({ref_params['user_id']}/{ref_params['session_id']})")
|
|
118
|
+
else:
|
|
119
|
+
logger.info(
|
|
120
|
+
f"Reference segmentation: {ref_params['name']} ({ref_params['user_id']}/{ref_params['session_id']})",
|
|
121
|
+
)
|
|
122
|
+
logger.info(f"Maximum distance: {max_distance} angstroms")
|
|
123
|
+
logger.info(
|
|
124
|
+
f"Target picks template: {output_params['object_name']} ({output_params['user_id']}/{output_params['session_id']})",
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
# Parallel discovery and processing - no sequential bottleneck!
|
|
128
|
+
results = limit_picks_by_distance_lazy_batch(
|
|
129
|
+
root=root,
|
|
130
|
+
config=task_config,
|
|
131
|
+
run_names=run_names_list,
|
|
132
|
+
workers=workers,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
successful = sum(1 for result in results.values() if result and result.get("processed", 0) > 0)
|
|
136
|
+
total_points = sum(result.get("points_created", 0) for result in results.values() if result)
|
|
137
|
+
total_processed = sum(result.get("processed", 0) for result in results.values() if result)
|
|
138
|
+
|
|
139
|
+
# Collect all errors
|
|
140
|
+
all_errors = []
|
|
141
|
+
for result in results.values():
|
|
142
|
+
if result and result.get("errors"):
|
|
143
|
+
all_errors.extend(result["errors"])
|
|
144
|
+
|
|
145
|
+
logger.info(f"Completed: {successful}/{len(results)} runs processed successfully")
|
|
146
|
+
logger.info(f"Total distance limiting operations completed: {total_processed}")
|
|
147
|
+
logger.info(f"Total points created: {total_points}")
|
|
148
|
+
|
|
149
|
+
if all_errors:
|
|
150
|
+
logger.warning(f"Encountered {len(all_errors)} errors during processing")
|
|
151
|
+
for error in all_errors[:5]: # Show first 5 errors
|
|
152
|
+
logger.warning(f" - {error}")
|
|
153
|
+
if len(all_errors) > 5:
|
|
154
|
+
logger.warning(f" ... and {len(all_errors) - 5} more errors")
|