-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathBaxterAlgorithms.m
More file actions
1524 lines (1351 loc) · 63.6 KB
/
BaxterAlgorithms.m
File metadata and controls
1524 lines (1351 loc) · 63.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
function BaxterAlgorithms()
% Starts the Baxter Algorithms, a software package for cell tracking.
%
% The Baxter Algorithms is a software package which can do segmentation and
% tracking of live cells in transmission microscopy and fluorescence
% microscopy. In fluorescence microscopy, the program can process both 2D
% images and 3D z-stacks, and it can handle both cytoplasmic and nuclear
% fluorescence. In transmission microscopy, the program can only handle 2D
% images. The program can also be used to analyze single images of muscle
% histology imaged using fluorescence microscopy. There are graphical user
% interfaces for segmentation of cells, manual correction of tracking
% results, analysis of tracks, and many other things.
%
% The program assumes that image sequences are saved as folders containing
% images for the individual time points. The file extensions tif, tiff,
% png, jpg, and jpeg are supported. For 3D data, the images associated with
% one z-stack can be either individual images for the different z-planes a
% tif-stack. A folder containing one or multiple image sequence folders is
% called an experiment (folder). The program can have one or more
% experiments open and the names of the image sequences in these
% experiments are displayed in a listbox to the right in the main figure.
% The user selects image sequences from this list and chooses functions to
% run with these sequences as inputs, in the menus of the main figure. When
% sequences are selected, thumbnails of the first images of the sequences
% are shown in the left side of the main figure.
%
% For a more detailed description of the software package, the reader is
% referred to the user guide in pdf-format, which can be opened by pressing
% the 'Help->User guide' menu option.
%
% See also:
% SegmentationPlayer, ProcessDirectory, ManualCorrectionPlayer
if ~isdeployed
% Add necessary paths.
subdirs = textscan(genpath(fileparts(mfilename('fullpath'))), '%s', 'delimiter', pathsep);
addpath(subdirs{1}{:});
else
% Set the java look-and-feel depending on the platform. Otherwise a
% cross-platform look-and-feel where the outlines of buttons are
% missing and where all menu options have a square in front of them.
if ispc()
javax.swing.UIManager.setLookAndFeel(...
'com.sun.java.swing.plaf.windows.WindowsLookAndFeel')
elseif ismac()
javax.swing.UIManager.setLookAndFeel(...
'com.apple.laf.AquaLookAndFeel')
elseif isunix()
% True also for Macs, but we have already dealt with Macs.
javax.swing.UIManager.setLookAndFeel(...
'com.jgoodies.looks.plastic.Plastic3DLookAndFeel')
end
end
% Add necessary java paths if they are not already added.
if ~isdeployed && ~CheckJavaPaths()
% Print out missing java paths.
fprintf('You need to add the folders:\n')
missingPaths = setdiff(RequiredJavaPaths(), javaclasspath('-all'));
for i = 1:length(missingPaths)
fprintf('%s\n', missingPaths{i})
end
fprintf('to\n%s\n', fullfile(prefdir, 'javaclasspath.txt'))
% Create a dialog where the user can decide how to add the paths.
choise = questdlg(...
['The Baxter Algorithms needs to add java paths to MATLAB. '...
'It is recommended that you let the program add the paths to ',...
'javaclasspath.txt. You can also let the program add the paths ',...
'temporarily (using javaaddpath), or add the paths yourself. '...
'The required paths have been printed to the terminal. '...
'You will need to restart the program after this dialog closes.'],...
'Add java paths',...
'Add paths javaclasspath.txt', 'Add paths temporarily', 'Cancel',...
'Add paths javaclasspath.txt');
switch choise
case 'Add paths javaclasspath.txt'
AddJavaPaths('Permanent', true)
case 'Add paths temporarily'
AddJavaPaths('Permanent', false)
end
% The program needs to be restarted, because the command javaaddpaths
% clears all the callbacks of the GUI (even before they are created).
% javaaddpath is called even when the paths are added to
% javaclasspath.txt, because MATLAB needs to be restarted before those
% changes take effect. For some reason, the callbacks don't come back
% if the program is restarted from within the code. The use has to
% restart the program manually.
return
end
% Upper limit on the length of the lists of previously opened experiments.
MAX_PREVEX = 10;
exPathsUni = {}; % The paths of the the open experiments.
seqDirs = {}; % Names of all image sequences.
seqPaths = {}; % Full paths to image sequences.
imDatas = {}; % Cached ImageData objects for seqPaths.
vers = {}; % Tracking versions of the image sequences.
% Cell array where every cell contains a
% cell array of strings with the tracking
% versions of the corresponding sequence.
conds = {}; % Culturing conditions of the images sequences.
selAlts = {'all', 'unknown'}; % Alternatives for "selPopupMenu".
selTypes = {'all', 'unknown'}; % Specifies the type of every alternative
% in "selAlts" ('all', 'unknown', 'ver' or 'cond').
mainFigure = figure(...
'MenuBar', 'none',...
'NumberTitle', 'off',...
'Name', 'Baxter Algorithms',...
'Units', 'normalized',...
'Position', [0.1 0.1 0.8 0.8],...
'CloseRequestFcn', @Close);
% Queue where the user can put computations for later execution.
queue = Queue();
% Paths of experiments that have been opened previously. These experiments
% will appear in lists next to File->Open Experiment and File->Add
% Experiment.
prevExPaths = LoadVariable('BaxterAlgorithms_prevExPaths');
prevExPaths = prevExPaths(1:min(MAX_PREVEX, length(prevExPaths)));
% Page number. If more than 20 images are selected, the images are
% arranged on multiple pages. "pageNum" stores the index of the page
% currently shown.
pageNum = 1;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MENU OPTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Data used to create the menus is put in the cell array "menus". The first
% column contains the labels on the menus, the second column contains
% levels specifying how advanced the settings are ('basic', 'advanced', or
% 'development'), and the third column contains either callbacks or cell
% arrays with sub-menus.
file = {...
'Open experiment', 'basic', @(aObj, aEvent)disp([])
'Add experiment', 'advanced', @(aObj, aEvent)disp([])
'Remove experiment', 'advanced', @(aObj, aEvent)RemoveExperiment()
'Concatenate experiments', 'advanced', @(aObj, aEvent)ConcatenateExperimentsGUI()
'Copy sequences', 'advanced', @(aObj, aEvent)CopySeq()
'Move sequences', 'advanced', @(aObj, aEvent)MoveSeq()
'Delete sequences', 'advanced', @(aObj, aEvent)DeleteSeq()
'Export tracks to CTC format', 'advanced', @(aObj, aEvent)disp([])
'Close all', 'advanced', @(aObj, aEvent)CloseAll()
'Invert selection', 'advanced', @(aObj, aEvent)InvertSelection()
'Random selection', 'advanced', @(aObj, aEvent)RandomSelection()
'Convert merged images', 'advanced', @(aObj, aEvent)ConvertMergedImagesGUI()};
settings = {...
'Settings', 'basic', @(aObj, aEvent)Settings()
'Save Settings', 'advanced', @(aObj, aEvent)CallbackSel(false, @SaveSettingsGUI)
'Load Settings', 'basic', @(aObj, aEvent)CallbackSel(false, @LoadSettingsImageGUI, 'CloseFunction', @Update)
'Load Settings (browse for file)', 'advanced', @(aObj, aEvent)CallbackSel(false, @LoadSettingsGUI, 'CloseFunction', @Update)
'Set segmentation parameters', 'basic', @(aObj, aEvent)CreatePlayer(false, 'Segmentation')
'Optimize segmentation parameters', 'advanced', @(aObj, aEvent)CallbackSel(false, @SegmentationOptimization)
'Train classifiers', 'advanced', @(aObj, aEvent)CallbackSel(true, @TrainClassifierGUI, queue)
'Set fluorescence display', 'basic', @(aObj, aEvent)CreatePlayer(false, 'Fluorescence')};
automated = {...
'Stabilize', 'basic', @(aObj, aEvent)CallbackSel(false, @StabilizationGUI, queue, 'ExitFunction', @SwitchExQuestion)
'Cut microwells', 'advanced', @(aObj, aEvent)CallbackSel(false, @CuttingGUI, queue, 'ExitFunction', @SwitchExQuestion)
'Track', 'basic', @(aObj, aEvent)CallbackSel(false, @TrackingGUI, queue, 'ExitFunction', @UpdateSelPopupMenu)
'Replace segmentation', 'development', @(aObj, aEvent)CallbackSel(true, @ReplaceSegmentation, queue, 'ExitFunction', @UpdateSelPopupMenu)};
manual = {...
'Play', 'basic', @(aObj, aEvent)CreatePlayer(false, 'Z')
'Track Correction', 'basic', @(aObj, aEvent)CreatePlayer(false, 'Correction')
'Fiber Correction', 'basic', @(aObj, aEvent)CreatePlayer(false, 'FiberCorrection')};
analysis = {...
'Cell Analysis GUI', 'basic', @(aObj, aEvent)CreatePlayer(true, 'Analysis')
'Population Analysis GUI', 'basic', @(aObj, aEvent)CallbackSel(true, @PopulationAnalysisGUI)
'Scatter Plot Analysis GUI', 'advanced', @(aObj, aEvent)CallbackSel(true, @ScatterPlotGUI)
'Fiber analysis GUI', 'basic', @(aObj, aEvent)CallbackSel(false, @FiberAnalysisGUI)
'Central nuclei GUI', 'development', @(aObj, aEvent)CallbackSel(false, @CentralNucleiGUI)
'Myotube fusion analysis GUI', 'advanced', @(aObj, aEvent)CallbackSel(false, @FusionIndexGUI)
'Plot GUI', 'advanced', @(aObj, aEvent)CallbackSel(false, @PlotGUI)
'Save plots', 'advanced', @(aObj, aEvent)SavePlotsGUI()
'Statistics', 'advanced', @(aObj, aEvent)CallbackSel(true, @ExportStatistics)
'TRA Tracking performance', 'advanced', @(aObj, aEvent)CallbackSel(true, @PerformanceTRAGUI, queue)
'SEG Segmentation performance', 'advanced', @(aObj, aEvent)CallbackSel(true, @PerformanceSEGGUI, queue)};
levels = {...
'basic', 'basic', @LevelCallback
'advanced', 'basic', @LevelCallback
'development', 'basic', @LevelCallback};
helpmenu = {...
'User guide', 'basic', @OpenUserGuide
'Information dialogs', 'advanced', @(aObj, aEvent)disp([])
'About Baxter Algorithms', 'basic', @(aObj, aEvent)AboutBaxterAlgorithms()};
% Cell array with all menus of the figure.
menus = {...
' File ', 'basic', file
' Settings ', 'basic', settings
' Automated ', 'basic', automated
' Manual ', 'basic', manual
' Analysis ', 'basic', analysis
' Level ', 'basic', levels
' Help ', 'basic', helpmenu};
menus = CreateMenus(mainFigure, menus);
% Get handles of menu objects that need to be accessed later.
basicMenu = GetMenu(mainFigure, ' Level ', 'basic');
advancedMenu = GetMenu(mainFigure, ' Level ', 'advanced');
developmentMenu = GetMenu(mainFigure, ' Level ', 'development');
openMenu = GetMenu(mainFigure, ' File ', 'Open experiment');
addMenu = GetMenu(mainFigure, ' File ', 'Add experiment');
ctcMenu = GetMenu(mainFigure, ' File ', 'Export tracks to CTC format');
infoMenu = GetMenu(mainFigure, ' Help ', 'Information dialogs');
% Sub-menu for opening new or previously opened experiments.
uimenu(openMenu,...
'Label', 'Browse...',...
'Callback', @(aObj, aEvent)OpenOrAddExperimentGUI('open'));
for p = 1:length(prevExPaths)
uimenu(openMenu,...
'Label', prevExPaths{p},...
'Callback', @(aObj, aEvent)OpenOrAddExperiment(prevExPaths{p}, 'open'));
end
% Sub-menu for adding new or previously opened experiments.
uimenu(addMenu,...
'Label', 'Browse...',...
'Callback', @(aObj, aEvent)OpenOrAddExperimentGUI('add'));
for p = 1:length(prevExPaths)
uimenu(addMenu,...
'Label', prevExPaths{p},...
'Callback', @(aObj, aEvent)OpenOrAddExperiment(prevExPaths{p}, 'add'));
end
uimenu(ctcMenu,...
'Label', 'RES tracks',...
'Callback', @(aObj, aEvent)CallbackSel(true, @CTCExportGUI, 'RES'))
uimenu(ctcMenu,...
'Label', 'SEG ground truth',...
'Callback', @(aObj, aEvent)CallbackSel(true, @CTCExportGUI, 'SEG'))
uimenu(ctcMenu,...
'Label', 'TRA ground truth',...
'Callback', @(aObj, aEvent)CallbackSel(true, @CTCExportGUI, 'TRA'))
uimenu(infoMenu,...
'Label', 'Display all',...
'Callback', @DisplayAllInfo_Callback);
uimenu(infoMenu,...
'Label', 'Display none',...
'Callback', @DisplayNoInfo_Callback);
% Set the menus level. If the GUI has been opened before, the level
% selected when the GUI was last closed is used. Otherwise, 'basic' is
% used.
level = LoadVariable('BaxterAlgorithms_level');
if isempty(level)
level = 'basic';
end
switch level
case 'basic'
set(basicMenu, 'Checked', 'on')
case 'advanced'
set(advancedMenu, 'Checked', 'on')
case 'development'
set(developmentMenu, 'Checked', 'on')
otherwise
error('Unknown level %s.\n', level)
end
SetVisibleMenus(menus, level)
% Order of control objects. Each cell contains the controls on one row.
order = [...
{{'exLabel'}}
{{'exListBox'}}
{{'seqLabel'}}
{{'seqListBox'}}
{{'selLabel'}}
{{'selPopupMenu'}}
{{'previousButton' 'nextButton'}}];
% Relative positions in the format
% [left margin, top margin, width, height].
positions = struct(...
'exLabel', [0.8, 0.01, 0.19, 0.02],...
'exListBox', [0.8, 0.005, 0.19, 0.25],...
'seqLabel', [0.8, 0.01, 0.19, 0.02],...
'seqListBox', [0.8, 0.005, 0.19, 0.54],...
'selLabel', [0.8, 0.01, 0.19, 0.02],...
'selPopupMenu', [0.8, 0.005, 0.19, 0.02],...
'previousButton', [0.8, 0.02, 0.09, 0.05],...
'nextButton', [0.01, 0.02, 0.09, 0.05]);
% Convert the relative positions to absolute positions.
top = 1;
for i = 1:length(order)
field1 = order{i}{1};
pos1 = positions.(field1);
deltaH = pos1(2) + pos1(4);
left = 0;
for j = 1:length(order{i})
field2 = order{i}{j};
pos2 = positions.(field2);
p1.(field2) = left + pos2(1);
p2.(field2) = top - deltaH;
left = left + pos2(1) + pos2(3);
end
top = top - deltaH;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% UI-CONTROLS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
exLabel = uicontrol('Style', 'text',...
'BackgroundColor', get(mainFigure, 'color'),...
'HorizontalAlignment', 'left',...
'String', 'Experiments',...
'Units', 'normalized',...
'Tooltip', 'Paths of experiments that the images sequences belong to'); %#ok<NASGU>
exListBox = uicontrol('Style', 'listbox',...
'Min', 0,...
'Max', 2,...
'Value', [],...
'String', exPathsUni,...
'Units', 'normalized',...
'Tooltip', 'Paths of experiments that the images sequences belong to',...
'Callback', @ExListBox_Callback);
seqLabel = uicontrol('Style', 'text',...
'BackgroundColor', get(mainFigure, 'color'),...
'HorizontalAlignment', 'left',...
'String', sprintf('Image sequences %d / %d', 0, length(seqDirs)),...
'Units', 'normalized',...
'Tooltip', 'Select image sequences to process');
seqListBox = uicontrol('Style', 'listbox',...
'Min', 0,...
'Max', 2,...
'Value', [],...
'String', seqDirs,...
'Units', 'normalized',...
'Tooltip', 'Select image sequences to process',...
'Callback', @SeqListBox_Callback);
selLabel = uicontrol('Style', 'text',...
'BackgroundColor', get(mainFigure, 'color'),...
'HorizontalAlignment', 'left',...
'String', 'Select',...
'Units', 'normalized',...
'Tooltip', 'Selects groups of image sequences'); %#ok<NASGU>
selPopupMenu = uicontrol(...
'BackgroundColor', 'white',...
'HorizontalAlignment', 'left',...
'Units', 'Normalized',...
'Style', 'popupmenu',...
'String', selAlts,...
'Value', find(strcmp(selTypes, 'unknown')),...
'Tooltip', 'Selects groups of image sequences',...
'Callback', @SelPopupMenu_Callback);
previousButton = uicontrol('Style', 'pushbutton',...
'Enable', 'off',...
'String', 'Previous 20',...
'Units', 'normalized',...
'Tooltip', 'Show thumbnails for the previous 20 image sequences',...
'Callback', @PreviousButton_Callback);
nextButton = uicontrol('Style', 'pushbutton',...
'Enable', 'off',...
'String', 'Next 20',...
'Units', 'normalized',...
'Tooltip', 'Show thumbnails for the following 20 image sequences',...
'Callback', @NextButton_Callback);
% Position the controls.
for i = 1:length(order)
for j = 1:length(order{i})
eval(['set(' order{i}{j} ,...
',''Position'', ['...
num2str([p1.(order{i}{j}),...
p2.(order{i}{j}),...
positions.(order{i}{j})(3),...
positions.(order{i}{j})(4)]) '])'])
end
end
if ispc
set(seqListBox, 'BackgroundColor', 'white');
set(exListBox, 'BackgroundColor', 'white');
else
% Don't know why I added this. Probably to make the GUI look nicer on
% unix. The GUI might also look nicer on Mac.
set(seqListBox,...
'BackgroundColor', get(0,'defaultUicontrolBackgroundColor'));
set(exListBox,...
'BackgroundColor', get(0,'defaultUicontrolBackgroundColor'));
end
% Create empty axes objects to show selected images in, and empty labels to
% display image sequence names.
smallPictures = cell(1,20);
smallLabels = cell(1,20);
for i=0:3
for j=1:5
smallPictures{i*5+j} = axes(...
'Units', 'normalized',...
'Position', [0.01+i*0.2 1-j*0.2 0.18 0.18]);
smallLabels{i*5+j} = uicontrol(...
'Style', 'text',...
'BackgroundColor', get(mainFigure, 'color'),...
'Units', 'normalized',...
'Position', [0.01+i*0.2, 0.98-(j-1)*0.2, 0.18, 0.02]);
axis off
end
end
% Load the experiments that were open when the program was last closed.
tmp = LoadVariable('BaxterAlgorithms_exPathsUni');
if isempty(tmp)
% Replace [] by {} to make cellfun work.
tmp = {};
end
% Remove experiments that no longer exist.
tmp = tmp(cellfun(@(x)exist(x,'dir') > 0, tmp));
OpenOrAddExperiment(tmp, 'open')
% Select the first image when a new experiment is opened.
if ~isempty(seqDirs)
set(seqListBox, 'Value', 1)
end
% Display thumbnails of selected image sequences.
SeqListBox_Callback(seqListBox, [])
InfoDialog('InfoBaxterAlgorithms', 'Main GUI',...
['First open a dataset by pressing '...
'File->Open Experiment. Then select the image sequences that you '...
'want to process in the listbox to the right. The available '...
'processing functions and user interfaces can be found under the '...
'different menus. The menu alternatives are separated into the 3 '...
'levels ''basic'', ''advanced'', and ''development'', and you can '...
'select which alternatives are shown using the Level menu. '...
'Information about the images is specified under '...
'Settings->Settings, the image sequences are played under '...
'Manual->Play. Segmentation settings are specified under '...
'Settings->Set Segmentation Parameters, tracking settings are '...
'specified under Settings->Settings. Tracking results are produced '...
'under Automated->Track. The tracking results can be viewed and '...
'corrected under Manual->Track Correction, and the results can '...
'be analyzed using the options on the Analysis menu. A pdf '...
'manual is available under Help->User Guide.'])
function AddExPath(aExPaths)
% Adds an experiment to the set of open experiments.
%
% Inputs:
% aExPaths - Cell array with paths of experiment folders to be
% added.
% Update experiment list box.
exPathsUni = [exPathsUni; aExPaths];
set(exListBox, 'String', exPathsUni)
for ii = 1:length(aExPaths)
% Update sequence list box.
tmpSeqDirs = GetUseSeq(aExPaths{ii});
seqDirs = [seqDirs; tmpSeqDirs]; %#ok<AGROW>
if ~isempty(seqDirs)
seqPaths = [seqPaths; strcat(aExPaths{ii}, filesep, tmpSeqDirs)]; %#ok<AGROW>
imDatas = [imDatas; cell(size(tmpSeqDirs))]; %#ok<AGROW>
end
end
set(seqListBox, 'String', seqDirs)
UpdateSelPopupMenu()
AddPrevExPath(aExPaths)
SaveVariable('BaxterAlgorithms_exPathsUni', exPathsUni)
end
function AddPrevExPath(aExPaths)
% Adds a path to the menus of previously opened experiments.
%
% The menus of previously opened experiments let the user open or
% add one of the experiments by clicking the menu instead of
% browsing for the experiment again.
%
% Inputs:
% aExPaths - Cell array with experiment paths to be added to the
% menus.
for ii = 1:length(aExPaths)
% Remove the path from the list if it is already on it.
if any(strcmpi(prevExPaths, aExPaths{ii}))
delete(GetMenu(mainFigure, ' File ', 'Open experiment', aExPaths{ii}))
delete(GetMenu(mainFigure, ' File ', 'Add experiment', aExPaths{ii}))
prevExPaths(strcmpi(prevExPaths, aExPaths{ii})) = [];
end
% Remove the oldest experiments for the list if necessary.
for prevIndex = length(prevExPaths) : -1 : MAX_PREVEX
delete(GetMenu(mainFigure, ' File ', 'Open experiment', prevExPaths{prevIndex}))
delete(GetMenu(mainFigure, ' File ', 'Add experiment', prevExPaths{prevIndex}))
end
prevExPaths = prevExPaths(1:min(MAX_PREVEX-1, length(prevExPaths)));
% Add new menu options.
uimenu(openMenu,...
'Position', 2,...
'Label', aExPaths{ii},...
'Callback', @(aObj, aEvent)OpenOrAddExperiment(aExPaths{ii}, 'open'));
uimenu(addMenu,...
'Position', 2,...
'Label', aExPaths{ii},...
'Callback', @(aObj, aEvent)OpenOrAddExperiment(aExPaths{ii}, 'add'));
prevExPaths = [aExPaths(ii); prevExPaths]; %#ok<AGROW>
end
% Save "prevExPaths" for future sessions.
SaveVariable('BaxterAlgorithms_prevExPaths', prevExPaths)
end
function CallbackSel(aCheckTracked, aFunction, varargin)
% Applies a sequence of functions to the selected image sequences.
%
% Inputs:
% aCheckTracked - Boolean variable specifying if the function
% requires a tracked sequence to play. If it does,
% selecting only sequences that have not been
% tracked will produce an error dialog.
% aFunction - Function handle for the function to be executed. The
% function should take a cell array of image sequence
% paths as the first input argument.
% varargin - Additional input arguments to aFunction.
index = get(seqListBox, 'Value');
% No sequences selected.
if isempty(index)
errordlg('You have not selected any image sequences to process.')
return
end
% No sequences tracked.
if aCheckTracked && isempty([vers{:}])
errordlg(['None of the selected image sequences have '...
'been tracked. There could exist a stabilized or '...
'cut version of the experiment which has been '...
'tracked.'], 'No tracking available')
return
end
% If the users have not selected all sequences, a dialog is opened
% to give them the option to select all.
numSel = length(index);
numSeq = length(get(seqListBox, 'String'));
if numSel < numSeq
if ~SelectAllDlg(numSel, numSeq)
return
end
end
index = get(seqListBox, 'Value');
% Call the functions.
feval(aFunction, seqPaths(index), varargin{:})
end
function Close( ~, ~)
% Callback executed before the main figure is closed.
%
% The function saves the selected menu level for next time that the
% GUI is opened.
% Saves the selected menu level so that it can be recalled the next
% time the GUI is opened.
SaveVariable('BaxterAlgorithms_level', GetLevel())
delete(mainFigure)
end
function CopySeq()
% Copies the selected image sequences to another experiment.
index = get(seqListBox, 'Value');
% No sequences selected.
if isempty(index)
errordlg('You have not selected any image sequences to copy.')
return
end
% Select an experiment to copy sequences to.
tmpExPath = UiGetMultipleDirs(...
'Title', 'Select an experiment folder',...
'Path', FileParts2(seqPaths{1}),...
'MultiSelect', false);
if ~isempty(tmpExPath)
if exist(fullfile(tmpExPath, 'SettingsLinks.csv'), 'file')
errordlg(['It is not possible to copy sequences to '...
'experiments with linked settings.'])
return
end
seqNames = FileEnd(seqPaths(index));
for seq = 1:length(seqNames)
if exist(fullfile(tmpExPath, seqNames{seq}), 'file')
errordlg(['The selected experiment already contains '...
'an image sequence named ' seqNames{seq} '.'])
return
end
end
CopySequences(seqPaths(index), tmpExPath);
end
end
function CloseAll()
% Closes all figures except the main figure.
figs = get(0, 'Children'); % all open figures
for ii = 1:length(figs)
if(figs(ii) ~= mainFigure) % Don't delete the main figure.
delete(figs(ii))
end
end
end
function CreatePlayer(aCheckTracked, aPlayerType)
% Opens one of the player GUIs that play image sequences.
%
% The different GUIs let the user visualize, edit and analyze image
% sequences and tracking results in different ways.
%
% Inputs:
% aCheckTracked - Boolean variable specifying if the player
% requires a tracked sequence to play. If it does,
% selecting only sequences that have not been
% tracked will produce an error dialog.
% aPlayerType - String defining which player to open. The different
% alternatives are:
% 'Z' - Plays 2D image sequences or sequences of 3D
% z-stacks.
% 'Fluorescence' - Lets the user specify colors and
% dynamic ranges for different
% (fluorescent) channels.
% 'Segmentation' - Lets the user specify segmentation
% settings for the image sequences
% and look at the corresponding
% segmentations.
% 'Correction' - Lets the user visualize and correct
% tracks and outlines of cells.
% 'Features' - Lets the user visualize the values of
% different features of segmented blobs.
% The outputs of classifiers operating
% on the features can also be
% visualized.
%
% See also:
% CallbackSel
index = get(seqListBox, 'Value');
% No sequences selected.
if isempty(index)
errordlg('You have not selected any image sequences to process.')
return
end
% No sequences tracked.
if aCheckTracked && isempty([vers{:}])
errordlg(['None of the selected image sequences have '...
'been tracked. There could exist a stabilized or '...
'cut version of the experiment which has been '...
'tracked.'], 'No tracking available')
return
end
switch aPlayerType
case 'Z'
ZPlayer(seqPaths(index));
InfoDialog('InfoZPlayer', 'Settings',...
['You can zoom in by clicking and dragging a '...
'rectangle, zoom out again by right-clicking, and '...
'pan by holding down the space bar or pressing '...
'''m''. If you are viewing slices of 3D data, you '...
'can switch to another slice by shift-clicking, or '...
'clicking with the center mouse button on the '...
'desired slice in one of the other 3D views.'])
case 'Fluorescence'
SetFluorescencePlayer(seqPaths(index),...
'CloseFunction', @Update);
InfoDialog('InfoSetFluorescencePlayer',...
'Set fluorescence display',...
{['You can select colors for the different '...
'channels using the dropdown menus, and specify '...
'the range of displayed intensity values by '...
'clicking and dragging in the gradients or the '...
'histograms. Before you can use this GUI, you need '...
'to specify the settings channelNames and '...
'channelTags.']
''
['You can zoom in by clicking and dragging a '...
'rectangle, zoom out again by right-clicking, and '...
'pan by holding down the space bar or pressing '...
'''m''. If you are viewing slices of 3D data, you '...
'can switch to another slice by shift-clicking, or '...
'clicking with the center mouse button on the '...
'desired slice in one of the other 3D views.']})
case 'Segmentation'
SegmentationPlayer(seqPaths(index));
InfoDialog('InfoSegmentationPlayer',...
'Set segmentation parameters',...
{['The segmentation settings are separated into '...
'the 3 levels ''basic'', ''advanced'', and '...
'''development''. You can select which levels to '...
'show using the Level menu. The basic level has '...
'settings which have to be set properly in order '...
'to get a good segmentation. The advanced settings '...
'are settings which can improve the segmentation '...
'or which are needed for special types of data. '...
'The development settings are not needed by the '...
'typical user and may not be fully tested.']
''
['If you are changing multiple settings at once, '...
'you can save time by unchecking the Update '...
'button while you make the changes. If you want '...
'to see the segmentations that unsaved settings '...
'produce on other image sequences, you need to '...
'uncheck the Revert to saved button before you '...
'switch to the other sequences.']
''
['You can zoom in by clicking and dragging a '...
'rectangle, zoom out again by right-clicking, and '...
'pan by holding down the space bar or pressing '...
'''m''. If you are viewing slices of 3D data, you '...
'can switch to another slice by shift-clicking, or '...
'clicking with the center mouse button on the '...
'desired slice in one of the other 3D views.']})
case 'Correction'
ManualCorrectionPlayer(seqPaths(index));
InfoDialog('InfoManualCorrectionPlayer',...
'Track Correction',...
{['In this player, you can select tracking results '...
'to view and correct in the dropdown menu in the '...
'upper right corner, or you can generate a manual '...
'tracking result from scratch using the correction '...
'tools. Automatic tracking results are created '...
'under Automated->Track, in the main window.']
''
['The zoom functions which are available in other '...
'players are enabled by pressing the zoom tool. '...
'You can zoom in by clicking and dragging a '...
'rectangle, zoom out again by right-clicking, and '...
'pan by holding down the space bar or pressing '...
'''m''. If you are viewing slices of 3D data, you '...
'can switch to another slice by shift-clicking, or '...
'clicking with the center mouse button on the '...
'desired slice in one of the other 3D views. '...
'Clicking in the lineage tree will take you to the '...
'clicked time point.']})
case 'FiberCorrection'
ManualFiberCorrectionPlayer(seqPaths(index));
InfoDialog('InfoFiberCorrectionPlayer',...
'Fiber Correction',...
{['In this player, you can select fiber '...
'segmentation results to view and correct in the '...
'dropdown menu in the upper right corner, or you '...
'can generate a manual segmentation result from '...
'scratch using the correction tools. Automatic '...
'segmentation results are created under '...
'Automated->Track, in the main window.']
''
['The zoom functions which are available in other '...
'players are enabled by pressing the zoom tool. '...
'You can zoom in by clicking and dragging a '...
'rectangle, zoom out again by right-clicking, and '...
'pan by holding down the space bar or pressing '...
'''m''. If you are viewing slices of 3D data, you '...
'can switch to another slice by shift-clicking, or '...
'clicking with the center mouse button on the '...
'desired slice in one of the other 3D views.']})
case 'Analysis'
CellAnalysisPlayer(seqPaths(index));
end
end
function DisplayAllInfo_Callback(~,~)
% Makes all GUIs display all information dialogs.
%
% This function will undo all decisions to not show information
% dialogs again.
%
% See also:
% DisplayNoInfo_Callback
SaveVariable('InfoBaxterAlgorithms', true)
SaveVariable('InfoSettingsGUI', true)
SaveVariable('InfoConvertMergedImagesGUI', true)
SaveVariable('InfoMergeExperimentsGUI', true)
SaveVariable('InfoZPlayer', true)
SaveVariable('InfoSetFluorescencePlayer', true)
SaveVariable('InfoSegmentationPlayer', true)
SaveVariable('InfoCreateTemplate', true)
SaveVariable('InfoManualCorrectionPlayer', true)
SaveVariable('InfoFiberCorrectionPlayer', true)
SaveVariable('InfoDeleteButton', true)
SaveVariable('InfoEditSegmentsButton', true)
SaveVariable('InfoSegmentationOptimization', true)
end
function DisplayNoInfo_Callback(~,~)
% Makes all GUIs not display optional information dialogs.
%
% After this function has been executed, information dialogs that
% the user can choose not to show again will not be shown at all.
%
% See also:
% DisplayAllInfo_Callback
SaveVariable('InfoBaxterAlgorithms', false)
SaveVariable('InfoSettingsGUI', false)
SaveVariable('InfoConvertMergedImagesGUI', false)
SaveVariable('InfoMergeExperimentsGUI', false)
SaveVariable('InfoZPlayer', false)
SaveVariable('InfoSetFluorescencePlayer', false)
SaveVariable('InfoSegmentationPlayer', false)
SaveVariable('InfoCreateTemplate', false)
SaveVariable('InfoManualCorrectionPlayer', false)
SaveVariable('InfoFiberCorrectionPlayer', false)
SaveVariable('InfoDeleteButton', false)
SaveVariable('InfoEditSegmentsButton', false)
SaveVariable('InfoSegmentationOptimization', false)
end
function DeleteSeq()
% Deletes the selected image sequences.
index = get(seqListBox, 'Value');
% No sequences selected.
if isempty(index)
errordlg('You have not selected any image sequences to delete.')
return
end
% Ask if the user really wants to delete the sequences.
choise = questdlg(...
sprintf(['Are you sure that you want to delete the %d '...
'selected sequences?'], length(index)),...
'Delete sequences?', 'Yes', 'No', 'No');
if strcmpi(choise, 'Yes')
DeleteSequences(seqPaths(index));
end
% Removes the deleted sequences from the sequence list box.
Update()
end
function ExListBox_Callback(aObj, ~)
% Selects image sequences when the user selects experiments.
%
% This callback will selects all images sequences that belong to
% the experiments that are selected in the experiment listbox.
%
% See also:
% SeqListBox_Callback, SelPopupMenu_Callback
% Get the selected experiments.
selection = get(aObj, 'Value');
exPathsSel = exPathsUni(selection);
% The experiments that the sequences belong to.
seqExPaths = FileParts2(seqPaths);
% Create a binary array which indicate which sequences are in the
% selected experiments.
seqSelection = false(size(seqPaths));
for ex = 1:length(exPathsSel)
seqSelection = seqSelection | strcmpi(seqExPaths, exPathsSel{ex});
end
% Select the sequences in the sequence listbox and execute the
% callback of the listbox so that all necessary updates are
% performed.
set(seqListBox, 'value', find(seqSelection))
SeqListBox_Callback(seqListBox, 'ExListBox_Callback')
end
function oLevel = GetLevel()
% Returns the selected menu level.
%
% The menu level is either 'basic', 'advanced', or 'development'
% and determines which other menus should be shown to the user.
if strcmp(get(basicMenu, 'Checked'), 'on')
oLevel = 'basic';
elseif strcmp(get(advancedMenu, 'Checked'), 'on')
oLevel = 'advanced';
elseif strcmp(get(developmentMenu, 'Checked'), 'on')
oLevel = 'development';
end
end
function InvertSelection()
% Inverts the selection in the image sequence listbox.
%
% The unmarked sequences become marked and the marked sequence
% become unmarked. This can be useful if a user wants to open
% and correct sequences that have not yet been manually corrected.
sel = get(seqListBox, 'Value');
newSel = setdiff(1:length(seqPaths),sel);
set(seqListBox, 'Value', newSel)
SeqListBox_Callback(seqListBox, [])
end
function RandomSelection()
% Lets the user select a random subset of the selected sequences.
%
% The function opens a dialog box where the user enters an integer,
% and then the program selects that number of random image
% sequences, from the set of already selected sequences.
sel = get(seqListBox, 'Value');
% No sequences selected.
if length(sel) < 2
errordlg(['You have to select at least two image sequences '...
'to draw a subset from.'])
return
end
% Ask the user how many sequences to select.
answer = inputdlg({'Number of sequences to select'},...
'Random selection', [1 40], {'1'});
if isempty(answer)
% The user closed the dialog.
return
end
num = str2double(answer);
if isnan(num) || num < 1 || num ~= round(num)
errordlg('You have to input a nonnegative integer.')
return
end
if num >= length(sel)
errordlg(sprintf(['Currently there are %d image sequences '...
'to pick from, so you have to input a number which is '...
'smaller than that.'], length(sel)))
return
end
% Select a random subset of the image sequences.
newSel = sel(randperm(length(sel)));
newSel = newSel(1:num);
set(seqListBox, 'Value', newSel)
SeqListBox_Callback(seqListBox, [])
end
function LevelCallback(aObj, ~)
% Callback executed when one of the level menus is clicked.
%
% The callback deselects all other level menus and then updates the
% set of other menus displayed.
otherMenus = setdiff(...
[basicMenu,...
advancedMenu,...
developmentMenu], aObj);
set(aObj, 'Checked', 'on')
set(otherMenus(1), 'Checked', 'off')
set(otherMenus(2), 'Checked', 'off')
SetVisibleMenus(menus, GetLevel())
end
function MoveSeq()
% Moves the selected image sequences to another experiment.
index = get(seqListBox, 'Value');
% No sequences selected.
if isempty(index)
errordlg('You have not selected any image sequences to move.')
return
end
% Select an experiment to move sequences to.
tmpExPath = UiGetMultipleDirs(...
'Title', 'Select an experiment folder',...
'Path', FileParts2(seqPaths{1}),...
'MultiSelect', false);
if ~isempty(tmpExPath)
if exist(fullfile(tmpExPath, 'SettingsLinks.csv'), 'file')
errordlg(['It is not possible to move sequences to '...
'experiments with linked settings.'])
return
end
seqNames = FileEnd(seqPaths(index));
for seq = 1:length(seqNames)
if exist(fullfile(tmpExPath, seqNames{seq}), 'file')
errordlg(['The selected experiment already contains '...