Skip to content

Conversation

@davidackerman
Copy link
Collaborator

@davidackerman davidackerman commented Aug 5, 2025

@stuarteberg
This pull request introduces several improvements and refactors to the affinity postprocessing logic, particularly in the AffinityPostprocessor class, and also updates channel handling in utility functions. The main changes include enhanced fragment filtering, more flexible bias parameters for segmentation, and improved compatibility for channel naming.

Affinity postprocessor improvements:

  • Refactored the AffinityPostprocessor constructor to replace the single bias parameter with adjacent_edge_bias, lr_bias_ratio, and filter_val for finer control over segmentation behavior. (cellmap_flow/post/postprocessors.py [1] [2]
  • Added a new filter_fragments method to filter MWS fragments based on mean affinity values, improving postprocessing quality. (cellmap_flow/post/postprocessors.py cellmap_flow/post/postprocessors.pyL148-R250)
  • Enhanced the _process method to include data normalization, noise addition, affinity smoothing, and application of the new bias parameters, as well as fragment filtering. (cellmap_flow/post/postprocessors.py cellmap_flow/post/postprocessors.pyL148-R250)

Channel and block shape handling:

  • Updated the computation of block_shape in _get_config to use config.output_channels instead of the possibly undefined local channels variable, fixing a potential bug. (cellmap_flow/utils/data.py cellmap_flow/utils/data.pyL125-R125)
  • Improved the get_dacapo_channels function to generate channel names based on the neighborhood attribute for better backward compatibility, instead of defaulting to ["x", "y", "z"]. (cellmap_flow/utils/data.py cellmap_flow/utils/data.pyL387-R388)

Copilot AI review requested due to automatic review settings August 5, 2025 17:30
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request refactors the AffinityPostprocessor class to provide more granular control over segmentation parameters and improves channel handling utilities. The changes enhance the flexibility of affinity-based segmentation postprocessing and fix potential bugs in channel configuration.

  • Replaced single bias parameter with three separate bias controls (adjacent_edge_bias, lr_bias_ratio, filter_val) for more precise segmentation tuning
  • Added fragment filtering capability based on mean affinity values with a new filter_fragments method
  • Enhanced the processing pipeline with data normalization, noise addition, and affinity smoothing
  • Fixed channel reference bug and improved backward compatibility for DaCapo channel naming

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.

File Description
cellmap_flow/post/postprocessors.py Major refactor of AffinityPostprocessor with new bias parameters, fragment filtering method, and enhanced processing pipeline
cellmap_flow/utils/data.py Fixed block_shape calculation bug and improved channel naming for AffinitiesTask backward compatibility

self.filter_val = float(filter_val)
self.neighborhood = ast.literal_eval(neighborhood)
self.use_exact = use_exact == "True"
self.use_exact = use_exact == "False"
Copy link

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic appears inverted - setting use_exact = use_exact == "False" means use_exact will be True when the string is "False" and False otherwise. This seems counterintuitive and likely incorrect.

Suggested change
self.use_exact = use_exact == "False"
self.use_exact = use_exact == "True"

Copilot uses AI. Check for mistakes.
Comment on lines +158 to 160
import numpy as np
from scipy.ndimage import measurements

Copy link

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imports should be at the top of the file, not inside a method. Move this import to the top of the file with other imports.

Suggested change
import numpy as np
from scipy.ndimage import measurements

Copilot uses AI. Check for mistakes.
self.neighborhood = self.neighborhood[:n_channels]
# raise Exception(data.max(), data.min(), self.neighborhood)
import numpy as np
from scipy.ndimage import measurements
Copy link

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imports should be at the top of the file, not inside a method. This import is also redundant as measurements is already imported at the top.

Suggested change
from scipy.ndimage import measurements

Copilot uses AI. Check for mistakes.
"""

filtered_fragments = []
average_affs: float = np.mean(affs_data.data, axis=0)
Copy link

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessing .data attribute on affs_data may fail if affs_data is a numpy array rather than an object with a .data attribute. Use affs_data directly instead of affs_data.data.

Suggested change
average_affs: float = np.mean(affs_data.data, axis=0)
average_affs: float = np.mean(affs_data, axis=0)

Copilot uses AI. Check for mistakes.

if data.max() < 1e-4:
segmentation = np.zeros(
data.shape, dtype=np.uint64 if self.use_exact else np.uint16
Copy link

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shape for the zeros array should match the spatial dimensions of the data, but data.shape includes the channel dimension. Use data.shape[1:] instead of data.shape to exclude the channel dimension.

Suggested change
data.shape, dtype=np.uint64 if self.use_exact else np.uint16
data.shape[1:], dtype=np.uint64 if self.use_exact else np.uint16

Copilot uses AI. Check for mistakes.
filtered_fragments: np.ndarray = np.array(
filtered_fragments, dtype=fragments_data.dtype
)
# replace: np.ndarray = np.zeros_like(filtered_fragments)
Copy link

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented-out code that is not being used. This line appears to be leftover development code.

Suggested change
# replace: np.ndarray = np.zeros_like(filtered_fragments)

Copilot uses AI. Check for mistakes.
if self.filter_val > 0.0:
self.filter_fragments(data, segmentation, self.filter_val)

# fragment_ids = fastremap.unique(segmentation[segmentation > 0])
Copy link

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented-out code. These lines appear to be leftover from the previous implementation.

Suggested change
# fragment_ids = fastremap.unique(segmentation[segmentation > 0])

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants