Skip to content

Commit 2801600

Browse files
kalidkeclaude
andcommitted
Fix sCMOS scalar calibration and non-square image bug (Issue #37)
Allow sCMOS cameras to use scalar calibration values for modern uniform sensors like Orca Fusion AND fix pre-existing bug with non-square sCMOS images. Issue #37 - Scalar Calibration: When CameraType='SCMOS' with scalar gain/offset/readnoise and empty CalibrationFilePath, the code failed because 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 dimensions after permutation, causing failures with ANY non-square sCMOS data (429×244, etc.), even with proper 2D calibration arrays. This was hidden when using square images (256×256) where transpose doesn't change dimensions. Changes: - FindROI.m constructor (lines 86-104): For sCMOS with scalar calibration, expand scalars to 2D variance image matching Data dimensions. THIS IS THE ONLY PLACE SCALARS NEED EXPANSION. - FindROI.gauss_sCMOS (lines 366-368): Fix output array dimensions after permutation by allocating to match PermutedStack size, not original Stack size. - SingleMoleculeFitting.m: Update documentation to clarify sCMOS supports both pixel-wise arrays and scalars (auto-expanded). Why convertToPhotons doesn't need changes: MATLAB handles scalar division correctly - the else branch at line 118 already works fine for scalars. Expansion is ONLY needed for sCMOS variance image (Varim) used by CUDA kernels. Testing: - Non-square sCMOS with scalars: ✓ Works (429×244 verified) - Non-square sCMOS with 2D arrays: ✓ Works (was broken, now fixed) - Square sCMOS: ✓ Works (backward compatible) - DataToPhotons unit tests: ✓ All pass (5/5) Fixes #37 + non-square sCMOS bug 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 7bef54a commit 2801600

2 files changed

Lines changed: 30 additions & 9 deletions

File tree

MATLAB/+smi_core/@FindROI/FindROI.m

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,29 @@
8383
switch SMF.Data.CameraType
8484
case 'SCMOS'
8585
obj.IsSCMOS = 1;
86-
obj.Varim = gpuArray(single(SMF.Data.CameraReadNoise./SMF.Data.CameraGain.^2));
86+
% For sCMOS with scalar calibration (modern uniform
87+
% sensors like Orca Fusion), expand to 2D variance image
88+
% matching data dimensions. This supports Issue #37 fix.
89+
CameraReadNoise = SMF.Data.CameraReadNoise;
90+
CameraGain = SMF.Data.CameraGain;
91+
if isscalar(CameraReadNoise) && isscalar(CameraGain)
92+
% Need 2D variance image for sCMOS CUDA kernels
93+
% Expand based on Data dimensions if available
94+
if nargin > 1 && ~isempty(Data)
95+
[NRows, NCols, ~] = size(Data);
96+
CameraReadNoise = CameraReadNoise * ones(NRows, NCols, 'single');
97+
CameraGain = CameraGain * ones(NRows, NCols, 'single');
98+
else
99+
% Data not yet available - will fail if used
100+
% This case shouldn't happen in normal workflow
101+
warning('FindROI: sCMOS with scalar calibration but no Data provided');
102+
end
103+
end
104+
obj.Varim = gpuArray(single(CameraReadNoise./CameraGain.^2));
87105
otherwise
88106
obj.IsSCMOS = 0;
89107
end
90-
108+
91109
end
92110

93111
if nargin > 1
@@ -344,9 +362,11 @@ function showOverlay(obj)
344362
Out1 = feval(K_Gauss,gpuArray(Stack),Varim,Out1,size(Stack,1),Sigma);
345363

346364
%Permuting and doing the other dimension
347-
Out = gpuArray(zeros(size(Stack),'single'));
348-
Out = feval(K_Gauss,permute(Out1,[2 1 3]),permute(Varim,[2 1]),Out,size(Stack,1),Sigma);
349-
365+
% For non-square images, output dimensions must match permuted input
366+
PermutedStack = permute(Out1,[2 1 3]);
367+
Out = gpuArray(zeros(size(PermutedStack),'single'));
368+
Out = feval(K_Gauss,PermutedStack,permute(Varim,[2 1]),Out,size(PermutedStack,1),Sigma);
369+
350370
%Permute back
351371
Out = permute(Out,[2 1 3]);
352372

MATLAB/+smi_core/@SingleMoleculeFitting/SingleMoleculeFitting.m

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -391,10 +391,11 @@
391391
'precedence over the inclusion set']);
392392
obj.SMFFieldNotes.Data.CameraType.Tip = ...
393393
sprintf(['Type of camera used to collect the raw data.\n', ...
394-
'CameraGain, CameraOffset, CameraReadNoise) should be\n', ...
395-
'scalars if the CameraType is EMCCD while if SCMOS,\n', ...
396-
'square arrays taken from the file located at the ', ...
397-
'CalibrationFilePath.']);
394+
'CameraGain, CameraOffset, CameraReadNoise should be:\n', ...
395+
' EMCCD: scalars\n', ...
396+
' SCMOS: either square arrays from CalibrationFilePath\n', ...
397+
' OR scalars for uniform sensors (e.g., Orca Fusion).\n', ...
398+
'Scalar values for SCMOS will be expanded automatically.']);
398399
obj.SMFFieldNotes.Data.CameraGain.Tip = ...
399400
'Gain of the camera used to collect the raw data';
400401
obj.SMFFieldNotes.Data.CameraOffset.Tip = ...

0 commit comments

Comments
 (0)