Claude-skill-registry lightsheet-psf-deconvolution

KINTSUGI deconvolution: True lightsheet PSF calculation to fix horizontal banding artifacts. Trigger: deconvolution artifacts, horizontal banding, PSF issues, fcyl, slitwidth, lightsheet, LsDeconv.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/lightsheet-psf-deconvolution" ~/.claude/skills/majiayu000-claude-skill-registry-lightsheet-psf-deconvolution && rm -rf "$T"
manifest: skills/data/lightsheet-psf-deconvolution/SKILL.md
source content

Lightsheet PSF for Deconvolution - Fixing Horizontal Banding Artifacts

Experiment Overview

ItemDetails
Date2025-12-27
GoalFix horizontal banding artifacts in Python deconvolution by implementing true lightsheet PSF
EnvironmentKINTSUGI KDecon module, HiPerGator, CuPy GPU
StatusRESOLVED

Context

The Python KDecon module was producing horizontal banding artifacts after deconvolution. The original MATLAB LsDeconv.m worked correctly. Investigation revealed that Python was using a widefield PSF that ignored the lightsheet parameters (

fcyl
and
slitwidth
), while MATLAB used a true lightsheet PSF.

Root Cause

The lightsheet PSF is fundamentally different from a widefield PSF:

Widefield PSF (WRONG for lightsheet data)

# Both excitation and emission use same NA and coordinate system
psf_ex = PSF(x, y, z, NA, n, lambda_ex)
psf_em = PSF(x, y, z, NA, n, lambda_em)
psf = psf_ex * psf_em

Lightsheet PSF (CORRECT - from MATLAB LsDeconv.m)

# Excitation uses lightsheet NA and SWAPPED coordinates (z, 0, x)
# Emission uses objective NA and standard coordinates (x, y, z)
NA_ls = np.sin(np.arctan(slitwidth / (2 * fcyl)))  # ~0.956 for fcyl=1, slitwidth=6.5
psf_ex = PSF(z, 0, x, NA_ls, n, lambda_ex)   # Note: z->x, y->0, x->z
psf_em = PSF(x, y, z, NA_obj, n, lambda_em)  # Standard coordinates
psf = psf_ex * psf_em

The coordinate swap

(z, 0, x)
instead of
(x, y, z)
models the lightsheet illuminating perpendicular to the detection axis.

Solution

1. Added
_psf_light_sheet_full()
function to
psf.py

def _psf_light_sheet_full(x, y, z, NA_obj, n, lambda_ex, lambda_em, NA_ls):
    """
    True lightsheet PSF matching MATLAB LsDeconv implementation.
    """
    # Lightsheet excitation PSF - coordinate swap (z, 0, x)
    psf_ex = _psf_single_wavelength(z, 0, x, NA_ls, n, lambda_ex)
    # Objective emission PSF - standard (x, y, z)
    psf_em = _psf_single_wavelength(x, y, z, NA_obj, n, lambda_em)
    return psf_ex * psf_em

2. Updated
generate_psf()
to use lightsheet mode when parameters provided

def generate_psf(dxy, dz, NA, n, lambda_ex, lambda_em,
                 fcyl=None, slitwidth=None, ...):
    use_lightsheet = fcyl is not None and slitwidth is not None
    if use_lightsheet:
        NA_ls = np.sin(np.arctan(slitwidth / (2 * fcyl)))
        # Use _psf_light_sheet_full instead of _psf_light_sheet

3. Updated
main.py
to pass parameters through

def _compute_psf(self):
    self._psf, self._psf_info = generate_psf(
        self.dxy, self.dz, self.NA, self.rf,
        self.lambda_ex, self.lambda_em,
        fcyl=self.fcyl,        # ADD
        slitwidth=self.slitwidth,  # ADD
        verbose=self.verbose
    )

4. Updated notebook DECON_PARAMS

DECON_PARAMS = {
    'xy_vox': 377,
    'z_vox': 1500,
    'iterations': 25,
    'mic_NA': 0.75,
    'tissue_RI': 1.44,
    'damping': 0,
    'stop_criterion': 5.0,
    'device': 'auto',
    'hist_clip': 0.01,      # ADD - histogram clipping percentage
    'slit_aper': 6.5,       # ADD - slit aperture width (mm)
    'f_cyl': 1,             # ADD - cylinder lens focal length (mm)
}

Failed Attempts (Critical)

AttemptWhy it FailedLesson Learned
Ignoring fcyl/slitwidth as "metadata only"These aren't metadata - they define the PSF shapeCheck MATLAB reference code before dismissing parameters
Using same NA for both excitation and emissionLightsheet has separate illumination NALightsheet optics are fundamentally different from widefield
Using same coordinate system for both PSFsLightsheet illuminates perpendicular to detectionThe coordinate swap (z,0,x) is essential

Key Parameters

ParameterTypical ValueDescription
fcyl
1 mmCylinder lens focal length
slitwidth
6.5 mmSlit aperture width
NA_ls
~0.956Calculated:
sin(atan(slitwidth / (2 * fcyl)))
hist_clip
0.01%Histogram clipping for output normalization

Diagnostic Signs

Symptom: Horizontal banding artifacts after deconvolution

  1. Check if
    fcyl
    and
    slitwidth
    are being passed to PSF generation
  2. Check if PSF uses coordinate swap for excitation component
  3. Compare PSF shape - lightsheet PSF should be anisotropic (narrower in lightsheet direction)

Key Insights

  • MATLAB is the reference - When Python produces artifacts MATLAB doesn't, compare implementations line-by-line
  • "Metadata" parameters may be functional - Just because a parameter isn't in the main algorithm doesn't mean it's unused
  • PSF shape determines deconvolution quality - Wrong PSF = wrong deconvolution = artifacts
  • Coordinate swaps are not typos - In optics code, coordinate manipulations usually have physical meaning

References

  • MATLAB LsDeconv.m (lines 560, 652-654): Original lightsheet deconvolution implementation
  • notebooks/Kdecon/psf.py
    : Python PSF calculation
  • notebooks/Kdecon/main.py
    : Python deconvolution interface
  • Commit
    37d1693
    : fix(decon): implement true lightsheet PSF matching MATLAB LsDeconv