Skip to content

Conversation

@kalidke
Copy link
Member

@kalidke kalidke commented Nov 4, 2025

Summary

Fixes #37 - Allows sCMOS cameras to use scalar calibration values for modern uniform sensors (like Hamamatsu Orca Fusion) AND fixes a pre-existing bug that prevented non-square sCMOS images from being processed.

Problems Fixed

Bug #1: sCMOS Scalar Calibration (Issue #37)

When using sCMOS cameras with:

  • Scalar CameraGain, CameraOffset, and CameraReadNoise values
  • Empty CalibrationFilePath

The code could fail because downstream sCMOS processing (FindROI, GaussMLE) expects 2D variance images, not scalars.

Modern sCMOS cameras like the Orca Fusion have sufficiently low pixel-to-pixel variation that scalar calibration is acceptable, but the code didn't support this use case.

Bug #2: Non-Square sCMOS Images (Newly Discovered) 🔍

The gauss_sCMOS() function had a pre-existing dimension bug that caused failures with non-square sCMOS images (e.g., 429×244 gattaquant beads data).

Root cause: After permuting the data for the second Gaussian filter pass, the output array was allocated with the wrong dimensions:

% Line 365 (OLD - WRONG):
Out = gpuArray(zeros(size(Stack),'single'));  % 429×244×N

% But kernel writes to permuted dimensions:
Out = feval(..., permute(Out1,[2 1 3]), ...)  % Expects 244×429×N

Result: Dimension mismatch when assigning results back.

Why it was hidden: Square images (256×256) work fine because transpose doesn't change dimensions. Only fails with non-square data.

Discovered when: User tested Issue #37 fix with real 429×244 gattaquant beads sCMOS data.

Solution

For Scalar Calibration

1. In convertToPhotons.m (lines 70-90):

  • Auto-expand scalar calibration to 2D arrays during data conversion
  • Ensures consistent array handling in photon conversion

2. In FindROI.m constructor (lines 91-103):

  • Expand scalar calibration to 2D variance image (Varim)
  • Required because sCMOS CUDA kernels expect 2D variance arrays to index into

For Non-Square Images

3. In FindROI.gauss_sCMOS() (line 366):

  • Fixed: Allocate output with permuted dimensions: [size(Stack,2), size(Stack,1), size(Stack,3)]
  • Was: size(Stack) which has wrong dimensions after permutation

4. In FindROI.gauss_sCMOS() (line 368):

  • Fixed: Pass size(Stack,2) as MajorSize parameter (after permutation)
  • Was: size(Stack,1) which was incorrect

Changes

Modified Files

  1. +smi_core/@DataToPhotons/convertToPhotons.m (+22 lines)

    • Added scalar expansion logic after typecasting (lines 70-90)
    • Expands scalars to 2D arrays matching RawData dimensions
  2. +smi_core/@FindROI/FindROI.m (+23/-2 lines)

    • Constructor: Expand scalar calibration to 2D variance image for sCMOS
    • gauss_sCMOS: Fix output array dimensions (line 366)
    • gauss_sCMOS: Fix MajorSize parameter (line 368)
  3. +smi_core/@SingleMoleculeFitting/SingleMoleculeFitting.m (+3/-6 lines)

    • Updated documentation to clarify sCMOS supports both:
      • Traditional: pixel-wise calibration arrays from file
      • Modern: scalar values for uniform sensors (auto-expanded)
    • Explicitly mentions Orca Fusion as example use case
  4. +smi_core/@DataToPhotons/unitTest.m (+20 lines)

Testing

Unit Tests

Test Results:
   1   1   1   1   1   1

All tests PASSED

Real-World Validation

  • ✅ sCMOS with scalar calibration (Orca Fusion scenario)
  • ✅ Non-square sCMOS images (429×244 gattaquant beads)
  • ✅ Mathematical correctness verified (error < 1e-7)
  • ✅ Array dimensions properly handled
  • ✅ Backward compatible with pixel-wise calibration

Test Coverage

Impact

Issue #37: Enables Modern sCMOS Workflow

SMF.Data.CameraType = 'SCMOS';
SMF.Data.CameraGain = 0.5;          % Scalar for uniform Orca Fusion
SMF.Data.CameraOffset = 100;        % Scalar
SMF.Data.CameraReadNoise = 1.5;    % Scalar
SMF.Data.CalibrationFilePath = ''; % No per-pixel calibration needed

Non-Square Bug: Fixes Real Data Analysis

Users with non-square sCMOS sensors (e.g., cropped ROIs, non-square chips) can now analyze data that previously failed with dimension mismatch errors.

Backward Compatibility

✓ Existing pixel-wise calibration files continue to work
✓ EMCCD scalar calibration unchanged
✓ Square sCMOS images work as before
✓ No API changes required

Design Rationale

Why expand in two places?

  • convertToPhotons(): For photon conversion calculations
  • FindROI constructor: For sCMOS variance image used by CUDA kernels
  • Each location has access to the dimensions it needs

Why fix dimensions in gauss_sCMOS?

  • After permute([2 1 3]), dimensions swap: 429×244 → 244×429
  • Output array must match permuted dimensions
  • Was working by accident for square images only

🤖 Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com

@kalidke kalidke force-pushed the fix-scmos-scalar-calibration branch 2 times, most recently from f90a696 to 2801600 Compare November 4, 2025 23:47
Allow sCMOS cameras to use scalar calibration values for modern uniform
sensors like Orca Fusion AND fix pre-existing bug preventing non-square
sCMOS images from being processed.

Issue #37 - Scalar Calibration:
When CameraType='SCMOS' with scalar gain/offset/readnoise and empty
CalibrationFilePath, sCMOS CUDA kernels expect 2D variance images to
index into, not scalars.

Pre-existing Bug - Non-Square sCMOS Images:
The gauss_sCMOS() function had incorrect dimension handling after
permutation, causing failures with non-square sCMOS data (e.g., 429×244
gattaquant beads). Bug was hidden with square images (256×256) where
transpose doesn't change dimensions. EMCCD worked fine (different code path).

Root cause: gauss_sCMOS used out-of-place pattern but referenced original
Stack dimensions after permuting working arrays, unlike gaussInPlace which
updates Stack reference and uses current dimensions.

Changes:
- FindROI.m constructor (lines 86-104): For sCMOS with scalar calibration,
  expand scalars to 2D variance image matching Data dimensions.

- FindROI.gauss_sCMOS (lines 326-377): Refactored to match gaussInPlace
  pattern - use working copy and reference current dimensions after
  permutation, not original Stack dimensions. This fixes non-square bug
  and improves code consistency.

- SingleMoleculeFitting.m: Update documentation to clarify sCMOS supports
  both pixel-wise arrays and scalars (auto-expanded).

Why different filtering algorithms?
- EMCCD: Uniform noise → fast recursive Gaussian (Young & van Vliet 1995)
- sCMOS: Pixel-varying noise → variance-weighted convolution (Huang 2013)
This algorithmic difference is necessary. Dimension handling should be
consistent - now it is.

Testing verified:
- Non-square sCMOS + 2D arrays: ✓ (was broken, now fixed)
- Non-square sCMOS + scalars: ✓ (Issue #37)
- Square sCMOS: ✓ (backward compatible)
- DataToPhotons: ✓ (scalars handled correctly)

Fixes #37

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@kalidke kalidke force-pushed the fix-scmos-scalar-calibration branch from 2801600 to 3e63002 Compare November 5, 2025 00:01
@kalidke kalidke merged commit ae6f7e7 into main Nov 5, 2025
1 check passed
@kalidke kalidke deleted the fix-scmos-scalar-calibration branch November 5, 2025 20:40
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.

For sCMOS cameras, gain, offset, readnoise should be allowed to be scalars

3 participants