1+ classdef DeepInterpolationDataStore < matlab .io .Datastore & ...
2+ matlab .io .datastore .Subsettable & ...
3+ matlab .io .datastore .Shuffleable
4+ % DEEPINTERPOLATIONDATASTORE - custom datastore for DeepInterpolation-MATLAB
5+ %
6+ % This custom datastore provides flanking frames and the center frame
7+ % upon one read.
8+ %
9+ % dids = DeepInterpolationDataStore(pathToTiffFile, options);
10+ %
11+ % Input must be full path to a grayscale, single channel tiff stack of
12+ % >'flankingFrames + 2' frames in order to work (this is according to
13+ % the function of the DeepInterpolation network).
14+ %
15+ % If the image frame dimensions differ from the network input size
16+ % the doAutoResize option controls whether the frames will be
17+ % automatically resized to outputFrameSize before they are returned.
18+ %
19+ % Dr. Thomas Künzel, The MathWorks, 2023
20+ 21+
22+ properties
23+ fileName string
24+ doAutoResize logical
25+ numberOfFlankingFrames int32
26+ outputFrameSize int32
27+ frameCount double
28+ dsSetCount double
29+ setsAvailable double
30+ currentSet double
31+ setFramesStartIndex double
32+ currentFrameIndex double
33+ allSetFrameStartIndices double
34+ end
35+
36+ methods % begin methods section
37+ function myds = DeepInterpolationDataStore(filePath , options )
38+ arguments
39+ filePath
40+ options = struct();
41+ end
42+ if isfield(options , ' doAutoResize' )
43+ myds.doAutoResize = logical(options .doAutoResize );
44+ else % default
45+ myds.doAutoResize = false ;
46+ end
47+ if isfield(options , ' numberOfFlankingFrames' )
48+ assert(options .numberOfFlankingFrames > 0 )
49+ assert(rem(options .numberOfFlankingFrames , 2 ) == 0 , " Number of flanking frames should be even." )
50+ myds.numberOfFlankingFrames = options .numberOfFlankingFrames ;
51+ else % default
52+ myds.numberOfFlankingFrames = 60 ;
53+ end
54+ if isfield(options , ' outputFrameSize' )
55+ if not (myds .doAutoResize )
56+ warning(' Specified an output frame size, but auto-resize is turned off.' )
57+ end
58+ outputFrameSize = options .outputFrameSize ;
59+ if not (isnumeric(outputFrameSize ) && isequal(size(outputFrameSize ), [1 , 2 ]) && all(outputFrameSize >= 0 ))
60+ error(' outputFrameSize should be an array with dimension 1x2 and non-negative values.' );
61+ end
62+ myds.outputFrameSize = outputFrameSize ;
63+ else % default
64+ myds.outputFrameSize = [512 , 512 ];
65+ end
66+ assert(isfile(filePath ));
67+ myds.fileName = filePath ;
68+ fileInfo = imfinfo(myds .fileName );
69+ assert(strcmp(fileInfo(1 ).Format,' tif' ), " Must be tiff format" );
70+ if ~myds .doAutoResize
71+ assert((fileInfo(1 ).Width == myds .outputFrameSize(1 )) ...
72+ && (fileInfo(1 ).Height == myds .outputFrameSize(2 )),...
73+ " Actual frame size is not equal to specified outputFrameSize" );
74+ end
75+ framePerSetCount = myds .numberOfFlankingFrames + 3 ;
76+ assert(numel(fileInfo ) >= framePerSetCount , " Not enough frames in stack for DeepInterpolation" );
77+ myds.frameCount = numel(fileInfo );
78+ myds.dsSetCount = myds .frameCount - framePerSetCount + 1 ;
79+ myds.allSetFrameStartIndices = 1 : myds .dsSetCount ;
80+ reset(myds );
81+ end
82+
83+ function tf = hasdata(myds )
84+ % Return true if more data is available.
85+ tf = myds .setsAvailable > 0 ;
86+ end
87+
88+ function [data ,info ] = read(myds )
89+ % Read data and information about the extracted data.
90+ assert(hasdata(myds ), " No more data to read" );
91+ rawRefFrame = imread(myds .fileName ,myds .currentFrameIndex );
92+ if myds .doAutoResize
93+ rawRefFrame = imresize(rawRefFrame ,myds .outputFrameSize );
94+ end
95+ refFrame = single(rawRefFrame );
96+ flankingFrames = single( ...
97+ ones(myds .outputFrameSize(1 ), ...
98+ myds .outputFrameSize(2 ), ...
99+ myds .numberOfFlankingFrames ) ...
100+ );
101+ framecount = 1 ;
102+ for leftFrame = 0 : (myds .numberOfFlankingFrames / 2 ) - 1
103+ rawThisFrame = imread(myds .fileName ,myds .setFramesStartIndex + leftFrame );
104+ if myds .doAutoResize
105+ rawThisFrame = imresize(rawThisFrame ,myds .outputFrameSize );
106+ end
107+ thisFrame = single(rawThisFrame );
108+ flankingFrames(: ,: ,framecount ) = thisFrame ;
109+ framecount = framecount + 1 ;
110+ end
111+ % frame myds.numberOfFlankingFrames + 1 is center frame. One
112+ % frame before and one after is left out.
113+ startRightFrame = myds .numberOfFlankingFrames / 2 + 3 ;
114+ for rightFrame = startRightFrame : startRightFrame + myds .numberOfFlankingFrames / 2 - 1
115+ rawThisFrame = imread(myds .fileName ,myds .setFramesStartIndex + rightFrame );
116+ if myds .doAutoResize
117+ rawThisFrame = imresize(rawThisFrame ,myds .outputFrameSize );
118+ end
119+ thisFrame = single(rawThisFrame );
120+ flankingFrames(: ,: ,framecount ) = thisFrame ;
121+ framecount = framecount + 1 ;
122+ end
123+ data = {flankingFrames , refFrame };
124+ info = " set=" + num2str(myds .currentSet ) + " /centerframe=" + num2str(myds .currentFrameIndex );
125+ myds.currentSet = myds .currentSet + 1 ;
126+ myds.setsAvailable = myds .setsAvailable - 1 ;
127+ if myds .setsAvailable > 0
128+ myds.setFramesStartIndex = myds .allSetFrameStartIndices(myds .currentSet );
129+ myds.currentFrameIndex = myds .setFramesStartIndex + myds .numberOfFlankingFrames / 2 + 1 ;
130+ else
131+ myds.setFramesStartIndex = nan ;
132+ myds.currentFrameIndex = nan ;
133+ end
134+ end
135+
136+ function reset(myds )
137+ % Reset to the start of the data.
138+ myds.setsAvailable = myds .dsSetCount ;
139+ myds.currentSet = 1 ;
140+ myds.setFramesStartIndex = myds .allSetFrameStartIndices(myds .currentSet );
141+ myds.currentFrameIndex = myds .setFramesStartIndex + myds .numberOfFlankingFrames / 2 + 1 ;
142+ end %
143+
144+ function shmyds = shuffle(myds )
145+ % shmyds = shuffle(myds) shuffles the sets
146+ % Create a copy of datastore
147+ shmyds = copy(myds );
148+
149+ % Shuffle files and corresponding labels
150+ numObservations = shmyds .dsSetCount ;
151+ idx = randperm(numObservations );
152+ shmyds.allSetFrameStartIndices = myds .allSetFrameStartIndices(idx );
153+ reset(shmyds );
154+ end
155+ end
156+
157+ methods (Hidden = true )
158+ function frac = progress(myds )
159+ % Determine percentage of data read from datastore
160+ if hasdata(myds )
161+ frac = (myds .currentSet - 1 ) / myds .dsSetCount ;
162+ else
163+ frac = 1 ;
164+ end
165+ end
166+ end
167+
168+ methods (Access = protected )
169+ function subds = subsetByReadIndices(myds , indices )
170+ subds = copy(myds );
171+ subds.dsSetCount = numel(indices );
172+ subds.allSetFrameStartIndices = myds .allSetFrameStartIndices(indices );
173+ reset(subds );
174+ end
175+
176+ function n = maxpartitions(myds )
177+ n = myds .dsSetCount ;
178+ end
179+ end
180+
181+ end
0 commit comments