Skip to content

Add slice interpolation for missing and degraded tissue sections#87

Open
FIrgolitsch wants to merge 3 commits intomainfrom
pr-3-slice-interpolation
Open

Add slice interpolation for missing and degraded tissue sections#87
FIrgolitsch wants to merge 3 commits intomainfrom
pr-3-slice-interpolation

Conversation

@FIrgolitsch
Copy link
Copy Markdown
Contributor

Summary

Serial section imaging frequently produces missing or severely degraded slices (due to tissue loss, fold artefacts, etc.). This PR provides a library and CLI to synthetically reconstruct such sections from adjacent good slices.

Key Changes

New linumpy/stitching/interpolation.py:

  • interpolate_average: simple mean of adjacent slices
  • interpolate_weighted: Gaussian-weighted blend
  • interpolate_registration_based: morphing via SimpleITK with linear/Gaussian blend
  • assess_degraded_slice_quality: SSIM + edge score + variance
  • blend_with_degraded: quality-weighted blend of interpolated and original slice

New scripts/linum_interpolate_missing_slice.py — full CLI; supports --method {average,weighted,registration} and --degraded_slice for quality-blended output when a poor slice exists rather than no slice

New tests:

  • linumpy/tests/test_stitching_interpolation.py
  • scripts/tests/test_interpolate_missing_slice.py

Dependencies

Depends on PR #85 (thread config module).


Merge order: Merge after PR #85.

New linumpy/stitching/interpolation.py library with three interpolation
methods (average, weighted-Gaussian, registration-based morphing) and
degraded-slice quality assessment using SSIM, edge score, and variance.
Corresponding linum_interpolate_missing_slice.py CLI and unit tests.
…treamline min-max scaling for fixed and moving images.
Copy link
Copy Markdown
Contributor

@CHrlS98 CHrlS98 left a comment

Choose a reason for hiding this comment

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

I have a few questions on how it works. see comments below. Also a few changes requested.

@@ -0,0 +1,288 @@
# -*- coding: utf-8 -*-
"""
Slice interpolation utilities for missing or degraded serial sections.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unclear to me what a "slice" actually is... Is it a whole 3D volume, like a slab, or a 2D slice taken from a 3D volume?

Comment on lines +69 to +76
"""Simple 50/50 average of two adjacent volumes.

Parameters
----------
vol_before : np.ndarray
Volume before missing slice (Z, X, Y).
vol_after : np.ndarray
Volume after missing slice (Z, X, Y).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what are the expected shape of these volumes? do they correspond to slabs, tiles, slices?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Also this method (and others in this file, Iguess) expect that both volumes were registered beforehand right? and that slices at z=zi in both volumes describe the same structures? This would need to be mentioned somewhere.

np.ndarray
Weighted average.
"""
from scipy.ndimage import gaussian_filter
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

move import to top of file?

Comment on lines +144 to +145
import SimpleITK as sitk
from linumpy.stitching.registration import register_2d_images_sitk, apply_transform
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

move imports to top of file

metrics : dict
Individual metric scores.
"""
from linumpy.utils.image_quality import (
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

move to top of file

def blend_with_degraded(interpolated: np.ndarray,
degraded: np.ndarray,
quality_weight: float) -> np.ndarray:
"""Blend an interpolated result with a degraded slice weighted by quality.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

add a note on what that could be used for. Quality control?

This script implements registration-based morphing interpolation to reconstruct
a missing slice in a serial sectioning dataset. The method:

1. Registers the slice before the gap to the slice after
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

a slice is a 3D volume? Is it 2D registration? If so it means it assumes that the same content is found at depth z_i in both volumes? I don't understand where it goes in the reconstruction pipeline.

Comment on lines +154 to +155
def register_slices_2d(fixed_slice, moving_slice, metric='MSE', max_iterations=1000):
"""
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

is this used anywhere?

sitk.AffineTransform
Transform representing half the transformation.
"""
import SimpleITK as sitk
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

move to top of file?

Copy link
Copy Markdown
Contributor

@CHrlS98 CHrlS98 left a comment

Choose a reason for hiding this comment

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

Two additional comments on your latest changes. Some comments from previous review are not resolved yet. Take your time, I just want to make sure I'm not too much of a bottleneck.

Z-index for registration reference. Default: middle Z.
When provided, overrides automatic plane selection and uses this
z-index (clamped to each volume's bounds) as the registration
reference in both volumes. When *None* (default),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

shoudn't this be a tuple mapping a slice from fixed volume to corresponding slice in moving volume? using the same reference slice in both volumes never makes sense does it?

Comment on lines +102 to +106
help="Z-index (in each volume, clamped to that volume's bounds)\n"
"to use as the registration reference plane.\n"
"If not specified, the best-correlated plane pair within\n"
"--overlap_search_window planes from each boundary is used\n"
"automatically (recommended).")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

should be a tuple

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