Claude Code Plugins

Community-maintained marketplace

Feedback

lightsheet-psf-deconvolution

@smith6jt-cop/Skills_Registry
0
0

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

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name lightsheet-psf-deconvolution
description KINTSUGI deconvolution: True lightsheet PSF calculation to fix horizontal banding artifacts. Trigger: deconvolution artifacts, horizontal banding, PSF issues, fcyl, slitwidth, lightsheet, LsDeconv.
author KINTSUGI Team
date Sat Dec 27 2025 00:00:00 GMT+0000 (Coordinated Universal Time)

Lightsheet PSF for Deconvolution - Fixing Horizontal Banding Artifacts

Experiment Overview

Item Details
Date 2025-12-27
Goal Fix horizontal banding artifacts in Python deconvolution by implementing true lightsheet PSF
Environment KINTSUGI KDecon module, HiPerGator, CuPy GPU
Status RESOLVED

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)

Attempt Why it Failed Lesson Learned
Ignoring fcyl/slitwidth as "metadata only" These aren't metadata - they define the PSF shape Check MATLAB reference code before dismissing parameters
Using same NA for both excitation and emission Lightsheet has separate illumination NA Lightsheet optics are fundamentally different from widefield
Using same coordinate system for both PSFs Lightsheet illuminates perpendicular to detection The coordinate swap (z,0,x) is essential

Key Parameters

Parameter Typical Value Description
fcyl 1 mm Cylinder lens focal length
slitwidth 6.5 mm Slit aperture width
NA_ls ~0.956 Calculated: 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