memthick#
- class cryocat.analysis.memthick.MeshNormalVoter(points, initial_normals, radius_hit, batch_size=2000, logger=None)#
Bases:
objectClass for refining normals and separating bilayer surfaces.
This class handles the refinement of surface normal vectors using a voting-based approach, and separates the bilayer into inner and outer surfaces based on normal directions.
- build_adjacency(max_neighbors=100)#
Build weighted adjacency graph for normal propagation.
- Parameters:
- max_neighborsint
Maximum number of neighbors per point
- Returns:
- graphscipy.sparse.csr_matrix
Weighted adjacency graph
- log(message)#
Log message using the logger if available, otherwise print
- orient_normals()#
Orient normals consistently using minimum spanning tree.
- Returns:
- refined_normalsndarray
Consistently oriented normal vectors
- process()#
Run full processing pipeline.
- Returns:
- surface1_maskndarray
Boolean mask for first surface
- surface2_maskndarray
Boolean mask for second surface
- refine_normals()#
Refine normal directions using weighted average of neighbor normals.
- Returns:
- refined_normalsndarray
Refined normal vectors
- separate_bilayer()#
Separate bilayer surfaces using marching cubes orientation.
Since marching cubes gives outward-pointing normals, we can use a simple dot product test with a direction vector to separate surfaces.
- Returns:
- surface1_maskndarray
Boolean mask for first surface
- surface2_maskndarray
Boolean mask for second surface
- cryocat.analysis.memthick.create_vertex_volume(aligned_vertices, membrane_mask_shape)#
Create binary volume marking vertex positions.
- Parameters:
- aligned_verticesnp.ndarray
2D array (N, 3) of vertex coordinates in voxel units
- membrane_mask_shapetuple
Shape (z, y, x) of the target volume
- Returns:
- np.ndarray
3D binary volume with 1 at vertex positions, 0 elsewhere
- cryocat.analysis.memthick.extract_and_validate_surface(segmentation, membrane_mask, mesh_sampling, logger=None)#
Extract and validate surface points using marching cubes.
- Parameters:
- segmentationnp.ndarray
3D segmentation volume (passed to extract_surface_points)
- membrane_masknp.ndarray
3D binary mask for membrane of interest
- mesh_samplingint
Step size for marching cubes algorithm
- loggerlogging.Logger, optional
Logger instance
- Returns:
- aligned_verticesnp.ndarray or None
2D array (N, 3) of validated surface vertices
- aligned_normalsnp.ndarray or None
2D array (N, 3) of corresponding normal vectors
- vertex_volumenp.ndarray or None
3D binary volume marking vertex positions
Notes
Returns (None, None, None) if no valid surface points found.
- cryocat.analysis.memthick.extract_intensity_profile(thickness_df, tomo, voxel_size=None, intensity_extension_voxels=10, intensity_normalize_method='zscore', logger=None)#
Extract intensity profiles between paired membrane points with physical units.
This function computes intensity profiles along lines connecting matched surface points from thickness measurements. It extracts intensity values from the tomogram along vectors extending beyond the matched points, providing data for quality assessment and filtering of thickness measurements.
The function performs the following steps:
Input validation: Checks for required columns and valid coordinate pairs
Tomogram normalization: Applies specified normalization method
Profile extraction: Computes intensity values along each line using linear interpolation
Coordinate scaling: Converts voxel coordinates to physical units
Extension: Extends profiles beyond matched points for better analysis
Intensity profiles are essential for validating thickness measurements by detecting characteristic bilayer features (dual minima, central maximum).
- Parameters:
- thickness_dfpd.DataFrame
DataFrame containing paired point coordinates for thickness measurements. Must have columns [‘x1_voxel’, ‘y1_voxel’, ‘z1_voxel’, ‘x2_voxel’, ‘y2_voxel’, ‘z2_voxel’] with coordinates in voxel units. Invalid or NaN coordinate pairs are automatically filtered out.
- tomonp.ndarray
3D tomogram array with shape (Z, Y, X) in ZYX order. The tomogram should have the same dimensions as the segmentation used for thickness measurement. Intensity values are extracted from this volume.
- voxel_sizefloat, optional
Voxel size in nanometers for physical coordinate scaling. If None, only voxel coordinates are returned. If provided, physical coordinates in nanometers are added to each profile dictionary.
- intensity_extension_voxelsint, default 10
Number of voxels to extend beyond the midpoint in each direction. Larger values provide more context for intensity analysis but may include irrelevant regions. Typical values range from 10-20 voxels.
- intensity_normalize_method{‘zscore’, ‘minmax’, ‘percentile’, ‘none’}, default ‘zscore’
Normalization method to apply to tomogram before extraction: - ‘zscore’: Standardize to zero mean and unit variance - ‘minmax’: Scale to range [0, 1] - ‘percentile’: Clip to 1st-99th percentile range - ‘none’: Use original intensity values
- loggerlogging.Logger, optional
Logger instance for status messages
- Returns:
- List[Dict]
List of profile dictionaries, one for each valid coordinate pair. Each dictionary contains:
Core profile data: - ‘profile’: np.ndarray of intensity values along the line - ‘p1’: np.ndarray, coordinates of first point (voxel units) - ‘p2’: np.ndarray, coordinates of second point (voxel units) - ‘midpoint’: np.ndarray, midpoint coordinates (voxel units) - ‘start’: np.ndarray, extended start coordinates (voxel units) - ‘end’: np.ndarray, extended end coordinates (voxel units)
Physical coordinates (if voxel_size provided): - ‘p1_nm’: np.ndarray, first point in nanometers - ‘p2_nm’: np.ndarray, second point in nanometers - ‘midpoint_nm’: np.ndarray, midpoint in nanometers - ‘start_nm’: np.ndarray, extended start in nanometers - ‘end_nm’: np.ndarray, extended end in nanometers - ‘voxel_size’: float, voxel size used for scaling
- Raises:
- ValueError
If required columns are missing from thickness_df. If tomo is not a 3D array. If voxel_size is negative.
- IndexError
If any coordinate pairs are outside tomogram bounds.
Notes
Profiles extend beyond the matched points by intensity_extension_voxels in both directions
Invalid or NaN coordinate pairs are automatically filtered out
Interpolation is performed using scipy.ndimage.map_coordinates with linear interpolation
Physical coordinates are computed by multiplying voxel coordinates by voxel_size
The function handles variable line lengths automatically
Processing time scales with the number of coordinate pairs and extension distance
Examples
Extract profiles with physical units as a standalone function:
>>> profiles = extract_intensity_profile( ... thickness_df=df, ... tomo=tomogram_array, ... voxel_size=0.788, ... intensity_extension_voxels=10, ... intensity_normalize_method='zscore' ... ) >>> print(f"Profile has {len(profiles[0]['profile'])} intensity points") >>> print(f"Physical distance: {np.linalg.norm(profiles[0]['p2_nm'] - profiles[0]['p1_nm']):.2f} nm")
- cryocat.analysis.memthick.extract_surface_points(segmentation, membrane_mask, mesh_sampling=1, logger=None)#
Extract surface points and normals using marching cubes algorithm.
This function processes a binary membrane mask to identify surface voxels and compute their normal vectors. It uses the marching cubes algorithm from scikit-image to extract the surface mesh, then validates each vertex to ensure it lies on the true segmentation boundary.
The function performs the following steps: 1. Applies marching cubes to extract surface mesh 2. Converts vertex coordinates to integer voxel positions 3. Validates each vertex using is_surface_point() function 4. Removes duplicate vertices at the same position 5. Returns validated vertices with corresponding normal vectors
- Parameters:
- segmentationnp.ndarray
3D segmentation volume (unused, kept for interface compatibility)
- membrane_masknp.ndarray
3D binary mask for membrane of interest
- mesh_samplingint, default 1
Step size for marching cubes algorithm. Larger values reduce computational cost but may miss fine surface details. - 1: Full resolution (most accurate, slowest) - 2: Half resolution (2x faster, some detail loss) - 4: Quarter resolution (4x faster, significant detail loss)
- loggerlogging.Logger, optional
Logger instance
- Returns:
- aligned_verticesnp.ndarray or None
2D array (N, 3) of surface vertex coordinates in voxel units
- aligned_normalsnp.ndarray or None
2D array (N, 3) of surface normal vectors
Notes
Only returns vertices that pass surface validation (is_surface_point). Returns (None, None) if extraction fails or no valid points found.
- cryocat.analysis.memthick.filter_intensity_profiles(profiles, thickness_df, intensity_min_snr=0.2, intensity_central_max_required=True, intensity_extension_range=(-10, 10), intensity_margin_factor=0.1, require_both_minima_in_region=True, smooth_sigma=0.0, edge_fraction=0.2, logger=None)#
Filter intensity profiles using quality criteria and geometric constraints.
This function applies a two-pass filtering approach to validate intensity profiles and filter out low-quality thickness measurements. It uses both signal quality metrics and geometric constraints to ensure only reliable bilayer measurements are retained.
Two-Pass Filtering Strategy:
Pass 1 - Characterization: Identifies candidate profiles using loose criteria to establish dataset characteristics and statistics. This pass is used for analysis only, not for filtering.
Pass 2 - Quality Filtering: Applies strict criteria to filter profiles based on: - Dual minima detection (representing lipid headgroups) - Central maximum requirement (representing lipid tails) - Signal-to-noise ratio validation - Geometric position constraints
Quality Criteria:
Dual Minima: Must detect at least two minima in the profile
Central Maximum: Must have a maximum between the two minima
Signal Quality: Minima must meet minimum SNR requirements
Position Validation: Minima must be positioned between matched points
Geometric Constraints: Optional margin for position flexibility
- Parameters:
- profilesList[Dict]
List of intensity profile dictionaries from extract_intensity_profile(). Each profile should contain ‘profile’, ‘p1’, ‘p2’, ‘start’, ‘end’, and ‘midpoint’ keys with appropriate coordinate data.
- thickness_dfpd.DataFrame
DataFrame containing thickness measurement metadata. Must have the same number of rows as profiles. Used for coordinate validation and result mapping.
- intensity_min_snrOptional[float], default 0.2
Minimum signal-to-noise ratio for minima prominence. - If None: SNR filtering is disabled (position-based filtering only) - If float: Minima must have prominence >= intensity_min_snr × baseline noise - Typical values: 1.0-3.0 (higher = stricter quality requirements) - Lower values may include noisy profiles, higher values may exclude valid ones
- intensity_central_max_requiredbool, default True
Whether to require a central maximum between the two detected minima. This validates the bilayer structure where lipid tails create a central intensity peak between the headgroup minima.
- intensity_extension_rangeTuple[float, float], default (-10, 10)
Distance range in voxel units to analyze around the profile midpoint. Profiles are analyzed within this range for feature detection. - First value: Minimum distance from midpoint - Second value: Maximum distance from midpoint - Typical range: (-8, 8) to (-15, 15) voxels
- intensity_margin_factorfloat, default 0.1
Allowed margin for minima detection outside the measurement region as a fraction of the measurement span. - 0.0: Minima must be exactly between matched points (strictest) - 0.1: 10% margin allowed (recommended for most cases) - 0.3: 30% margin allowed (most permissive) - Higher values accommodate measurement uncertainty
- require_both_minima_in_regionbool, default True
If True, both minima must be within the extended region for a profile to pass filtering. If False, only one minimum is required. - True: Ensures complete bilayer detection (recommended) - False: More permissive, may include partial bilayer profiles
- smooth_sigmafloat, default 0.0
Gaussian smoothing parameter for intensity profiles. - 0.0: No smoothing (preserves original profile features) - 0.5-1.0: Light smoothing (reduces noise) - 1.5-2.0: Moderate smoothing (may blur features) - Higher values: Heavy smoothing (may lose important features)
- edge_fractionfloat, default 0.2
Fraction of profile edges used for baseline noise calculation. - 0.1: Use 10% of profile edges for baseline (narrow baseline) - 0.2: Use 20% of profile edges for baseline (recommended) - 0.3: Use 30% of profile edges for baseline (wide baseline) - Used to calculate signal-to-noise ratios
- loggerlogging.Logger, optional
Logger instance for status messages. If None, prints to stdout. Used to report filtering progress and results.
- Returns:
- Dict
Comprehensive filtering results containing:
Core Results: - ‘pass1_candidates’: List of Pass 1 characterization results - ‘final_results’: List of Pass 2 filtering results - ‘filtered_profiles’: List of profiles that passed filtering - ‘filtered_thickness_df’: DataFrame of filtered thickness data
Statistics and Analysis: - ‘statistics’: Comprehensive filtering statistics - ‘dataset_characteristics’: Dataset-wide feature characteristics - ‘parameters’: User-specified filtering parameters
Statistics Details: - ‘total_profiles’: Total number of profiles analyzed - ‘profiles_passed’: Number of profiles passing all criteria - ‘pass_rate’: Fraction of profiles passing filters - ‘failure_analysis’: Breakdown of failure reasons - ‘quality_metrics’: Statistical analysis of passed profiles
Dataset Characteristics: - ‘median_separation’: Typical distance between minima - ‘median_prominence_snr’: Typical signal quality - ‘n_candidates’: Number of Pass 1 candidates
- Raises:
- ValueError
If profiles and thickness_df have incompatible lengths. If intensity_extension_range is invalid (min >= max). If intensity_margin_factor is negative.
- RuntimeError
If profile processing fails unexpectedly.
Notes
Filtering Logic: - Profiles are processed individually with comprehensive feature detection - Minima detection uses scipy.signal.find_peaks with prominence filtering - Position validation ensures minima fall within measurement constraints - SNR calculation uses edge regions for baseline noise estimation
Performance Considerations: - Processing time scales with number of profiles and profile length - Memory usage scales with profile count and feature data storage - Smoothing increases computation time but may improve feature detection
Quality Trade-offs: - Stricter SNR requirements improve quality but reduce coverage - Larger position margins increase coverage but may include lower quality data - Central maximum requirement ensures bilayer structure but may exclude valid cases
Examples
Basic filtering with default parameters:
>>> from memthick import filter_intensity_profiles >>> import pandas as pd >>> >>> # Filter profiles with standard criteria >>> results = filter_intensity_profiles( ... profiles=extracted_profiles, ... thickness_df=thickness_data, ... intensity_min_snr=0.2, ... intensity_central_max_required=True, ... intensity_extension_range=(-10, 10) ... ) >>> >>> print(f"Profiles passed: {results['statistics']['profiles_passed']}") >>> print(f"Pass rate: {results['statistics']['pass_rate']:.1%}")
Custom filtering parameters:
>>> # More permissive filtering >>> results_permissive = filter_intensity_profiles( ... profiles=extracted_profiles, ... thickness_df=thickness_data, ... intensity_min_snr=None, # Disable SNR filtering ... intensity_central_max_required=False, # Don't require central maximum ... intensity_margin_factor=0.2, # 20% position margin ... require_both_minima_in_region=False # Only one minimum required ... )
>>> # Stricter filtering >>> results_strict = filter_intensity_profiles( ... profiles=extracted_profiles, ... thickness_df=thickness_data, ... intensity_min_snr=2.0, # High SNR requirement ... intensity_central_max_required=True, ... intensity_margin_factor=0.0, # Exact position requirement ... smooth_sigma=0.5 # Light smoothing ... )
Analyzing failure reasons:
>>> failure_analysis = results['statistics']['failure_analysis'] >>> for reason, count in failure_analysis.items(): ... print(f"{reason}: {count} profiles")
Accessing quality metrics:
>>> quality_metrics = results['statistics']['quality_metrics'] >>> snr_stats = quality_metrics['prominence_snr_stats'] >>> print(f"Mean SNR: {snr_stats['mean']:.1f}x") >>> print(f"Median SNR: {snr_stats['median']:.1f}x")
- cryocat.analysis.memthick.find_all_possible_matches_kernel(points, normals, surface1_mask, surface2_mask, match_distances, match_indices, match_counts, max_thickness_voxels, max_angle_cos, max_matches_per_point)#
CUDA kernel to find all possible matches for each surface1 point.
- Parameters:
- pointsndarray
Vertex coordinates
- normalsndarray
Normal vectors
- surface1_maskndarray
Boolean mask for first surface
- surface2_maskndarray
Boolean mask for second surface
- match_distancesndarray
Output array for match distances
- match_indicesndarray
Output array for match indices
- match_countsndarray
Output array for match counts
- max_thickness_voxelsfloat
Maximum thickness in voxel units
- max_angle_cosfloat
Cosine of maximum angle for cone search
- max_matches_per_pointint
Maximum number of matches per point
- cryocat.analysis.memthick.find_matches_parallel(points, normals, source_mask, target_mask, target_indices, max_thickness_voxels, max_angle_cos, match_distances, match_indices, match_counts)#
Parallelized function to find matches between points on different surfaces.
- Parameters:
- pointsndarray
Point coordinates
- normalsndarray
Normal vectors
- source_maskndarray
Mask for source points
- target_maskndarray
Mask for target points
- target_indicesndarray
Indices of target points
- max_thickness_voxelsfloat
Maximum thickness in voxel units
- max_angle_cosfloat
Cosine of maximum angle
- match_distancesndarray
Output array for match distances
- match_indicesndarray
Output array for match indices
- match_countsndarray
Output array for match counts
- cryocat.analysis.memthick.find_surface_neighbors(vertex, segmentation, include_edges=True)#
Find valid surface neighbors around a vertex.
- Parameters:
- vertexarray-like
Coordinates [x, y, z] of the central vertex
- segmentationnp.ndarray
3D binary segmentation volume
- include_edgesbool, default True
Whether to include edge neighbors (12) in addition to face neighbors (6)
- Returns:
- list
List of [x, y, z] coordinates for valid surface neighbors
- cryocat.analysis.memthick.generate_matching_statistics(thickness_results, valid_mask, point_pairs, points, surface1_mask, surface2_mask, voxel_size)#
Generate comprehensive statistics for thickness measurements.
- Parameters:
- thickness_resultsnp.ndarray
1D array of thickness measurements in physical units (nm)
- valid_masknp.ndarray
1D boolean array indicating valid measurements
- point_pairsnp.ndarray
1D array of indices for paired points
- pointsnp.ndarray
2D array (N, 3) of vertex coordinates in voxel units
- surface1_masknp.ndarray
1D boolean array for surface 1 points
- surface2_masknp.ndarray
1D boolean array for surface 2 points
- voxel_sizefloat
Voxel size in nanometers for coordinate scaling
- Returns:
- dict
Statistics dictionary containing: - total_points, surface1_points, surface2_points, valid_measurements - coverage_percentage - thickness statistics (mean, std, median, min, max, percentiles) - thickness_histogram with counts and bin_edges - spatial_distribution with mean and std coordinates
- cryocat.analysis.memthick.generate_thickness_volume(points, thickness_results, valid_mask, segmentation, voxel_size, point_pairs)#
Create 3D volume where voxel values represent membrane thickness.
- Parameters:
- pointsnp.ndarray
2D array (N, 3) of point coordinates in voxel space
- thickness_resultsnp.ndarray
1D array of thickness measurements in nanometers
- valid_masknp.ndarray
1D boolean array indicating valid measurements
- segmentationnp.ndarray
3D reference segmentation for volume dimensions
- voxel_sizefloat
Voxel size in nanometers (unused but kept for consistency)
- point_pairsnp.ndarray
1D array of paired point indices
- Returns:
- np.ndarray
3D float32 volume with thickness values in nm (NaN for unmeasured voxels)
Notes
Sets thickness values at both surface points of each valid measurement.
- cryocat.analysis.memthick.get_neighbor_surface_points(vertex, segmentation, include_edges=True)#
Find neighboring surface points around a vertex.
- Parameters:
- vertexarray-like
Coordinates [x, y, z] of the central vertex
- segmentationnp.ndarray
3D binary segmentation volume
- include_edgesbool, default True
Whether to include 12 edge neighbors in addition to 6 face neighbors
- Returns:
- list
List of neighboring points that pass surface validation
- cryocat.analysis.memthick.int_profiles_extract_clean(thickness_csv, tomo_path, output_dir, intensity_min_snr=0.2, intensity_central_max_required=True, intensity_extension_voxels=10, intensity_extension_range=(-10, 10), intensity_normalize_method='zscore', save_cleaned_df=True, save_profiles=True, save_statistics=True, intensity_margin_factor=0.1, intensity_require_both_minima=True, intensity_smooth_sigma=0.0, intensity_edge_fraction=0.2, logger=None)#
Workflow for extracting intensity profiles, filtering, and saving results.
- Parameters:
- thickness_csvUnion[str, Path]
Path to thickness CSV file
- tomo_pathUnion[str, Path]
Path to tomogram file
- output_dirUnion[str, Path]
Directory to save results
- intensity_min_snrOptional[float], default 0.2
Minimum SNR for minima prominence. If None, SNR filtering is disabled.
- intensity_central_max_requiredbool
Whether to require central maximum
- intensity_extension_voxelsint
Extension distance for profile extraction
- intensity_extension_rangeTuple[float, float]
Range for filtering analysis
- intensity_normalize_methodLiteral
Tomogram normalization method
- save_cleaned_dfbool
Whether to save cleaned DataFrame
- save_profilesbool
Whether to save intensity profiles
- save_statisticsbool
Whether to save statistics
- intensity_margin_factorfloat, default 0.1
Allowed margin for minima detection outside measurement region (0.0=exact, 0.3=30% margin)
- intensity_require_both_minimabool, default True
Whether both minima must be in extended region
- intensity_smooth_sigmafloat, default 0.0
Gaussian smoothing parameter (0=no smoothing)
- intensity_edge_fractionfloat, default 0.2
Fraction of profile edges for baseline calculation
- loggerlogging.Logger, optional
Logger instance for status messages
- Returns:
- Dict
Complete analysis results
- cryocat.analysis.memthick.interpolate_between_points(p1, p2, segmentation, num_points=1)#
Interpolate points between two coordinates with surface validation.
- Parameters:
- p1, p2array-like
Start and end point coordinates
- segmentationnp.ndarray
3D binary segmentation volume for validation
- num_pointsint, default 1
Number of points to interpolate
- Returns:
- list
List of interpolated points that pass surface validation
- cryocat.analysis.memthick.interpolate_between_vertices(v1, v2, segmentation, num_points=1)#
Interpolate points between two vertices on the surface.
- Parameters:
- v1, v2array-like
Start and end vertex coordinates
- segmentationnp.ndarray
3D binary segmentation volume for validation
- num_pointsint, default 1
Number of points to interpolate between vertices
- Returns:
- list
List of interpolated points that pass surface validation
- cryocat.analysis.memthick.interpolate_surface_if_requested(aligned_vertices, aligned_normals, membrane_mask, interpolate, interpolation_points, logger=None)#
Conditionally interpolate surface points for denser coverage.
- Parameters:
- aligned_verticesnp.ndarray
2D array (N, 3) of surface vertex coordinates
- aligned_normalsnp.ndarray
2D array (N, 3) of normal vectors
- membrane_masknp.ndarray
3D binary segmentation mask for validation
- interpolatebool
Whether to perform interpolation
- interpolation_pointsint
Number of points to interpolate between vertices
- loggerlogging.Logger, optional
Logger instance
- Returns:
- verticesnp.ndarray
2D array of (possibly modified) vertex coordinates
- normalsnp.ndarray
2D array of (possibly modified) normal vectors
Notes
Returns original arrays unchanged if interpolate=False.
- cryocat.analysis.memthick.interpolate_surface_points(vertices, normals, segmentation, interpolation_points=1, include_edges=True, logger=None)#
Increase surface point density through interpolation and neighbor addition.
This function enhances surface coverage by adding interpolated points between consecutive vertices and including neighboring surface points around each vertex. The resulting denser surface representation improves thickness measurement accuracy and coverage.
The function performs two types of point addition:
Interpolation: Adds points between consecutive vertices along the surface using linear interpolation
Neighbor addition: Includes valid surface neighbors around each vertex (6 face neighbors + 12 edge neighbors if include_edges=True)
All new points are validated using is_surface_point() to ensure they lie on the true segmentation boundary.
- Parameters:
- verticesnp.ndarray
2D array (N, 3) of original vertex coordinates
- normalsnp.ndarray
2D array (N, 3) of corresponding normal vectors
- segmentationnp.ndarray
3D binary segmentation volume for validation
- interpolation_pointsint, default 1
Number of points to interpolate between consecutive vertices. - 0: No interpolation (only neighbor addition) - 1: One point between each pair of vertices (recommended) - 2: Two points between each pair of vertices - Higher values increase density but may create redundant points
- include_edgesbool, default True
Whether to include edge neighbors around each vertex
- loggerlogging.Logger, optional
Logger instance
- Returns:
- dense_verticesnp.ndarray
2D array of densified vertex coordinates
- dense_normalsnp.ndarray
2D array of corresponding normal vectors
Notes
Processing time scales with N * (1 + interpolation_points + neighbor_count)
Memory usage scales with the final number of vertices M
All new points are validated using is_surface_point() function
Duplicate positions are automatically removed
Interpolated normals are linearly interpolated and re-normalized
Neighbor points inherit the normal vector of their source vertex
The function maintains the order: original vertices, then interpolated, then neighbor points
- cryocat.analysis.memthick.is_surface_point(point, segmentation)#
Validate if a point is truly on the segmentation surface boundary.
This function determines whether a given voxel position lies on the surface of a binary segmentation by checking if it is inside the segmentation and has at least one immediate neighbor outside it.
The function uses a 6-connected neighborhood check (face neighbors only) to determine surface membership. A point is considered on the surface if it satisfies both conditions: 1. The point itself is inside the segmentation (True/1) 2. At least one of its 6 face neighbors is outside the segmentation (False/0)
- Parameters:
- pointarray-like
Coordinates [x, y, z] of the point to check
- segmentationnp.ndarray
3D binary segmentation volume where True/1 indicates inside the segmentation and False/0 indicates outside. Shape should be (Z, Y, X) in voxel coordinates.
- Returns:
- bool
True if the point is on the surface boundary, False otherwise. A point is on the surface if it’s inside the segmentation and has at least one face neighbor outside the segmentation.
- Raises:
- IndexError
If the point coordinates are outside the segmentation array bounds.
- ValueError
If the segmentation array is not 3D or contains non-boolean values.
Notes
Uses 6-connected neighborhood (face neighbors only, not edge or corner)
Face neighbors are at positions: [x±1, y, z], [x, y±1, z], [x, y, z±1]
Edge and corner neighbors are not considered for surface detection
This conservative approach ensures only true boundary points are identified
Processing time is O(1) per point (constant time)
- cryocat.analysis.memthick.main()#
Entry point for command line execution.
This function: 1) Parses CLI arguments 2) Validates inputs per selected mode 3) Dispatches to the requested workflow (full, surface, thickness, intensity)
Exit codes are communicated via printed error messages and early returns.
- cryocat.analysis.memthick.measure_membrane_thickness(segmentation_path, input_csv, output_csv=None, output_dir=None, max_thickness=8.0, max_angle=1.0, save_thickness_mrc=False, direction='1to2', use_gpu=True, num_cpu_threads=None, logger=None)#
Measure membrane thickness between separated surface points.
- Parameters:
- segmentation_pathstr
Path to original MRC segmentation file (for metadata)
- input_csvstr
Path to CSV file with vertices, normals, and surface assignments
- output_csvstr, optional
Path for thickness results CSV (auto-generated if None)
- output_dirstr, optional
Output directory (defaults to input CSV directory)
- max_thicknessfloat, default 8.0
Maximum allowed thickness in nanometers
- max_anglefloat, default 1.0
Maximum angle for cone search in degrees
- save_thickness_mrcbool, default False
Whether to save thickness volume as MRC file
- directionstr, default “1to2”
Measurement direction: “1to2” (surface1→surface2) or “2to1”
- use_gpubool, default True
Whether to use GPU acceleration if available
- num_cpu_threadsint, optional
Number of CPU threads (if using CPU implementation)
- loggerlogging.Logger, optional
Logger instance
- Returns:
- output_csvstr or None
Path to thickness measurements CSV file
- stats_filestr or None
Path to statistics log file
Notes
Output CSV contains only valid thickness measurements with complete information about both matched surface points. Falls back to CPU if GPU not available.
- cryocat.analysis.memthick.measure_thickness_cpu(points, normals, surface1_mask, surface2_mask, voxel_size, max_thickness_nm=8.0, max_angle_degrees=1.0, direction='1to2', num_threads=None, logger=None, max_matches_per_point=25)#
CPU-based thickness measurement with parallelization.
- cryocat.analysis.memthick.measure_thickness_gpu(points, normals, surface1_mask, surface2_mask, voxel_size, max_thickness_nm=8.0, max_angle_degrees=1.0, direction='1to2', logger=None)#
GPU-accelerated membrane thickness measurement with one-to-one point matching.
This function measures membrane thickness between two separated surfaces using CUDA-accelerated nearest neighbor search. It ensures each surface point is measured exactly once by implementing a one-to-one matching algorithm that prioritizes the shortest valid distances.
The function performs the following steps:
GPU preparation: Transfers data to GPU memory and configures CUDA grid
Parallel search: Uses CUDA kernel to find all possible matches for each source point within geometric constraints
CPU post-processing: Processes matches on CPU to ensure one-to-one assignment and converts results to physical units
Validation: Applies geometric constraints (max thickness, cone angle)
Geometric constraints ensure measurement quality: - Maximum thickness: Limits search to reasonable membrane thicknesses - Cone angle: Restricts search to a cone along the normal direction - Surface separation: Ensures points are on different surfaces
- Parameters:
- pointsndarray
Unscaled voxel coordinates
- normalsndarray
Normal vectors
- surface1_mask, surface2_maskndarray
Boolean masks for each surface
- voxel_sizefloat
Voxel size in nm or angstroms
- max_thickness_nmfloat
Maximum thickness in nm (will be converted to voxels internally)
- max_angle_degreesfloat
Maximum angle for cone search
- directionstr
Direction of thickness measurement, either “1to2” (surface1 to surface2) or “2to1” (surface2 to surface1)
- loggerlogging.Logger, optional
Logger instance
- Returns:
- thickness_resultsnp.ndarray
1D array of length N containing thickness measurements in nanometers. Only valid measurements have non-zero values; invalid measurements are set to 0.0.
- valid_masknp.ndarray
1D boolean array of length N indicating which measurements are valid. True values indicate successful thickness measurements.
- point_pairsnp.ndarray
1D array of length N containing indices of matched points for each source point. For valid measurements, this gives the index of the corresponding point on the opposite surface.
- Raises:
- RuntimeError
If CUDA is not available or GPU memory allocation fails.
- ValueError
If input arrays have incompatible shapes or invalid parameters.
Notes
GPU Requirements: Requires CUDA-capable GPU with sufficient memory
Performance: Significantly faster than CPU implementation for large surfaces (typically 10-100x speedup)
Memory: GPU memory usage scales with N * max_matches_per_point
Fallback: Automatically falls back to CPU if CUDA unavailable
Constraints: Maximum 25 potential matches per point to manage memory
Accuracy: Results are identical to CPU implementation but faster
- cryocat.analysis.memthick.normalize_tomogram(tomo, method='zscore', logger=None)#
Normalize tomogram intensity values using various strategies.
- Parameters:
- tomonp.ndarray
3D tomogram array
- method{‘zscore’, ‘minmax’, ‘percentile’, ‘none’}, default ‘zscore’
Normalization method
- loggerlogging.Logger, optional
Logger instance for status messages
- Returns:
- np.ndarray
Normalized tomogram
- cryocat.analysis.memthick.parse_arguments()#
Build and parse command line arguments for the CLI.
The CLI supports four modes: - full: complete pipeline with optional intensity profiling - surface: surface extraction only - thickness: thickness measurement only - intensity: intensity profiling only
- Returns:
- argparse.Namespace
Parsed CLI arguments containing all options required by the pipeline and its sub-commands.
Examples
Typical invocations:
Full pipeline with intensity profiling: python memthick_250814.py seg.mrc –mode full –extract_intensity –tomo_path tomo.mrc –membrane_labels NE:1,ER:2
Surface extraction only: python memthick_250814.py seg.mrc –mode surface –mesh_sampling 2
Thickness only: python memthick_250814.py seg.mrc –mode thickness –input_csv vertices.csv
Intensity only: python memthick_250814.py seg.mrc –mode intensity –thickness_csv thickness.csv –tomo_path tomo.mrc
- cryocat.analysis.memthick.print_summary(results, logger=None)#
Print summary of filtering results.
- cryocat.analysis.memthick.process_matches_cpu2cpu(flat_matches, n_points, voxel_size)#
Process matches on CPU to ensure one-to-one matching and convert to physical units.
- Parameters:
- flat_matcheslist
List of tuples (distance, source_idx, target_idx)
- n_pointsint
Total number of points
- voxel_sizefloat
Voxel size for scaling
- Returns:
- thickness_resultsndarray
Thickness measurements in physical units
- valid_maskndarray
Boolean mask for valid measurements
- point_pairsndarray
Indices of paired points
- cryocat.analysis.memthick.process_matches_gpu2cpu(match_distances, match_indices, match_counts, n_points, max_matches_per_point, voxel_size)#
Process matches on CPU to ensure one-to-one matching and convert to physical units.
- Parameters:
- match_distancesndarray
Match distances in voxel units
- match_indicesndarray
Match indices
- match_countsndarray
Match counts
- n_pointsint
Number of points
- max_matches_per_pointint
Maximum number of matches per point
- voxel_sizefloat
Voxel size for scaling
- Returns:
- thickness_resultsndarray
Thickness measurements in physical units
- valid_maskndarray
Boolean mask for valid measurements
- point_pairsndarray
Indices of paired points
- cryocat.analysis.memthick.process_membrane_segmentation(segmentation_path, output_dir=None, config_path=None, membrane_labels=None, mesh_sampling=1, interpolate=True, interpolation_points=1, refine_normals=True, radius_hit=10.0, flip_normals=True, batch_size=2000, save_vertices_mrc=False, save_vertices_xyz=False, logger=None)#
Process membrane segmentation to extract and refine surface points.
- Parameters:
- segmentation_pathstr
Path to input MRC segmentation file
- output_dirstr, optional
Output directory (defaults to segmentation file directory)
- config_pathstr, optional
Path to YAML configuration file with membrane labels
- membrane_labelsdict, optional
Mapping of membrane names to label values {name: int}
- mesh_samplingint, default 1
Step size for marching cubes algorithm
- interpolatebool, default True
Whether to interpolate surface points for denser coverage
- interpolation_pointsint, default 1
Number of points to interpolate between vertices
- refine_normalsbool, default True
Whether to refine normals and separate surfaces
- radius_hitfloat, default 10.0
Search radius for normal refinement (voxel units)
- flip_normalsbool, default True
Whether to flip normals inward after refinement
- batch_sizeint, default 2000
Batch size for normal refinement processing
- save_vertices_mrcbool, default False
Whether to save vertex positions as MRC files
- save_vertices_xyzbool, default False
Whether to save coordinates as XYZ point clouds
- loggerlogging.Logger, optional
Logger instance
- Returns:
- dict or None
Mapping of membrane names to output CSV file paths Returns None if processing fails
Notes
Processes each membrane label separately through the full pipeline: 1. Surface extraction and validation 2. Optional point interpolation 3. Optional normal refinement and surface separation 4. Output file generation
- cryocat.analysis.memthick.read_segmentation(segmentation_path, logger=None)#
Read segmentation data from MRC file and extract metadata.
- Parameters:
- segmentation_pathstr
Path to the MRC segmentation file
- loggerlogging.Logger, optional
Logger instance for status messages
- Returns:
- segmentationnp.ndarray or None
3D segmentation data array (ZYX order)
- voxel_sizefloat or None
Voxel size in nanometers
- origintuple or None
Origin coordinates (x, y, z) in nanometers
- shapetuple or None
Shape of the array (ZYX order)
Notes
Returns (None, None, None) if file reading fails. Voxel size is converted from angstroms to nanometers by dividing by 10.
- cryocat.analysis.memthick.read_tomo(tomo_path, logger=None)#
Read tomogram data from MRC file and extract metadata.
- Parameters:
- tomo_pathstr
Path to the MRC tomogram file
- loggerlogging.Logger, optional
Logger instance for status messages
- Returns:
- tomonp.ndarray or None
3D tomogram data array (ZYX order)
- voxel_sizefloat or None
Voxel size in nanometers
- shapetuple or None
Shape of the tomogram array (ZYX order)
- cryocat.analysis.memthick.refine_mesh_normals(vertices, initial_normals, radius_hit=10.0, batch_size=2000, flip_normals=True, logger=None)#
Refine surface normals and separate bilayer surfaces.
This function improves the quality of surface normal vectors and separates the bilayer membrane into inner and outer surfaces. It uses a voting-based approach to refine normals by averaging neighboring normals with distance-weighted contributions.
The function performs three main operations:
Normal refinement: Uses weighted averaging of neighbor normals within a specified radius to smooth and improve normal quality
Normal orientation: Ensures consistent normal orientation across the surface using minimum spanning tree propagation
Surface separation: Separates the bilayer into two surfaces based on normal direction analysis using PCA
- Parameters:
- verticesnp.ndarray
2D array (N, 3) of surface vertex coordinates
- initial_normalsnp.ndarray
2D array (N, 3) of initial normal vectors from marching cubes
- radius_hitfloat, default 10.0
Search radius for finding neighbor points in voxel units. Larger values include more neighbors but increase computation time. Typical values range from 5-20 voxels depending on surface density.
- batch_sizeint, default 2000
Number of vertices to process in each batch. Larger batches are more memory-efficient but may cause memory issues with very large surfaces. Adjust based on available RAM.
- flip_normalsbool, default True
Whether to flip refined normals to point inward toward the membrane interior. This is typically desired for bilayer analysis as it ensures consistent orientation relative to the membrane center.
- loggerlogging.Logger, optional
Logger instance
- Returns:
- refined_normalsnp.ndarray
2D array of shape (N, 3) containing refined normal vectors. All vectors are unit-normalized and consistently oriented. If flip_normals=True, normals point inward toward membrane center.
- surface1_masknp.ndarray
1D boolean array of length N indicating membership in the first surface. True values indicate vertices assigned to surface 1. Returns zero array if surface separation fails.
- surface2_masknp.ndarray
1D boolean array for second surface assignment
Notes
Processing time scales with N * (average_neighbors_per_point)
Memory usage scales with N and the number of neighbor connections
Normal refinement uses Gaussian weighting based on distance
Surface separation requires sufficient surface coverage to work reliably
The function automatically falls back to original normals if refinement fails
Batch processing helps manage memory for large surfaces
- cryocat.analysis.memthick.refine_normals_and_separate_surfaces(aligned_vertices, aligned_normals, refine_normals, radius_hit, batch_size, flip_normals, logger=None)#
Conditionally refine normals and separate bilayer surfaces.
- Parameters:
- aligned_verticesnp.ndarray
2D array (N, 3) of surface vertex coordinates
- aligned_normalsnp.ndarray
2D array (N, 3) of initial normal vectors
- refine_normalsbool
Whether to perform normal refinement
- radius_hitfloat
Search radius for neighbor finding (voxel units)
- batch_sizeint
Batch size for processing
- flip_normalsbool
Whether to flip refined normals inward
- loggerlogging.Logger, optional
Logger instance
- Returns:
- refined_normalsnp.ndarray
2D array of (possibly refined) normal vectors
- surface1_masknp.ndarray
1D boolean array for surface 1 assignment
- surface2_masknp.ndarray
1D boolean array for surface 2 assignment
Notes
Always initializes surface masks to False arrays. Only modifies them if refinement succeeds.
- cryocat.analysis.memthick.run_full_pipeline(segmentation_path, output_dir=None, config_path=None, membrane_labels=None, mesh_sampling=1, interpolate=True, interpolation_points=1, refine_normals=True, radius_hit=10.0, flip_normals=True, max_thickness=8.0, max_angle=1.0, save_vertices_mrc=False, save_vertices_xyz=False, save_thickness_mrc=False, direction='1to2', batch_size=2000, use_gpu=True, num_cpu_threads=None, extract_intensity_profiles=True, tomo_path=None, intensity_extension_voxels=10, intensity_extension_range=(-10, 10), intensity_normalize_method='zscore', intensity_min_snr=0.2, intensity_central_max_required=True, intensity_save_profiles=True, intensity_save_statistics=True, intensity_tolerance=0.01, intensity_margin_factor=0.1, intensity_require_both_minima=True, intensity_smooth_sigma=0.0, intensity_edge_fraction=0.2)#
Execute complete membrane thickness analysis pipeline with optional intensity profiling.
This is the main entry point for comprehensive membrane analysis. The function orchestrates the entire workflow from surface extraction to thickness measurement and optional intensity profile analysis. It processes each membrane type separately and provides comprehensive output files for further analysis.
The pipeline consists of three main stages:
Surface Processing (process_membrane_segmentation):
Extract surface points using marching cubes algorithm
Optionally interpolate points for denser coverage
Refine normal vectors using neighbor averaging
Separate bilayer into inner/outer surfaces
Thickness Measurement (measure_membrane_thickness):
Match points between separated surfaces
Apply geometric constraints (max thickness, cone angle)
Generate thickness measurements with GPU acceleration
Create comprehensive output files
Intensity Profiling (optional, int_profiles_extract_clean):
Extract intensity profiles from tomogram
Filter profiles using quality criteria
Validate thickness measurements
Generate quality metrics and statistics
- Parameters:
- segmentation_pathstr
Path to input MRC segmentation file
- output_dirstr, optional
Output directory (defaults to segmentation file directory)
- config_pathstr, optional
Path to YAML configuration file specifying membrane labels. Format: {“membrane_name”: label_value}. If None, uses membrane_labels parameter or defaults to {“membrane”: 1}.
- membrane_labelsdict, optional
Direct specification of membrane labels as {name: value} pairs. Example: {“plasma_membrane”: 1, “nuclear_envelope”: 2}. Overrides config_path if both are provided.
- **Surface Processing Parameters:**
- mesh_samplingint, default 1
Step size for marching cubes algorithm. Larger values reduce computation time but may miss fine surface details. - 1: Full resolution (most accurate, slowest) - 2: Half resolution (2x faster, some detail loss) - 4: Quarter resolution (4x faster, significant detail loss)
- interpolatebool, default True
Whether to interpolate surface points for denser coverage. Increases the number of surface points for better thickness measurement accuracy.
- interpolation_pointsint, default 1
Number of points to interpolate between consecutive vertices. Higher values increase surface density but may create redundant points.
- refine_normalsbool, default True
Whether to refine normal vectors using neighbor averaging. Improves normal quality and surface separation reliability.
- radius_hitfloat, default 10.0
Search radius for normal refinement in voxel units. Larger values include more neighbors but increase computation time.
- flip_normalsbool, default True
Whether to flip refined normals to point inward toward the membrane interior. Typically desired for bilayer analysis.
- **Thickness Measurement Parameters:**
- max_thicknessfloat, default 8.0
Maximum allowed thickness in nanometers. Typical membrane thicknesses range from 4-8 nm. Larger values may include invalid measurements.
- max_anglefloat, default 1.0
Maximum cone search angle in degrees. Restricts search to a cone along the normal direction. Smaller angles provide more precise measurements.
- directionstr, default “1to2”
Thickness measurement direction: - “1to2”: Measure from surface 1 to surface 2 - “2to1”: Measure from surface 2 to surface 1
- save_vertices_mrcbool, default False
Whether to save vertex positions as MRC files for visualization.
- save_vertices_xyzbool, default False
Whether to save coordinates as XYZ point clouds for external tools.
- save_thickness_mrcbool, default False
Whether to save thickness volume as MRC file where voxel values represent thickness measurements.
- **Performance Parameters:**
- batch_sizeint, default 2000
Processing batch size for normal refinement. Larger batches are more memory-efficient but may cause memory issues.
- use_gpubool, default True
Whether to use GPU acceleration for thickness measurement. Automatically falls back to CPU if CUDA unavailable.
- num_cpu_threadsint, optional
Number of CPU threads for parallel processing. If None, uses all available cores.
- **Intensity Profiling Parameters:**
- extract_intensity_profilesbool, default True
Whether to perform intensity profile analysis after thickness measurement. Requires tomo_path to be specified.
- tomo_pathstr, optional
Path to tomogram file for intensity profiling. Must have compatible dimensions and voxel size with the segmentation.
- intensity_extension_voxelsint, default 10
Number of voxels to extend intensity profiles beyond matched points. Larger values provide more context for analysis.
- intensity_extension_rangetuple, default (-10, 10)
Range for intensity profile filtering analysis in voxel units. Profiles are analyzed within this range around the midpoint.
- intensity_normalize_methodstr, default ‘zscore’
Tomogram normalization method for intensity extraction:
‘zscore’: Standardize to zero mean and unit variance
‘minmax’: Scale to range [0, 1]
‘percentile’: Clip to 1st-99th percentile range
‘none’: Use original intensity values
- intensity_min_snrOptional[float], default 0.2
Minimum signal-to-noise ratio for minima prominence. If None, SNR filtering is disabled (position-based filtering only). Higher values require more prominent bilayer features.
- intensity_central_max_requiredbool, default True
Whether to require a central maximum between minima in intensity profiles. This validates bilayer structure.
- intensity_tolerancefloat, default 0.01
Tolerance for segmentation-tomogram compatibility check in nm. Files must have matching dimensions and voxel sizes within this tolerance.
- intensity_margin_factorfloat, default 0.1
Allowed margin for minima detection outside measurement region as fraction of measurement span. 0.0 = exact, 0.3 = 30% margin.
- intensity_require_both_minimabool, default True
Whether both minima must be within the extended region for a profile to pass filtering.
- intensity_smooth_sigmafloat, default 0.0
Gaussian smoothing parameter for intensity profiles. 0 = no smoothing, higher values smooth profiles.
- intensity_edge_fractionfloat, default 0.2
Fraction of profile edges used for baseline noise calculation. Used to determine signal-to-noise ratios.
- Returns:
- dict or None
Results dictionary with membrane names as keys and dictionaries containing analysis results. Returns None if pipeline fails.
Each membrane result dictionary contains:
‘input_csv’: Path to vertices/normals CSV file
‘thickness_csv’: Path to thickness measurements CSV file
‘stats_file’: Path to thickness statistics log file
‘intensity_results’: Dictionary with intensity analysis results (only if extract_intensity_profiles=True)
Intensity results include:
‘status’: “completed”, “skipped”, or “failed”
‘analysis_results’: Complete intensity analysis results
‘profiles_extracted’: Number of profiles extracted
‘profiles_filtered’: Number of profiles passing quality filters
‘pass_rate’: Fraction of profiles passing filters
- Raises:
- FileNotFoundError
If segmentation_path or tomo_path (if specified) don’t exist.
- ValueError
If required parameters are invalid or incompatible. If intensity profiling is requested without tomo_path.
- RuntimeError
If any pipeline stage fails unexpectedly.
Notes
Performance Considerations:
GPU acceleration provides 10-100x speedup for thickness measurement
Memory usage scales with surface complexity and batch size
Processing time scales with surface size and interpolation settings
Output Files:
*_vertices_normals.csv: Surface point coordinates and normals
*_thickness.csv: Thickness measurements with point pairs
*_thickness_stats.log: Comprehensive measurement statistics
*_int_profiles.pkl: Intensity profiles (if enabled)
*_thickness_cleaned.csv: Filtered thickness data (if enabled)
Quality Control:
Surface validation ensures only boundary points are used
Geometric constraints filter invalid thickness measurements
Intensity profiling provides automated quality assessment
Comprehensive logging tracks all processing steps
Examples
Basic pipeline without intensity profiling:
>>> from memthick import run_full_pipeline >>> >>> results = run_full_pipeline( ... segmentation_path="membrane_seg.mrc", ... output_dir="analysis_results", ... membrane_labels={"plasma_membrane": 1, "nuclear_envelope": 2}, ... interpolate=True, ... refine_normals=True, ... max_thickness=6.0, ... use_gpu=True ... ) >>> >>> for membrane_name, result in results.items(): ... print(f"{membrane_name}: {result['thickness_csv']}")
Complete pipeline with intensity profiling:
>>> results_with_intensity = run_full_pipeline( ... segmentation_path="membrane_seg.mrc", ... output_dir="analysis_with_intensity", ... extract_intensity_profiles=True, ... tomo_path="tomogram.mrc", ... intensity_min_snr=0.2, ... intensity_central_max_required=True, ... intensity_margin_factor=0.1 ... ) >>> >>> # Check intensity profiling results >>> for membrane_name, result in results_with_intensity.items(): ... if 'intensity_results' in result: ... int_results = result['intensity_results'] ... print(f"{membrane_name}: {int_results['profiles_filtered']} profiles passed")
Custom surface processing parameters:
>>> results_custom = run_full_pipeline( ... segmentation_path="membrane_seg.mrc", ... mesh_sampling=2, # Faster processing ... interpolate=False, # No interpolation ... radius_hit=5.0, # Smaller search radius ... batch_size=1000, # Smaller batches ... save_vertices_mrc=True, # Save vertex files ... save_thickness_mrc=True # Save thickness volume ... )
Intensity profiling requires compatible tomogram file with matching dimensions and voxel size to the segmentation.
- cryocat.analysis.memthick.save_int_results(results, thickness_csv, output_dir, profiles, save_cleaned_df=True, save_profiles=True, save_statistics=True, logger=None)#
Save files related to intensity profiles pre- and post-filtering with feature data.
- Parameters:
- resultsDict
Results from filter_intensity_profiles containing filtered data
- thickness_csvPath
Original thickness file path (for naming)
- output_dirUnion[str, Path]
Directory to save results
- profilesList[Dict]
Original extracted intensity profiles from extract_intensity_profile(). Each dict contains ‘profile’, ‘p1’, ‘p2’, ‘start’, ‘end’, ‘midpoint’
- save_cleaned_dfbool, default True
Whether to save cleaned thickness DataFrame as “*_thickness_cleaned.csv”
- save_profilesbool, default True
Whether to save intensity profiles (both original and cleaned)
- save_statisticsbool, default True
Whether to save filtering statistics as “*_filtering_stats.txt”
- loggerlogging.Logger, optional
Logger instance for status messages
- Returns:
- Dict[str, Path]
Dictionary mapping file types to saved paths: - ‘thickness_cleaned’: Path to cleaned thickness CSV - ‘profiles_original’: Path to original intensity profiles with features - ‘profiles_cleaned’: Path to cleaned intensity profiles with features - ‘statistics’: Path to statistics file
Notes
Follows naming convention: base_name + “_thickness_cleaned.csv”
Intensity profiles saved as pickle files with feature data merged in
Each profile now includes ‘features’ dict with extracted minima/maxima data
Base name automatically extracted by removing common suffixes
- cryocat.analysis.memthick.save_matching_statistics(stats, output_path, logger=None)#
Save thickness analysis statistics to formatted text file.
- Parameters:
- statsdict
Statistics dictionary from generate_matching_statistics()
- output_pathstr
Path where statistics file will be saved
- loggerlogging.Logger, optional
Logger instance for status messages
- cryocat.analysis.memthick.save_thickness_volume(thickness_volume, output_path, voxel_size, origin=(0, 0, 0))#
Save thickness volume as MRC file with proper metadata.
- Parameters:
- thickness_volumenp.ndarray
3D volume with thickness values in nanometers
- output_pathstr
Path for output MRC file
- voxel_sizefloat
Voxel size in nanometers
- origintuple, default (0, 0, 0)
Origin coordinates (x, y, z) in nanometers
Notes
NaN values are converted to 0 for visualization compatibility. Voxel size is converted to angstroms for MRC format.
- cryocat.analysis.memthick.save_vertices_mrc_helper(vertex_volume, output_path, voxel_size, origin)#
Helper function to save vertex volume as MRC file.
- Parameters:
- vertex_volumenp.ndarray
3D binary volume data
- output_pathstr
Path for output MRC file
- voxel_sizefloat
Voxel size in nanometers
- origintuple
Origin coordinates (x, y, z) in nanometers
- cryocat.analysis.memthick.setup_logger(output_dir, name='MembraneThickness')#
Set up logger for the analysis with both file and console handlers.
- Parameters:
- output_dirstr
Directory where log file will be saved
- namestr, default “MembraneThickness”
Name of the logger
- Returns:
- logging.Logger
Configured logger instance with file and console handlers
- cryocat.analysis.memthick.update_vertex_volume_after_interpolation(aligned_vertices, membrane_mask, logger=None)#
Rebuild vertex volume to include interpolated points.
- Parameters:
- aligned_verticesnp.ndarray
2D array (N, 3) of all vertex coordinates (including interpolated)
- membrane_masknp.ndarray
3D reference mask for volume shape
- loggerlogging.Logger, optional
Logger instance
- Returns:
- np.ndarray
3D binary volume with 1 at all vertex positions
Notes
Recreates the entire vertex volume from current vertex list. Uses tqdm progress bar for large vertex sets.
- cryocat.analysis.memthick.validate_seg_tomo_compatibility(segmentation_path, tomo_path, tolerance=0.01, logger=None)#
Validate compatibility between segmentation and tomogram files.
Checks dimensions and voxel size compatibility between a segmentation MRC file and its corresponding tomogram for intensity profile analysis.
- Parameters:
- segmentation_pathstr
Path to the MRC segmentation file
- tomo_pathstr
Path to the MRC tomogram file
- tolerancefloat, default 0.01
Tolerance for voxel size comparison (in nanometers)
- loggerlogging.Logger, optional
Logger instance for status messages
- Returns:
- compatiblebool
True if files are compatible for intensity analysis
- detailsdict
Dictionary containing compatibility details: - ‘segmentation_shape’: tuple of segmentation dimensions (ZYX) - ‘tomogram_shape’: tuple of tomogram dimensions (ZYX) - ‘segmentation_voxel_size’: float, voxel size in nm - ‘tomogram_voxel_size’: float, voxel size in nm - ‘dimensions_match’: bool, whether shapes are identical - ‘voxel_sizes_match’: bool, whether voxel sizes are within tolerance - ‘error’: str, error message if validation failed
- cryocat.analysis.memthick.verify_and_save_outputs(aligned_vertices, aligned_normals, vertex_volume, surface1_mask, surface2_mask, membrane_name, base_name, output_dir, voxel_size, origin, save_vertices_mrc=False, save_vertices_xyz=False, logger=None)#
Save surface analysis outputs in multiple formats.
- Parameters:
- aligned_verticesnp.ndarray
2D array (N, 3) of vertex coordinates in voxel units (ZYX order)
- aligned_normalsnp.ndarray
2D array (N, 3) of normal vectors (ZYX order)
- vertex_volumenp.ndarray
3D binary volume marking vertex positions
- surface1_masknp.ndarray
1D boolean array for surface 1 assignment
- surface2_masknp.ndarray
1D boolean array for surface 2 assignment
- membrane_namestr
Name identifier for this membrane
- base_namestr
Base filename for outputs
- output_dirstr
Output directory path
- voxel_sizefloat
Voxel size in nanometers
- origintuple
Origin coordinates (x, y, z) in nanometers
- save_vertices_mrcbool, default False
Whether to save vertex volume as MRC file
- save_vertices_xyzbool, default False
Whether to save coordinates as XYZ point cloud
- loggerlogging.Logger, optional
Logger instance
- Returns:
- bool
True if all requested outputs saved successfully