Skip to content

Commit 58aa355

Browse files
committed
Added double output to FocusStack. fsStack.AlignedStackDouble(:, :, :, :) now returns aligned stack with NaNs where pixel value is not available.
1 parent 1ce9de6 commit 58aa355

File tree

4 files changed

+172
-1
lines changed

4 files changed

+172
-1
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
function [tfData] = ExtractAlignedFramesDouble(oStack, sSubs)
2+
3+
% ExtractAlignedFrames - METHOD Extract and align frames from the stack
4+
5+
% - Convert cell references to a subsref structure
6+
if (iscell(sSubs))
7+
subs = sSubs;
8+
clear sSubs;
9+
sSubs.subs = subs;
10+
sSubs.type = '()';
11+
end
12+
13+
% -- Check whether the reference is even possible
14+
15+
if (numel(sSubs) > 1)
16+
error('FocusStack:ImproperReference', '*** FocusStack/ExtractFrames: Only one referencing level is possible.');
17+
end
18+
19+
if (~isequal(sSubs.type, '()'))
20+
error('FocusStack:ImproperReference', '*** FocusStack/ExtractFrames: Only ''()'' referencing is supported.');
21+
end
22+
23+
24+
% -- Check if alignment data exists
25+
26+
if (isempty(oStack.mfFrameShifts))
27+
% - No, so just return un-aligned data
28+
warning('FocusStack:UnalignedStack', '--- FocusStack/ExtractAlignedFrames: Warning: The stack has not yet been aligned. Returning un-aligned stack images.');
29+
tfData = ExtractFrames(oStack, sSubs);
30+
return;
31+
end
32+
33+
34+
% -- Create aligned frames cache, if it doesn't exist
35+
36+
vnStackSize = size(oStack);
37+
if (isempty(oStack.vbCachedAlignedFrames) || isempty(oStack.oAlignedFrameCache))
38+
% - Allocate a cache
39+
oStack.vbCachedAlignedFrames = false(vnStackSize(3:4));
40+
oStack.oAlignedFrameCache = MappedTensor(vnStackSize, 'Class', oStack.strDataClass);
41+
end
42+
43+
44+
% -- Align each frame and extract desired pixels
45+
46+
[nul, cvnRefs, vnDataSize] = GetFullFileRefs(oStack, sSubs.subs);
47+
48+
vnFrames = cvnRefs{1};
49+
50+
% - Record data manipulation state
51+
bSubtractBlack = oStack.bSubtractBlack;
52+
bSubtractBlank = oStack.bSubtractBlank;
53+
bConvertToDFF = oStack.bConvertToDFF;
54+
55+
% Always return double (to allow NaN elements for unavailable pixels)
56+
strOutputDataClass = 'double';
57+
% if (bSubtractBlack || bConvertToDFF)
58+
% strOutputDataClass = 'double';
59+
% else
60+
% strOutputDataClass = oStack.strDataClass;
61+
% end
62+
63+
% - Determine desired frame size
64+
if (numel(vnDataSize) == 3)
65+
tfData = zeros(vnDataSize, strOutputDataClass);
66+
vnFrameSize = vnDataSize(1);
67+
68+
elseif (numel(vnDataSize) == 4)
69+
tfData = zeros([prod(vnDataSize(1:2)) vnDataSize(3:4)], strOutputDataClass);
70+
vnFrameSize = vnDataSize(1:2);
71+
72+
else
73+
% - Shouldn't ever happen
74+
error('FocusStack:UnexpectedError', '*** FocusStack/ExtractAlignedFrames: Unexpected error in data sizing.');
75+
end
76+
77+
% - Turn off data manipulation
78+
oStack.bSubtractBlack = false;
79+
oStack.bConvertToDFF = false;
80+
oStack.bSubtractBlank = false;
81+
oStack.bDoubleOutput=true;
82+
83+
try
84+
for (nFrameIndex = 1:numel(vnFrames))
85+
% -- Check the aligned frame cache
86+
if (false) % all(oStack.vbCachedAlignedFrames(vnFrames(nFrameIndex), cvnRefs{2})))
87+
% - Extract the aligned frames from the cache
88+
tfAlignedFrame = oStack.oAlignedFrameCache(:, :, vnFrames(nFrameIndex), cvnRefs{2});
89+
90+
else
91+
% -- Extract a full frame from the stack
92+
% - Permute to get channels in the third dimension
93+
tfThisFrame = permute(oStack.ExtractFrames({':', ':', vnFrames(nFrameIndex), cvnRefs{2}}), [1 2 4 3]);
94+
95+
% - Compute a translation matrix
96+
vfThisShift = oStack.mfFrameShifts(vnFrames(nFrameIndex), :);
97+
98+
if (any(vfThisShift ~= 0))
99+
mfTranslation = eye(3);
100+
mfTranslation(3, 1:2) = vfThisShift;
101+
oTForm = maketform('projective', mfTranslation);
102+
103+
% - Align the frame according to the pre-calculated shift data
104+
tfAlignedFrame = imtransform(tfThisFrame, oTForm, 'XData', [1 vnStackSize(1)], 'YData', [1 vnStackSize(2)], 'FillValues', nan);
105+
else
106+
tfAlignedFrame = tfThisFrame;
107+
end
108+
109+
% - Insert aligned frame into stack
110+
oStack.oAlignedFrameCache(:, :, vnFrames(nFrameIndex), cvnRefs{2}) = tfAlignedFrame;
111+
oStack.vbCachedAlignedFrames(vnFrames(nFrameIndex), cvnRefs{2}) = true;
112+
end
113+
114+
% - Return only the requested pixels
115+
tfAlignedFrame = reshape(tfAlignedFrame, [], 1, numel(cvnRefs{2}));
116+
117+
% - Should we subtract the black?
118+
if (bSubtractBlack)
119+
% - Subtract the black trace for this frame
120+
tfAlignedFrame = double(tfAlignedFrame) - oStack.vfBlackTrace(vnFrames(nFrameIndex));
121+
end
122+
123+
% - Reshape data and return
124+
tfData(:, nFrameIndex, :) = reshape(ipermute(tfAlignedFrame(cvnRefs{3}, :, :), [1 2 4 3]), [prod(vnFrameSize) 1 numel(cvnRefs{2})]);
125+
end
126+
127+
% - Should we convert to DFF?
128+
if (bConvertToDFF)
129+
% - Extract the blank frame for these frames and divide
130+
tfBlanks = ExtractBlankFrames(oStack, {cvnRefs{3} cvnRefs{1}});
131+
tfData = double(tfData) ./ tfBlanks - 1;
132+
end
133+
134+
% - Should we subtract the blank?
135+
if (bSubtractBlank)
136+
% - Extract the blank frame for these frames and subtract
137+
tfBlanks = ExtractBlankFrames(oStack, {cvnRefs{3} cvnRefs{1}});
138+
tfData = double(tfData) - tfBlanks;
139+
end
140+
141+
catch err
142+
% - Restore data manipulation state
143+
oStack.bSubtractBlack = bSubtractBlack;
144+
oStack.bConvertToDFF = bConvertToDFF;
145+
oStack.bSubtractBlank = bSubtractBlank;
146+
rethrow(err);
147+
end
148+
149+
% - Restore data manipulation state
150+
oStack.bSubtractBlack = bSubtractBlack;
151+
oStack.bSubtractBlank = bSubtractBlank;
152+
oStack.bConvertToDFF = bConvertToDFF;
153+
oStack.bDoubleOutput=false;
154+
155+
% - Return pixels to correct size
156+
tfData = reshape(tfData, vnDataSize);
157+
158+
% --- END ExtractAlignedFrames METHOD ---

@FocusStack/ExtractFrames.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
% -- Read from each file in turn
3232

33-
if (oStack.bSubtractBlack || oStack.bConvertToDFF || oStack.bSubtractBlank)
33+
if (oStack.bSubtractBlack || oStack.bConvertToDFF || oStack.bSubtractBlank || oStack.bDoubleOutput)
3434
strOutputDataClass = 'double';
3535
else
3636
strOutputDataClass = oStack.strDataClass;

@FocusStack/FocusStack.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
% fsStack.AlignedStack(:, :, :, :)
1010
% fsStack.RawStack(:, :, :, :);
1111
%
12+
% To extract aligned frames in double format (including NaN for unavailable pixels:
13+
% fsStack.AlignedStackDouble(:, :, :, :)
14+
%
1215
% To accumulate over the stack:
1316
% fsStack.SummedFrames(:, :, :, :);
1417
% fsStack.SummedAlignedFrames(:, :, :, :);
@@ -35,6 +38,7 @@
3538
cstrFilenames = {};
3639
bConvertToDFF = false;
3740
bSubtractBlank = false;
41+
bDoubleOutput = false;
3842
end
3943

4044
properties (SetAccess = private, GetAccess = private)

@FocusStack/subsref.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@
3737

3838
varargout{1} = ExtractAlignedFrames(oStack, sSubs(2));
3939

40+
case {'AlignedStackDouble'}
41+
if (numel(sSubs) == 1)
42+
sSubs(2).type = '()';
43+
sSubs(2).subs = {':', ':', ':', ':'};
44+
end
45+
46+
varargout{1} = ExtractAlignedFramesDouble(oStack, sSubs(2));
47+
48+
4049
case {'SummedFrames'}
4150
if (numel(sSubs) == 1)
4251
sSubs(2).type = '()';

0 commit comments

Comments
 (0)