copick-utils 0.6.1__py3-none-any.whl → 1.0.1__py3-none-any.whl
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/__init__.py +1 -1
- copick_utils/cli/__init__.py +33 -0
- copick_utils/cli/clipmesh.py +161 -0
- copick_utils/cli/clippicks.py +154 -0
- copick_utils/cli/clipseg.py +163 -0
- copick_utils/cli/conversion_commands.py +32 -0
- copick_utils/cli/enclosed.py +191 -0
- copick_utils/cli/filter_components.py +166 -0
- copick_utils/cli/fit_spline.py +191 -0
- copick_utils/cli/hull.py +138 -0
- copick_utils/cli/input_output_selection.py +76 -0
- copick_utils/cli/logical_commands.py +29 -0
- copick_utils/cli/mesh2picks.py +170 -0
- copick_utils/cli/mesh2seg.py +167 -0
- copick_utils/cli/meshop.py +262 -0
- copick_utils/cli/picks2ellipsoid.py +171 -0
- copick_utils/cli/picks2mesh.py +181 -0
- copick_utils/cli/picks2plane.py +156 -0
- copick_utils/cli/picks2seg.py +134 -0
- copick_utils/cli/picks2sphere.py +170 -0
- copick_utils/cli/picks2surface.py +164 -0
- copick_utils/cli/picksin.py +146 -0
- copick_utils/cli/picksout.py +148 -0
- copick_utils/cli/processing_commands.py +18 -0
- copick_utils/cli/seg2mesh.py +135 -0
- copick_utils/cli/seg2picks.py +128 -0
- copick_utils/cli/segop.py +248 -0
- copick_utils/cli/separate_components.py +155 -0
- copick_utils/cli/skeletonize.py +164 -0
- copick_utils/cli/util.py +580 -0
- copick_utils/cli/validbox.py +155 -0
- copick_utils/converters/__init__.py +35 -0
- copick_utils/converters/converter_common.py +543 -0
- copick_utils/converters/ellipsoid_from_picks.py +335 -0
- copick_utils/converters/lazy_converter.py +576 -0
- copick_utils/converters/mesh_from_picks.py +209 -0
- copick_utils/converters/mesh_from_segmentation.py +119 -0
- copick_utils/converters/picks_from_mesh.py +542 -0
- copick_utils/converters/picks_from_segmentation.py +168 -0
- copick_utils/converters/plane_from_picks.py +251 -0
- copick_utils/converters/segmentation_from_mesh.py +291 -0
- copick_utils/{segmentation → converters}/segmentation_from_picks.py +123 -13
- copick_utils/converters/sphere_from_picks.py +306 -0
- copick_utils/converters/surface_from_picks.py +337 -0
- copick_utils/logical/__init__.py +43 -0
- copick_utils/logical/distance_operations.py +604 -0
- copick_utils/logical/enclosed_operations.py +222 -0
- copick_utils/logical/mesh_operations.py +443 -0
- copick_utils/logical/point_operations.py +303 -0
- copick_utils/logical/segmentation_operations.py +399 -0
- copick_utils/process/__init__.py +47 -0
- copick_utils/process/connected_components.py +360 -0
- copick_utils/process/filter_components.py +306 -0
- copick_utils/process/hull.py +106 -0
- copick_utils/process/skeletonize.py +326 -0
- copick_utils/process/spline_fitting.py +648 -0
- copick_utils/process/validbox.py +333 -0
- copick_utils/util/__init__.py +6 -0
- copick_utils/util/config_models.py +614 -0
- {copick_utils-0.6.1.dist-info → copick_utils-1.0.1.dist-info}/METADATA +15 -2
- copick_utils-1.0.1.dist-info/RECORD +71 -0
- {copick_utils-0.6.1.dist-info → copick_utils-1.0.1.dist-info}/WHEEL +1 -1
- copick_utils-1.0.1.dist-info/entry_points.txt +29 -0
- copick_utils/segmentation/picks_from_segmentation.py +0 -81
- copick_utils-0.6.1.dist-info/RECORD +0 -14
- /copick_utils/{segmentation → io}/__init__.py +0 -0
- {copick_utils-0.6.1.dist-info → copick_utils-1.0.1.dist-info}/licenses/LICENSE +0 -0
copick_utils/__init__.py
CHANGED
|
@@ -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")
|
|
@@ -0,0 +1,163 @@
|
|
|
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 segmentations to voxels 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 segmentations.")
|
|
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("segmentation")
|
|
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 segmentations.")
|
|
40
|
+
@add_output_option("segmentation", default_tool="clipseg")
|
|
41
|
+
@add_debug_option
|
|
42
|
+
def clipseg(
|
|
43
|
+
config,
|
|
44
|
+
run_names,
|
|
45
|
+
input_uri,
|
|
46
|
+
ref_mesh_uri,
|
|
47
|
+
ref_seg_uri,
|
|
48
|
+
max_distance,
|
|
49
|
+
mesh_voxel_spacing,
|
|
50
|
+
workers,
|
|
51
|
+
output_uri,
|
|
52
|
+
debug,
|
|
53
|
+
):
|
|
54
|
+
"""
|
|
55
|
+
Limit segmentations to voxels within a certain distance of a reference surface.
|
|
56
|
+
|
|
57
|
+
\b
|
|
58
|
+
URI Format:
|
|
59
|
+
Segmentations: name:user_id/session_id@voxel_spacing
|
|
60
|
+
Meshes: object_name:user_id/session_id
|
|
61
|
+
|
|
62
|
+
\b
|
|
63
|
+
The reference surface can be either a mesh or another segmentation.
|
|
64
|
+
Only segmentation voxels within the specified distance will be kept.
|
|
65
|
+
|
|
66
|
+
\b
|
|
67
|
+
Examples:
|
|
68
|
+
# Limit segmentation to voxels near reference mesh
|
|
69
|
+
copick logical clipseg -i "membrane:user1/full-001@10.0" -rm "boundary:user1/boundary-001" -o "membrane:clipseg/limited-001@10.0" --max-distance 50.0
|
|
70
|
+
|
|
71
|
+
# Limit using another segmentation as reference
|
|
72
|
+
copick logical clipseg -i "membrane:user1/full-001@10.0" -rs "mask:user1/mask-001@10.0" -o "membrane:clipseg/limited-001@10.0" --max-distance 100.0
|
|
73
|
+
"""
|
|
74
|
+
from copick_utils.logical.distance_operations import limit_segmentation_by_distance_lazy_batch
|
|
75
|
+
|
|
76
|
+
logger = get_logger(__name__, debug=debug)
|
|
77
|
+
|
|
78
|
+
# Validate that exactly one reference type is provided
|
|
79
|
+
if not ref_mesh_uri and not ref_seg_uri:
|
|
80
|
+
raise click.BadParameter("Must provide either --ref-mesh or --ref-seg")
|
|
81
|
+
if ref_mesh_uri and ref_seg_uri:
|
|
82
|
+
raise click.BadParameter("Cannot provide both --ref-mesh and --ref-seg")
|
|
83
|
+
|
|
84
|
+
root = copick.from_file(config)
|
|
85
|
+
run_names_list = list(run_names) if run_names else None
|
|
86
|
+
|
|
87
|
+
# Determine reference type and URI
|
|
88
|
+
reference_uri = ref_mesh_uri or ref_seg_uri
|
|
89
|
+
reference_type = "mesh" if ref_mesh_uri else "segmentation"
|
|
90
|
+
|
|
91
|
+
# Extract voxel_spacing and multilabel from output for additional_params
|
|
92
|
+
output_params_temp = parse_copick_uri(output_uri, "segmentation")
|
|
93
|
+
voxel_spacing_output = output_params_temp["voxel_spacing"]
|
|
94
|
+
if isinstance(voxel_spacing_output, str):
|
|
95
|
+
voxel_spacing_output = float(voxel_spacing_output)
|
|
96
|
+
multilabel_output = output_params_temp.get("multilabel") or False
|
|
97
|
+
|
|
98
|
+
# Create config directly from URIs with additional params and smart defaults
|
|
99
|
+
try:
|
|
100
|
+
task_config = create_reference_config(
|
|
101
|
+
input_uri=input_uri,
|
|
102
|
+
input_type="segmentation",
|
|
103
|
+
output_uri=output_uri,
|
|
104
|
+
output_type="segmentation",
|
|
105
|
+
reference_uri=reference_uri,
|
|
106
|
+
reference_type=reference_type,
|
|
107
|
+
additional_params={
|
|
108
|
+
"max_distance": max_distance,
|
|
109
|
+
"mesh_voxel_spacing": mesh_voxel_spacing,
|
|
110
|
+
"voxel_spacing": voxel_spacing_output,
|
|
111
|
+
"is_multilabel": multilabel_output,
|
|
112
|
+
},
|
|
113
|
+
command_name="clipseg",
|
|
114
|
+
)
|
|
115
|
+
except ValueError as e:
|
|
116
|
+
raise click.BadParameter(str(e)) from e
|
|
117
|
+
|
|
118
|
+
# Extract parameters for logging
|
|
119
|
+
input_params = parse_copick_uri(input_uri, "segmentation")
|
|
120
|
+
output_params = parse_copick_uri(output_uri, "segmentation")
|
|
121
|
+
ref_params = parse_copick_uri(reference_uri, reference_type)
|
|
122
|
+
|
|
123
|
+
logger.info(f"Limiting segmentations by distance for '{input_params['name']}'")
|
|
124
|
+
logger.info(f"Source segmentation pattern: {input_params['user_id']}/{input_params['session_id']}")
|
|
125
|
+
if reference_type == "mesh":
|
|
126
|
+
logger.info(f"Reference mesh: {ref_params['object_name']} ({ref_params['user_id']}/{ref_params['session_id']})")
|
|
127
|
+
else:
|
|
128
|
+
logger.info(
|
|
129
|
+
f"Reference segmentation: {ref_params['name']} ({ref_params['user_id']}/{ref_params['session_id']})",
|
|
130
|
+
)
|
|
131
|
+
logger.info(f"Maximum distance: {max_distance} angstroms")
|
|
132
|
+
logger.info(
|
|
133
|
+
f"Target segmentation template: {output_params['name']} ({output_params['user_id']}/{output_params['session_id']})",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# Parallel discovery and processing - no sequential bottleneck!
|
|
137
|
+
results = limit_segmentation_by_distance_lazy_batch(
|
|
138
|
+
root=root,
|
|
139
|
+
config=task_config,
|
|
140
|
+
run_names=run_names_list,
|
|
141
|
+
workers=workers,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
successful = sum(1 for result in results.values() if result and result.get("processed", 0) > 0)
|
|
145
|
+
total_voxels = sum(result.get("voxels_created", 0) for result in results.values() if result)
|
|
146
|
+
total_processed = sum(result.get("processed", 0) for result in results.values() if result)
|
|
147
|
+
|
|
148
|
+
# Collect all errors
|
|
149
|
+
all_errors = []
|
|
150
|
+
for result in results.values():
|
|
151
|
+
if result and result.get("errors"):
|
|
152
|
+
all_errors.extend(result["errors"])
|
|
153
|
+
|
|
154
|
+
logger.info(f"Completed: {successful}/{len(results)} runs processed successfully")
|
|
155
|
+
logger.info(f"Total distance limiting operations completed: {total_processed}")
|
|
156
|
+
logger.info(f"Total voxels created: {total_voxels}")
|
|
157
|
+
|
|
158
|
+
if all_errors:
|
|
159
|
+
logger.warning(f"Encountered {len(all_errors)} errors during processing")
|
|
160
|
+
for error in all_errors[:5]: # Show first 5 errors
|
|
161
|
+
logger.warning(f" - {error}")
|
|
162
|
+
if len(all_errors) > 5:
|
|
163
|
+
logger.warning(f" ... and {len(all_errors) - 5} more errors")
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""CLI commands for data conversion between different copick formats.
|
|
2
|
+
|
|
3
|
+
This module imports all conversion commands from specialized files for better organization.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from copick_utils.cli.mesh2picks import mesh2picks
|
|
7
|
+
from copick_utils.cli.mesh2seg import mesh2seg
|
|
8
|
+
from copick_utils.cli.picks2ellipsoid import picks2ellipsoid
|
|
9
|
+
from copick_utils.cli.picks2mesh import picks2mesh
|
|
10
|
+
from copick_utils.cli.picks2plane import picks2plane
|
|
11
|
+
from copick_utils.cli.picks2seg import picks2seg
|
|
12
|
+
from copick_utils.cli.picks2sphere import picks2sphere
|
|
13
|
+
from copick_utils.cli.picks2surface import picks2surface
|
|
14
|
+
from copick_utils.cli.seg2mesh import seg2mesh
|
|
15
|
+
from copick_utils.cli.seg2picks import seg2picks
|
|
16
|
+
|
|
17
|
+
# All commands are now available for import by the main CLI
|
|
18
|
+
__all__ = [
|
|
19
|
+
# Picks to mesh commands
|
|
20
|
+
"picks2mesh",
|
|
21
|
+
"picks2sphere",
|
|
22
|
+
"picks2ellipsoid",
|
|
23
|
+
"picks2plane",
|
|
24
|
+
"picks2surface",
|
|
25
|
+
# Mesh to picks commands
|
|
26
|
+
"mesh2picks",
|
|
27
|
+
# Segmentation conversion commands
|
|
28
|
+
"picks2seg",
|
|
29
|
+
"seg2picks",
|
|
30
|
+
"mesh2seg",
|
|
31
|
+
"seg2mesh",
|
|
32
|
+
]
|