Skip to content

Add Suite2p-aware weighted ROI similarity utilities#1803

Closed
FlorianPfaff wants to merge 3 commits intomainfrom
weighted-roi-similarity
Closed

Add Suite2p-aware weighted ROI similarity utilities#1803
FlorianPfaff wants to merge 3 commits intomainfrom
weighted-roi-similarity

Conversation

@FlorianPfaff
Copy link
Copy Markdown
Owner

Summary

This PR adds a Suite2p-aware ROI similarity layer for longitudinal neuron identity tracking.

Current open tracking-related PRs already cover:

What is still missing is a reusable utility that preserves Suite2p footprint weights (lam) instead of reducing ROIs to binary support. This PR fills that gap by adding weighted ROI similarity and a fused ROI cost-matrix builder.

Added

  • pyrecest/utils/roi_similarity.py
    • weighted_roi_jaccard
    • weighted_roi_cosine_similarity
    • pairwise_roi_similarity
    • roi_centroid
    • pairwise_centroid_distances
    • build_roi_cost_matrix
  • exports in pyrecest/utils/__init__.py
  • pyrecest/tests/test_roi_similarity.py

Motivation

For cross-session calcium-cell tracking, binary IoU is a useful baseline but it discards intensity structure already available in Suite2p stat.npy entries. In particular, lam, med, and overlap can be exploited to build a better appearance/gating signal for downstream assignment.

This PR therefore enables:

  • lam-aware weighted footprint matching
  • optional exclusion of Suite2p overlap pixels
  • centroid extraction using med when available
  • fused appearance + centroid ROI costs for downstream association

Scope

This PR is intentionally utility-level and does not reimplement the assignment logic already proposed elsewhere. It is meant to complement the existing ROI-assignment / feature-association PRs rather than duplicate them.

@github-actions
Copy link
Copy Markdown

MegaLinter analysis: Error

Descriptor Linter Files Fixed Errors Warnings Elapsed time
✅ COPYPASTE jscpd yes no no 16.91s
✅ JSON prettier 2 0 0 0 0.46s
✅ JSON v8r 2 0 0 2.34s
✅ MARKDOWN markdownlint 2 0 0 0 0.68s
✅ MARKDOWN markdown-table-formatter 2 0 0 0 0.22s
✅ PYTHON bandit 353 0 0 5.28s
✅ PYTHON black 353 9 0 0 8.55s
✅ PYTHON flake8 353 0 0 2.92s
✅ PYTHON isort 353 14 0 0 0.69s
✅ PYTHON mypy 353 0 0 4.85s
❌ PYTHON pylint 353 7 0 110.02s
✅ PYTHON ruff 353 14 0 0 0.07s
✅ REPOSITORY checkov yes no no 24.83s
✅ REPOSITORY gitleaks yes no no 9.83s
✅ REPOSITORY git_diff yes no no 0.04s
✅ REPOSITORY secretlint yes no no 7.16s
✅ REPOSITORY syft yes no no 3.68s
✅ REPOSITORY trivy-sbom yes no no 2.39s
✅ REPOSITORY trufflehog yes no no 20.14s
✅ YAML prettier 4 0 0 0 0.48s
✅ YAML v8r 4 0 0 5.2s
✅ YAML yamllint 4 0 0 0.45s

Detailed Issues

❌ PYTHON / pylint - 7 errors
************* Module pyrecest.utils.roi_similarity
pyrecest/utils/roi_similarity.py:35:0: R0915: Too many statements (51/50) (too-many-statements)
pyrecest/utils/roi_similarity.py:353:0: R0914: Too many local variables (16/15) (too-many-locals)
************* Module update_init_helper
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.nonrigid_point_set_registration:[211:221]
==pyrecest.utils.point_set_registration:[241:251]
    costs = asarray(cost_matrix)
    if costs.ndim != 2:
        raise ValueError("cost_matrix must be two-dimensional.")
    if costs.shape[0] == 0:
        return zeros((0,), dtype=int64)
    if costs.shape[1] == 0:
        return zeros((costs.shape[0],), dtype=int64) - 1

    finite_mask = isfinite(costs)
    finite_costs = costs[finite_mask] (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.nonrigid_point_set_registration:[124:135]
==pyrecest.utils.point_set_registration:[107:118]
    assignment: Any
    matched_reference_indices: Any
    matched_moving_indices: Any
    transformed_reference_points: Any
    matched_costs: Any
    rmse: float
    n_iterations: int
    converged: bool


def _as_point_array(points): (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.nonrigid_point_set_registration:[319:329]
==pyrecest.utils.point_set_registration:[390:400]
    association_cost = _default_cost if cost_function is None else cost_function

    for iteration in range(1, max_iterations + 1):
        transformed_reference = transform.apply(reference)
        current_costs = asarray(association_cost(transformed_reference, moving))
        if current_costs.shape != (reference.shape[0], moving.shape[0]):
            raise ValueError(
                "cost_function must return an array of shape (n_reference, n_moving)."
            )
 (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.nonrigid_point_set_registration:[146:154]
==pyrecest.utils.point_set_registration:[129:137]
    source = _as_point_array(source_points)
    target = _as_point_array(target_points)
    if source.shape != target.shape:
        raise ValueError("source_points and target_points must have the same shape.")
    return source, target


def _tps_kernel_from_distances(distances, epsilon: float = 1e-12): (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.nonrigid_point_set_registration:[230:236]
==pyrecest.utils.point_set_registration:[262:268]
    row_indices, col_indices = linear_sum_assignment(padded_costs)

    assignment = zeros((costs.shape[0],), dtype=int64) - 1
    for row_index, col_index in zip(row_indices, col_indices):
        if row_index >= costs.shape[0] or col_index >= costs.shape[1]:
            continue (duplicate-code)

------------------------------------
Your code has been rated at 10.00/10

See detailed reports in MegaLinter artifacts

Your project could benefit from a custom flavor, which would allow you to run only the linters you need, and thus improve runtime performances. (Skip this info by defining FLAVOR_SUGGESTIONS: false)

  • Documentation: Custom Flavors
  • Command: npx mega-linter-runner@9.4.0 --custom-flavor-setup --custom-flavor-linters PYTHON_PYLINT,PYTHON_BLACK,PYTHON_FLAKE8,PYTHON_ISORT,PYTHON_BANDIT,PYTHON_MYPY,PYTHON_RUFF,COPYPASTE_JSCPD,JSON_V8R,JSON_PRETTIER,MARKDOWN_MARKDOWNLINT,MARKDOWN_MARKDOWN_TABLE_FORMATTER,REPOSITORY_CHECKOV,REPOSITORY_GIT_DIFF,REPOSITORY_GITLEAKS,REPOSITORY_SECRETLINT,REPOSITORY_SYFT,REPOSITORY_TRIVY_SBOM,REPOSITORY_TRUFFLEHOG,YAML_PRETTIER,YAML_YAMLLINT,YAML_V8R

MegaLinter is graciously provided by OX Security
Show us your support by starring ⭐ the repository

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.

1 participant