-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathColTapp.m
More file actions
15025 lines (13540 loc) · 692 KB
/
ColTapp.m
File metadata and controls
15025 lines (13540 loc) · 692 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 ColTapp_v1_2
%% initializing the interface
% suppress some warnings
%#ok<*AGROW>
%#ok<*HIST>
warning('off','MATLAB:hg:uicontrol:ValueMustBeInRange');
warning('off', 'images:imfindcircles:warnForSmallRadius');
% Check if GUI toolbox is installed
stp=Verifiyversion();
if stp
return
end
clear stp;
Fvar=struct(); %those are variables with fixed values in the software
Fvar.screen=get(0,'ScreenSize');
if Fvar.screen(3)/Fvar.screen(4)>2
Fvar.figscale=0.7;
else
Fvar.figscale=1;
end
%% New figure
hs.f = figure('units','norm','Position',[0.1 0.1 0.8*Fvar.figscale 0.8], 'KeyPressFcn', @WindowKeyPressFcn,...
'MenuBar', 'none', 'NumberTitle', 'off','HandleVisibility','on', ...
'Name', 'ColTapp v1.2-beta', 'ToolBar', 'none');
removeToolbarExplorationButtons(hs.f);
saveV='-v7';
Layoutcomponents;
mO=struct();mouseOvers;
%% Initialise variables
p=struct();%all the data
b=struct(); %contains variables that are used in batch mode
orig=struct();
pback=struct();
restore1=struct();
VorEdg=struct();
k=struct();
colonies=struct();%struct for tlag comparison
Kymo=struct();
initialize_gui;
%% Make figure visible after adding components
hs.fig.Visible = 'on';
hs.firstLoad=1;%for the load button. if the user open a new set, the complete layout is redone in order to ensure that the buttons are in
%the state they should be
%% initialising functions
function stp=Verifiyversion()
stp=0;
if verLessThan('Matlab','1.6')
disp('Matlab 2008 and earlier are not supported')
stp=1;
return
end
v=ver;%get list of all toolboxes
%first the check if the necesarry GUI toolbox is installed
if sum(strcmp({v.Name},'GUI Layout Toolbox'))==0
quest=questdlg('The necesarry "GUI Layout Toolbox" is missing. Do you want to open the website to download and install that toolbox now?',...
'Toolbox download', 'Yes','No','Yes');
stp=1;
switch quest
case 'Yes'
url='https://ch.mathworks.com/matlabcentral/fileexchange/47982-gui-layout-toolbox';
web(url,'-browser');
return
case 'No'
return
case ''
return
end
end
if sum(strcmp({v.Name},'Image Processing Toolbox'))==0
quest=questdlg('The necesarry "Image Processing Toolbox" is missing. To install it, you need to re-run the MATLAB installer and select the toolbox. Do you want to open the download-page?',...
'Toolbox download', 'Yes','No','Yes');
stp=1;
switch quest
case 'Yes'
url='https://www.mathworks.com/downloads/';
web(url,'-browser');
return
case 'No'
return
case ''
return
end
end
%for some things, we need the curve fitting toolbox, check that as well
if sum(strcmp({v.Name},'Curve Fitting Toolbox'))==0
quest=questdlg(['The "Curve Fitting Toolbox" is missing. It is needed for detecting the radius of transition and growth rate for timelapse analysis.',...
'You can continue without this toolbox but may run into problems. To install that toolbox, re-run the matlab installer and select the toolbox to install'],...
'Toolbox missing', 'Continue without','Cancel','Continue without');
switch quest
case 'Continue without'
pause(0.000001)
case 'Cancel'
stp=1;
return
case ''
stp=1;
return
end
end
Fvar.imTBmiss=0;
if ~license('checkout','Image_Toolbox')
quest=questdlg(['The "Image Toolbox" license is missing or the license is in use. It is needed for various image manipulation tools.',...
'You can continue without this toolbox but may run into errors Data analysis stuff should be possible. To install that toolbox, re-run the matlab installer and select the toolbox to install'],...
'Toolbox missing', 'Continue without','Cancel','Continue without');
switch quest
case 'Continue without'
pause(0.000001)
Fvar.imTBmiss=1;
case 'Cancel'
stp=1;
return
case ''
stp=1;
return
end
if ~license('checkout','map_toolbox')
quest=questdlg(['The "Mapping Toolbox" license is missing or the license is in use. It is needed only for the Voronoi calculation',...
'So you should install it if you plan to analyse colonies spatial distribution with the voronoi metric. Run the matlab installer and select the toolbox to install'],...
'Toolbox missing', 'Continue without','Cancel','Continue without');
switch quest
case 'Continue without'
pause(0.000001)
Fvar.imTBmiss=1;
case 'Cancel'
stp=1;
return
case ''
stp=1;
return
end
end
end
if verLessThan('Matlab','9.8')
saveV='-v7.3';
% files are saved without compression for speed. In Matlab
% version 2020, it is now possible to save matfiles with
% version 7 instead of 7.3, which increases speed. In
% older versions, -v7.3 will be used. We assume no version
% before 2008
end
clear v
end%check if necessary toolboxes are missing
function Layoutcomponents
%color values for the different button types
hs.btnCol.gray=[0.7 0.7 0.7];
% hs.btnCol.green1=[0 0.6 0];
% hs.btnCol.green2=[0 0.9 0];$
hs.btnCol.green1=[0.4490 0.8588 0.5922]; %main buttons
hs.btnCol.green2=[0.5071 0.9216 0.5078]; %load etc buttons
% Cutting main units
hs.main=uix.VBoxFlex('Parent', hs.f,'Padding',0, 'Spacing', 10); % whole box, separed into two units: 1) TopLayer and 2) BottomLayer
hs.TopLayer=uix.HBox('Parent',hs.main); %1
hs.BottomLayer=uix.HBoxFlex('Parent',hs.main,'Padding', 0, 'Spacing', 10); %#2, separated into two units: 3) LeftPan (all buttons etc on left side) and 4) FigPan (the picture box)
hs.LeftPan=uix.VBox('Parent', hs.BottomLayer,'Padding', 30); %#3
hs.FigPanBig=uix.HBox('Parent', hs.BottomLayer,'Padding', 30); %#4
% smaller cuts
hs.NavigatePics=uix.HBox('Parent', hs.LeftPan); %box for all
hs.AllParam=uix.HBox('Parent', hs.LeftPan);
% Add contents
%in Toplayer
hs.LoadSave=uix.VBox('Parent', hs.TopLayer);
hs.LoadClassify=uix.HBox('Parent', hs.LoadSave);
hs.LoadButton=uicontrol('Parent', hs.LoadClassify, 'String', 'Load/Open (O)', 'CallBack', @LoadButton_callback,'FontSize',15, 'BackgroundColor', hs.btnCol.green2);
hs.Batch=uicontrol('Parent', hs.LoadClassify, 'String', 'Batch analysis', 'CallBack', @MergeRun,'FontSize',15, 'BackgroundColor', hs.btnCol.green2);
hs.LoadSaveAS=uix.HBox('Parent', hs.LoadSave);
hs.SaveAsButton=uicontrol('Parent', hs.LoadSaveAS, 'String', 'Save file', 'CallBack', @SaveAsButton_callback,'FontSize',15, 'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.SaveAsCSV2=uicontrol('Parent', hs.LoadSaveAS, 'String', '.csv Export', 'CallBack', @Export2_callback,'FontSize',15, 'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Classify=uicontrol('Parent', hs.LoadSaveAS, 'String', 'Classify', 'CallBack', @Classify_callback,'FontSize',15, 'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.UserMessage=uix.VBox('Parent', hs.TopLayer);
hs.UserMess=uicontrol('Style', 'text','Parent',hs.UserMessage, 'String', 'starting','FontSize',12);
hs.UserMess2=uix.HBoxFlex('Parent',hs.UserMessage);
hs.UserMessDir=uicontrol('Style', 'text','Parent',hs.UserMess2, 'String', 'directory','FontSize',12);
hs.UserMessFrame=uicontrol('Style', 'text','Parent',hs.UserMess2, 'String', 'Frame number','FontSize',12);
hs.UserMessNumCol=uicontrol('Style', 'text','Parent',hs.UserMess2, 'String', 'number of colonies','FontSize',12);
hs.Progress1=axes('Parent', hs.UserMessage, 'Color', [0.8 0.9 0.8], 'Visible', 'off', 'Xcolor', 'none','Ycolor', 'none','Position', [0 0 1 1]);
hs.Progress2=axes('Parent', hs.UserMessage, 'Color', [0.8 0.9 0.8], 'Visible', 'off', 'Xcolor', 'none','Ycolor', 'none','Position', [0 0 1 1]);
% in left Pan
% in navigate
hs.setframebox=uix.HBox('Parent',hs.NavigatePics);
hs.setframeinput=uicontrol('Parent',hs.setframebox, 'Style','edit', 'KeyPressFcn', @set_frame_callback);
hs.SetFrameSlider=uicontrol('Parent',hs.setframebox, 'Style', 'slider', ...
'Callback', @set_frame_slider,'FontSize',15,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.setframebox.Widths=[-1, -3];
hs.Options=uicontrol('Parent',hs.NavigatePics, 'String', 'Options', 'Callback', @Options_Callback,'FontSize',15,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.NavigatePics.Widths=[-1 -1];
hs.VoidTop=uix.Empty('Parent', hs.AllParam);
hs.AllParam.Widths=-1;
%tabs
hs.Tabs=uitabgroup('Parent', hs.LeftPan); %%%%%%%%%%%%%%%%%
hs.AutoDetectTab = uitab('Parent', hs.Tabs, 'Title', 'Detect');
hs.SITab= uitab('Parent', hs.Tabs, 'Title', 'Main-EP');
hs.TimeLapseTab = uitab('Parent', hs.Tabs, 'Title', 'Main-TL');
hs.ResultsTab= uitab('Parent', hs.Tabs, 'Title', 'Visualize');
% in right Pan
hs.LeftButton=uicontrol('Parent', hs.FigPanBig, 'String', '<','Callback', @previous_Callback,'FontSize',15,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.FigPan=uipanel('Parent', hs.FigPanBig); %in order to be able to use subplot, creating a panel for the figure
hs.fig=axes('Parent', hs.FigPan, 'Color', [0.8 0.9 0.8], 'Visible', 'off', 'Xcolor', 'none','Ycolor', 'none','Position', [0 0 1 1]); %creating axes in it
hs.RightButton=uicontrol('Parent', hs.FigPanBig, 'String', '>', 'Callback', @next_Callback,'FontSize',15,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.FigPanBig.Widths=[20, -1, 20];
% in tabs
%Detect Tab
hs.DetectTabBox=uix.VBox('Parent', hs.AutoDetectTab,'Padding', 20);
hs.umRef=uicontrol('Parent',hs.DetectTabBox, 'String', 'Set spatial calibration factor','FontSize',14, 'Callback', @umRef_Callback, 'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Void0=uix.Empty('Parent', hs.DetectTabBox);
hs.aoistring=uicontrol('Style', 'text','Parent',hs.DetectTabBox, 'String', 'Area of interest:','FontSize',14);
hs.aoibox=uix.HBox('Parent',hs.DetectTabBox);
hs.aoiplate=uicontrol('Parent',hs.aoibox, 'String', 'Plate', 'Callback', @DelimitAreaPlate_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.aoipolygon=uicontrol('Parent',hs.aoibox, 'String', 'Polygon', 'Callback', @DelimitAreaPolygon_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.aoiwhole=uicontrol('Parent',hs.aoibox, 'String', 'None', 'Callback', @DelimitAreaWhole_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Void=uix.Empty('Parent', hs.DetectTabBox);
hs.enhanceImg=uix.HBox('Parent',hs.DetectTabBox);
hs.EnhanceImage=uicontrol('Style', 'checkbox','Parent',hs.enhanceImg, 'String', 'Autocontrast','FontSize',14, 'Callback', @EnhanceImage_Callback, 'Enable', 'inactive');
hs.EnhanceImage2=uicontrol('Style', 'checkbox','Parent',hs.enhanceImg, 'String', 'Improve lighting','FontSize',14, 'Callback', @EnhanceImage2_Callback, 'Enable', 'inactive');
hs.DefineRange=uicontrol('Parent',hs.DetectTabBox, 'String', 'Define radius range', 'Callback', @AutomaticallyDefineParameters_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.FindColonies=uicontrol('Parent',hs.DetectTabBox, 'String', 'Find Colonies', 'Callback', @FindColonies_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Void1=uix.Empty('Parent', hs.DetectTabBox);
hs.modColonyClick=uicontrol('Style', 'checkbox', 'Parent',hs.DetectTabBox,'String','Add/Remove with click', 'Callback', @EnablemodColonyClick_Callback,'FontSize',14, 'Enable', 'off');
hs.AddRmv=uix.HBox('Parent',hs.DetectTabBox);
hs.AddCol=uicontrol('Parent',hs.AddRmv, 'String', '(C) Add', 'Callback', @Addcol_callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.RmvCol=uicontrol('Parent',hs.AddRmv, 'String', '(R) Remove', 'Callback', @RemoveCol2_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Clean=uix.HBox('Parent',hs.DetectTabBox);
hs.CleanZone=uicontrol('Parent',hs.Clean, 'String', '(T) Clear in', 'Callback', @ClearZone_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.CleanOutZone=uicontrol('Parent',hs.Clean, 'String', '(Z) Clear out', 'Callback', @ClearOutZone_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.UndoButton=uicontrol('Parent',hs.DetectTabBox, 'String', '(backslash) Undo', 'Callback', @Undo_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Void2=uix.Empty('Parent', hs.DetectTabBox);
hs.Liststring=uicontrol('Style', 'text','Parent',hs.DetectTabBox, 'String', 'User lists','FontSize',14);
hs.UserListButtons=uix.HBox('Parent',hs.DetectTabBox);
hs.AddList=uicontrol('Parent',hs.UserListButtons, 'String', '+/-', 'Callback', @Add_to_List_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.ShowList=uicontrol('Parent',hs.UserListButtons, 'String', 'Show', 'Callback', @Show_UserList_Callback,'FontSize',15,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.ListSelect=uicontrol('Parent',hs.UserListButtons, 'Style', 'popup','String', {'none','new'},'FontSize',15,'BackgroundColor', 'white','Callback', @ChangeUserList_callBack );
hs.Highlight=uix.HBox('Parent',hs.DetectTabBox);
hs.HLButton=uicontrol('Parent',hs.Highlight, 'String', 'Highlight Colony', 'Callback', @HighlightCol_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.HLinput=uicontrol('Parent',hs.Highlight, 'Style','edit', 'KeyPressFcn', @HighlightCol_Callback);
hs.HLDelButton=uicontrol('Parent',hs.Highlight, 'String', 'X','FontWeight','bold','Callback', @DeleteHighlightCol_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Highlight.Widths=[-4, -1, -1];
hs.Void3=uix.Empty('Parent', hs.DetectTabBox);
hs.LocalCorrection1=uicontrol('Parent',hs.DetectTabBox, 'String', 'Calculate Voronoi areas','FontSize',14, 'Callback', @Voronoi_Callback,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
%EP Tab
hs.SITabBox= uix.VBox('Parent', hs.SITab,'Padding', 20) ;
hs.ovbx=uix.HBox('Parent',hs.SITabBox);
hs.overlay=uicontrol('Style', 'checkbox', 'Parent',hs.ovbx,'String','Overlay images', 'Callback', @OverlayCheckboxchange_Callback,'FontSize',14, 'Enable', 'off');
hs.overlayselect=uicontrol('Parent',hs.ovbx, 'Style', 'popup','String', {''},'FontSize',15,'BackgroundColor', 'white','Callback', @ChangeOverlayFolder_callBack );
hs.Void=uix.Empty('Parent', hs.SITabBox);
hs.AddNonGrowingButton=uicontrol('Parent',hs.SITabBox, 'String', '(N) Add 0-radius colony', 'Callback', @AddNonGrowing_callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Void1=uix.Empty('Parent', hs.SITabBox);
hs.multiEP=uicontrol('Parent',hs.SITabBox,'String','Link folders', 'Callback', @MultiEPLoad_Callback,'FontSize',14, 'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.showmultiEP=uicontrol('Parent',hs.SITabBox,'String','Display linked colonies', 'Callback', @MultiEPShow_Callback,'FontSize',14, 'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.registermultiEP=uicontrol('Parent',hs.SITabBox,'String','Register linked folders', 'Callback', @MultiEPRegister_Callback,'FontSize',14, 'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.GRmultiEP=uicontrol('Parent',hs.SITabBox,'String','Growth rate from linked folders', 'Callback', @MultiEPGR_Callback,'FontSize',14, 'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Void2=uix.Empty('Parent', hs.SITabBox);
hs.LoadRef2=uicontrol('Parent',hs.SITabBox, 'String', 'Define reference growth parameters', 'Callback', @GiveRef_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Void3=uix.Empty('Parent', hs.SITabBox);
hs.TappEst=uicontrol('Parent',hs.SITabBox, 'String', 'Apearance time estimation', 'Callback', @TappEst_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Void4=uix.Empty('Parent', hs.SITabBox);
hs.IntensityRadius=uicontrol('Parent',hs.SITabBox, 'String', 'Intensity along radius', 'Callback', @EP_intensityRadius_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
%Timelapse tab
hs.TimelapseTabBox=uix.VBox('Parent', hs.TimeLapseTab,'Padding', 20);
hs.registration=uicontrol('Style', 'checkbox', 'Parent',hs.TimelapseTabBox,'String','Registration', 'Callback', @RegistrationCheckboxchange_Callback,'FontSize',14, 'Enable', 'off');
hs.CenterCorrString=uicontrol('Style', 'text','Parent',hs.TimelapseTabBox, 'String', {'';'Center correction:'},'FontSize',14);
hs.CenterCorr=uix.HBox('Parent',hs.TimelapseTabBox);
hs.AutoCenter=uicontrol('Parent',hs.CenterCorr, 'String', 'Automatic', 'Callback', @AutoCenter_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.ManualCenter=uicontrol('Parent',hs.CenterCorr, 'String', 'Manual', 'Callback', @CenterCheck_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.closecenter=uix.HBox('Parent',hs.TimelapseTabBox);
hs.closecenterinput=uicontrol('Parent',hs.closecenter, 'Style','edit', 'KeyPressFcn', @closecenter_Callback, 'String', '5');
hs.closecenterbutton=uicontrol('Parent',hs.closecenter, 'String', 'Detect close centers', 'Callback', @closecenter_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.closecenter.Widths=[-1, -4];
hs.Void2=uix.Empty('Parent', hs.TimelapseTabBox);
hs.FindTimeCol=uicontrol('Parent',hs.TimelapseTabBox, 'String', 'Track radii over time', 'Callback', @FindTimeCol_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.findwrongkymo=uicontrol('Parent',hs.TimelapseTabBox, 'String', 'Find failed kymographs', 'Callback', @AutoKymoCheck_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.CorrectThresh=uicontrol('Parent',hs.TimelapseTabBox, 'String', 'Correct kymographs', 'Callback', @CorrectThresh_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Void3=uix.Empty('Parent', hs.TimelapseTabBox);
hs.LoadRef1=uicontrol('Parent',hs.TimelapseTabBox, 'String', 'Define reference growth parameters', 'Callback', @GiveRef_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Void4=uix.Empty('Parent', hs.TimelapseTabBox);
hs.TappCalc=uicontrol('Parent',hs.TimelapseTabBox, 'String', 'Apearance time determination', 'Callback', @TappCalc_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Void4=uix.Empty('Parent', hs.TimelapseTabBox);
hs.IntensityString=uicontrol('Style', 'text','Parent',hs.TimelapseTabBox, 'String', {'Intensity time-lapse'},'FontSize',14);
hs.Intensity=uix.HBox('Parent',hs.TimelapseTabBox);
hs.IntensityFull=uicontrol('Parent',hs.Intensity, 'String', 'Full image', 'Callback', @Intensity_TL_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.IntensityColony=uicontrol('Parent',hs.Intensity, 'String', 'Per Colony', 'Callback', @Colony_Intensity_TL_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
%Visualize tab
hs.ResultsTabBox=uix.VBox('Parent', hs.ResultsTab,'Padding', 20);
hs.SizeDist=uicontrol('Parent',hs.ResultsTabBox, 'String', 'Radius distribution', 'Callback', @SizeDist_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.plot=uicontrol('Parent',hs.ResultsTabBox, 'String', 'Radius vs Time', 'Callback', @plotTL_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.VoidSizeDat=uix.Empty('Parent',hs.ResultsTabBox);
hs.TappDist=uicontrol('Parent',hs.ResultsTabBox, 'String', 'Appearance time distribution', 'Callback', @TappDist_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.GRdist=uicontrol('Parent',hs.ResultsTabBox, 'String', 'Growth rate distribution','Callback', @GRdist_Callback,'FontSize',14,'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
hs.Void=uix.Empty('Parent', hs.ResultsTabBox);
% proportions of buttons
hs.TopLayer.Widths=[400, -3];
hs.main.Heights=[-1, -10];
hs.UserListButtons.Widths=[-0.75 -1.25 -2];
hs.BottomLayer.Widths=[-1, -2.2];
hs.LeftPan.Heights=[-1 ,20,-15];
hs.DetectTabBox.Heights=[-1 -0.2 -1 -1 -1 -1 -1 -1 -1 -1.5 -1 -1 -1 -1 -1 -1.5 -1 -1 -1];
hs.SITabBox.Heights=[-1 -1 -1 -2 -1 -1 -1 -1 -2 -1 -2 -1 -1 -1];
hs.TimelapseTabBox.Heights=[-1 -2 -1 -1 -1 -1 -1 -1 -2 -1 -2 -1 -2 -1 -1];
hs.ResultsTabBox.Heights=[-1 -1 -1 -1 -1 -12];
end %make GUI
function mouseOvers
% this is a list of text for mouse overs
mO.SFramCst='If this box is ticked, the exported CSV will not repeat the values which do not change with time.';
mO.WideLong='The radius data can be exported either as a column data or as a matrix, where columns represent time';
% add newline characters in the texts
numax=35;
for whSt=fieldnames(mO)'
str=[mO.(whSt{1}),' ']; %this is the string to cut
newstr='';
while length(str)>numax+4
spces=strfind(str,' ');
cut=spces(find(spces>21,1));
newstr= [newstr,str(1:cut-1),newline];
str=str(cut+1:end);
end
mO.(whSt{1})=[newstr,str(1:end)]; %replace the text
end
end %tooltips for mouse-over hoovering
function initialize_pstruc
% first listing all the ones that control operation of the GUI
% and associated functions. Below will come the generated data that
% can be exported for the user then more easily
% general handling
p.coltappV=1.2; %for tracking of version to enable backward compatability
p.nChannelDontAsk=false; %if this is set to true, it just sets always to single channel handling
p.modColonyClick=true; %left click to add and middle to remove if true
p.imgMethod=2; %indicate which method of RGB to grayscale transformation to use (1 to 16, 2 is R RGB channel)
p.ExportMode='px'; %exporting in micrometer or pixel? (auto changes to um if calibration is set)
p.csvdelimiter=1; %delimter to use for csv export (index of list {',',';', ' ', ' ', ':'};)
p.savebackups=true; %disable the backup save by setting to false (.mat files with date in name)
p.Rlin=130; %approximate radius at which a colony transition from exp to lin growth regarding radius
% visualisation and appearance
p.showColony=true;%show blue cirlces for colonies if =1
p.showNr=false;%=1 if number of colony should be shown on image
p.showGrayscale=false;%switch to greyscale if =1
p.showNrCol='k';%change the color of the number for the col nr display
p.showCircleScale=1; %scale radius of circle displayed
p.showROI=false; %show the area of analysis (either the circle and/or the polygon)
p.showList=false; %if 1 and p.UserLists is not empty, the program colors circles of list in a particular color
p.ShowVoronoiAreas=false; %display the Voronoi area text if true
p.ShowVoronoiEdges=false;%display the Voronoi edges if true
% describing experiment and plate
p.petriDishUmSize=89000; %micrometer dish size diameter
p.deltaTmin=10; %default deltaT between pictures
%for plots etc
p.plotUnit=1; %1=plot pxl vs frame, 2=smoothed um vs h, 3=log um vs h, 4=all
p.rawTitle='Raw radius in pixel vs time in frames'; %//TODO: combine the 3 titles into one list and choose based on p.plotUnit
p.smoothTitle='Radius in \mum vs time in hours';
p.logTitle='Log10 transformed radius in \mum vs time in hours';
p.histbins=15; %number of histogram bins
% colony detection
p.detectMinRadPx = 20; %min radius for colony detection in pxl
p.detectMaxRadPx = 65; %max rad for colony detection in pxl
p.BlackColony=0; % if =1 -> use imcomplement for colony detection
p.detectSensitivity = 0.96; %overall sensitivity for colony detection
p.detectMinFillCircle=0.8; %80% filling at least to be considered a colony
p.detectMinFillCircleOverlap=0.9; %90% filling at least when conflicting colonies
p.detectBinarizeSensitivity=0.01; %sensitivity for binarization for colony detection
p.detectRadStepsize=7; % imfindcircles iterated with a step of this radius size
p.detectRescaleBigCol=10; %this value works best for imfindcircles in colonies cases
p.detectMaxOverlap=0.9;%how much colony overlaping is allowed to be?
p.detectBinarizationMethod=1; %which option: 1) adaptive binarization 2) otsu 3) none
p.detectCircleMode=1; %=1 -> regionprops mode; =2 -> global mode
p.detectBoundingBoxScale=1.35; %for find colonies: scale crop area of bounding box to search within
p.detectBlurDiskSize=0.025; %initial bluring disk scaling based on bounding box size
p.detectMaxCircleGradient=8; %max circles to be found on gradient image. If more, use actual image
p.detectMinBorderDist=10; %min distance of a center from subimage border in pxl
p.detectForegroundBias=0.17; %subtract this from graythresh value for binary image of blob to bias towards more foreground
p.detectMinForground=0.70; %min area to be foreground
p.detectMaxOverlapCompare=0.9; %max overlap of two circles when comparing them
p.detectDiscardOvelapMinRadDiff=10; %goes together with p.detectDiscardOvelapMinCentDst. discard one of a pair of circles...
p.detectDiscardOvelapMinCentDst=20; %if both distance and radius difference are below these 2 thresholds
p.detectMaxOverlapTotal=0.95; %total area of a circle allowed to overlap with any circle
p.detectMaxOverlapStartThresh=0.8; %start value for iterative threshold increase for final overlap discarding
p.detectMinCenterDistFinal=2; %final check to exclude colonies closer than 2px
% radius tracking and calculation from kymograph
p.registrationFactor=100; % //TODO: check what this does
p.radCropAreaScaleFactor=1.15;%how big is the area around colony for analysis. Fixed parameter, set to 115% of col rad
p.radOverlapScale=1; %scales the radius of the focal colony to be smaller/bigger to be able to exclude close colonies as well
p.radzeroRadCutoff=6; %used in CalcRadKymo, arbitrary threshold (we chose 6 because= 1 hour) after which the radius is set to 0 (no colony has appeared yet)
p.radThetaResolution=128; % # of grid points for theta coordinate (change to needed binning)
p.radOverlapRemoveTheta=true; %=1 if the overlapping region between 2 colonies is removed for the interpolation in radial coordinates (TL function)
p.radUseEnhancedImg=0; %use enhanced images for timelapse if =1
p.radDefaultKymoMode=1; %default kymo mode: 1->global; 2->edge
p.radKymoBias=0.17; % the threshold shift for the radius curve to fit to the kymograpbh
p.TLimgenhance=0; %use enhanced images for timelapse if =1
% kymograph to radius variables. defaults. The values per colony are stored in the variables without def at the end
p.kymoScalePillboxdef=1/10000; %this times dim1*dim2 of kymo is used for pillbox filter
p.kymoWienerFilterSizedef=5; %size of the wiener2 filter kernel
p.kymoMaxIntensityCutoffdef=1; %every intensity above p.kymoMaxIntensityCutoff is set to 1
p.kymoCannyLowThreshdef=0.05; %lower canny edge detection threshold
p.kymoCannyHighThreshdef=0.19; %upper canny edge detection threshold
p.kymoNoiseFilterSizedef=0.05; %this times dim2 (time) of kymo is used to define the size (in area pixel) of noise objects
p.kymoVerticalLineRemovaldef=0.7; %this times dim2 is threshold for vertical line removal
p.kymoHorizontalLineRemovaldef=0.4; %this times dim1 is threshold for horizontal line removal
p.kymoCloseFilterLineLendef=1/30; %this times dim2 (time) of kymo is the size of line to use for closing
p.kymoCloseFilterLineAngledef=10; %the angle to be used for line closing
p.kymoCloseFilterDiskSizedef=3; %this times dim2 (time) of kymo is used for disk closing
p.kymoMaskScalingdef=1.7; %scale the binarization threshold for mask creation
p.kymoIterationsdef = 70; %number of iterations of active contouring
p.kymoInvertContourdef=0; %invert contour if 1
p.kymoInvertKymodef=0; %invert kymograph if 1
p.kymoDisablePrefilterdef=0; %disable all image prefiltering
% appearance time calculation
p.tappMode='um'; %can be either 'um' or 'px'. define if the Tapp is calculated via pxl or um thresholding
p.tappThreshUm=200; %for the Tapp calculation (if mode um)
p.tappThreshPx=10; %detection threshold in pxl (if mode px)
p.tappLengthLinFitFrame=50; %number of frames in which we fit the linear regression
p.tappRefMode='Mean'; %reference mode for growth rate extraction: 'Mean' or 'Quantile'
p.tappRefQuantile=0.5; %default quantile for reference growth rate extraction (only used if refMode is set to 'Quantile')
p.tappStayOverThresh=5; % Rad needs to stay above the threshold for that many frames otherwise discarded
% initialization of various empty variables used for progress tracking
% and data storage
% general control variables
p.operatingMode=[]; %define if loaded images are single set or timelapse
p.operatingModeStr=[]; %the text written on the classify button
p.definedOperatingMode=false;%change to true if p.operatingMode is set //TODO: remove and make sure it still works
p.imgFormat=[]; %indicates if the user loaded RGB or grayscale images
p.nChannel=[]; %for multi-channel (fluorescent) image handling
p.channelprocessing = 1; %which channel is currently processed
p.channelPrefix=''; %prefix to identify the imaging channel from image name
p.dir=char(java.lang.System.getProperty('user.home'));%directory. start at home
p.i=1;%which frame is displayed
p.overlayIMGstatus=false; %=1 if overlay is activated
p.dirOverlay=[]; %directory for the overlay images
p.iOverlay=1;%overlay frame.
p.iold=0; %old frame, used to check if the frame has changed and image needs update
p.iOverlayold=0; %old frame, used to check if the frame has changed and image needs update
p.l=[]; %will contain a list of files with filename
p.lOverlay=[]; %will contain a list of files with filename
p.filextension='.JPG'; %default file extension
p.fileCount=0; %number of files in the directory
p.smoothFrames=1;%smoothing factor for plots
p.TLrun=0;% set to 1 if TL is running to suppress display of various things
% ROI variables
p.roiType=[];%Analysis area: 0=All images,1=Automatically found plate,2=Delimited zone
p.roiPolygonImg=[];%For Delimited zone : polygon vertices
p.roiPlateRad=[];%%For plate:radius of ROI circle in pxl
p.roiPlateCenter=[];%For plate: center of ROI cirlce
% TL specific variables
p.focalframe=[];%where are the centers stored
p.KymoTrack=[]; %track if the kymograph is correctly elongated during the TL run
p.KymoChanged=false; %changes to true if something is changed in the kymograph and needs to be saved
p.overlapTL=[]; % contains for each colony the colonies that overlap with that one
p.overlapCoord=[]; %contains the 2 coordinates of the two overlapping circles. for each colony, for each overlapping colony
p.overlapCoordSmall=[]; %same, but transformed for the small image used in the TL run
p.mat2grayRef=[]; %contains the reference values for mat2gray
p.kymomode=[]; %kymomode for each colony: 1: global threshold, 2: edge detection
p.newR=[]; % //TODO: check what this does
% EP-specific variables
p.multiEPdirs=[]; %contains folder names of each linked folder
p.timepoints=[]; %timepoints for each linked folder
p.thistimepoint=[];%timepoint of active folder
% registration variables
p.REGstatus=false;%=1 if TL registration is activated
p.registrationTranslation=[]; %Registration translation shift (x,y)
p.colonyCenRadUnregistered=[]; %backup the unregistered colony centers and radii
p.coloniesColors=[]; % //TODO: check what this
% these are the variables that are measured and should be easily exported
% general measurement variables
p.umConversion=[]; %conversion rate from pxl to um, stored per frame
% radius, center, growth rate, appearance time variables
p.colonyCenRad=[];%contains the radii and centers derived from find colony function
p.centers=[];%all centers detected //TODO: remove this and use p.colonyCenRad (lol, Copilot knew it)
p.radii=[];%all radii detected //TODO: remove this and use p.colonyCenRad (lol, Copilot knew it)
p.RadMean=[];%radius over time
p.RadMeanUm=[];%meanRad in micrometers //TODO: remove this and use p.RadMean * p.umConversion
p.GR=[]; %growth rates per colony
p.TappErrors=[]; %contains the colonies for which an error occured
p.R0=[]; %x=0 intercept of the linear regression
p.Tapp=[]; %appearance time per colony
p.estTapp=[];%estimated Tapp for EP
p.TappCalibrated=[]; %subtracted the reference appearance time
p.VoronoiAreas=[]; %contains the calculated voronoi area
% user list variables
p.UserLists=struct; %list of user defined colonies (marked on image and in export)
p.UserLists.listOptions={'none','-1 near col','-2 failed kymo','new'};
p.colList=[]; %which colony to analyse
p.timeList=[];%which frames to analyse
p.timeVect=[]; %range of time
% reference condition variables
p.TappRef=[]; %reference appearance time
p.GRRef=[];%reference GR
p.GRRefAll=[];%all GR of reference folder
p.TappRefAll=[];%all Tapp for reference folder
p.quantileV=0.5; %default quantile for reference
% comparison variables
p.currentName='MainComparison';%default name for comparison plotting
p.compLoaded=false;%set to true if a loaded comparison is a TL
p.compFileName=[];%name for loaded comparison file storage
p.comparisonRadUm=[];%for single images: load the rad distribution of exponential comparison at timepoint
p.Tlag=[]; % will store the Tlag for the opened image set
end
function initialize_gui
loadConfig
% batch run
b.runningBatch=0; %this value becomes 1 when program is running in batch mode
b.batchFile=[]; %this will contain a list of folders to analyse (all files therein)
Kymo.Kymo=[]; %contains the kymograph
Fvar.lastUndo=nan(7,1); %this will contain values to track user actions to undo actions
varUndos={'colonyCenRad', 'centers','radii','UserLists'}; %variables to allow undo
% parameters that are not saved in the p file
for iv=1:7
for jv=1:length(varUndos)
Fvar.([varUndos{jv},num2str(iv)])= [];%all radii for undo
end
end
varUndos='RadMean'; %also to allow undo
for iv=1:7
Fvar.([varUndos,num2str(iv)])= [];%all radii for undo
end
Fvar.grayoptions={'RGB, R channel', 'RGB, G channel', 'RGB, B channel', 'Lab, L channel', 'Lab, a channel','Lab, b channel',...
'YIQ, Y channel', 'YIQ, I channel', 'YIQ, Q channel', 'CIE, X channel','CIE, Y channel', 'CIE, Z channel','YCbCr, Y channel',...
'YCbCr, Cb channel','YCbCr, Cr channel', 'rgb2gray'};
Fvar.TLrunning=true;% set to 1 if TL is running to suppress display of various things
Fvar.csvdelimiters={'comma','semicolon', 'tab', 'space', 'colon'};
Fvar.csvdelimiterssymbol={',',';', ' ', ' ', ':'};
Fvar.imgextsion={'jpg','jpeg', 'png', 'bmp', 'tiff', 'tif','JPG','JPEG','PNG','BMP','TIFF','TIF'};
Fvar.showImage=true; %set false to improve speed of the timelapse as the image is not shown for each step
Fvar.imTBmiss=0; %this is a flag to indicate if the image processing toolbox is missing. //TODO: remove this for python
Fvar.rgb=[];%contains image
Fvar.imgray=[]; %the grayscale transformed image
Fvar.im=[]; %and that the imshow plot
Fvar.background=[]; %temporarily storage of background for cleaner images
Fvar.imgenhanced=false; %set to 1 if image enhancement process was applied
Fvar.imgenhanced2=false; %set to 1 if image enhancement process was applied
Fvar.clickcall=0;
Fvar.clickdisable=0;
Fvar.numNonUserList=2;
Fvar.circlehandleR=[];
Fvar.circlehandleG=[];
Fvar.circlehandleB=[];
Fvar.numberhandle=[];
Fvar.roihandle=[];
Fvar.voroThandle=[];
Fvar.voroAhandle=[];
VorEdg.VoronoiEdges=[];
ProgressInitialize %call to this function initialize all progress ckeck variables
hs.UserMess.String='started'; %user message to be printed
end %initiate all parameters
%% load data, initialize missing variables, classify folders
function loadConfig
% Define the filename
fullPath = mfilename('fullpath');
[curd, ~, ~] = fileparts(fullPath);
configFile = 'coltapp_config.json';
% Check if the config file exists
if isfile(fullfile(curd, configFile))
% Load and decode the JSON file
fid = fopen(configFile, 'r');
raw = fread(fid, inf);
str = char(raw');
fclose(fid);
p = jsondecode(str);
else
% If the file doesn't exist, create it with default settings
initialize_pstruc;
saveConfig(p, fullfile(curd, configFile)); % Save the default parameters to a new JSON file
end
end
function saveConfig(p, configFile)
% Encode the struct as JSON
jsonStr = jsonencode(p, 'PrettyPrint', true); % 'PrettyPrint' for human-readable JSON
% Write to the file
fid = fopen(configFile, 'w');
if fid == -1
error('Cannot create JSON file.');
end
fwrite(fid, jsonStr, 'char');
fclose(fid);
end
function LoadButton_callback (~, ~)
%This function executes when "Load/Open" button is pressed. It asks
%user to find a directory and calls the function chngDir
dirTemp=p.dir;%store the current dir for default display
%ask user for dir
dirUser=uigetdir(dirTemp,'please select the directory with the timelapse images');
if dirUser==0; return; end %user cancelled
if writeperm(dirUser); errordlg('ColTapp needs Writting permisssion to operate. This permission was denied.'); return; end
% b=struct();
if ~exist('b', 'var')
b=struct();
b.batchmode=0;
end
if ~isstruct(b)
b=struct();
b.batchmode=0;
end
if ~isfield(b, 'batchmode')
b.batchmode=0;
end
if hs.firstLoad==1%this will be one for the first startup of the GUI. Do nothing than change that value
hs.firstLoad=0;
errorTrck=0;
else% we reset the GUI
% Add the UI components
clf
Layoutcomponents;
clear p; clear colonies;
% Initialise variables
p=struct();%all the data
colonies=struct();%struct for tlag comparison
orig=struct();
VorEdg=struct();
initialize_gui;
errorTrck=1;
end
hs.UserMess.String='Please wait, data is loading...';customdrawnow
p.dir=dirUser; %update p.dir
p.dirS=p.dir; %the file saving is initialy done on the same folder
erlod=chngDir; %actual loading function
if length(p.l)<1
waitfor(errordlg('There are no images in this folder. Loading is cancelled'));
if ~errorTrck
clf
Layoutcomponents;
clear p; clear colonies;
% Initialise variables
hs.UserMessNumCol.String= ''; customdrawnow
delete(hs.fig);
hs.fig=axes('Parent', hs.FigPan, 'Color', [0.9 0.9 0.8], 'Position', [0 0 1 1]); %creating axes
p.dir=dirUser; %update p.dir
p.dirS=p.dir; %the file saving is initialy done on the same folder
hs.UserMess.String='Loading failed';customdrawnow
return
else
p.dir=dirTemp;
p.dirS=p.dir;
chngDir
refresh(1);
ProgressUpdate;
hs.UserMess.String='Loading failed';customdrawnow
return
end
elseif ~erlod
p.dir=dirTemp;
p.dirS=p.dir;
chngDir
refresh(1);
ProgressUpdate;
hs.UserMess.String='Loading failed';customdrawnow
return
else
hs.UserMessNumCol.String= ''; customdrawnow
hs.UserMess.String='Setting up GUI...';customdrawnow
delete(hs.fig);
hs.fig=axes('Parent', hs.FigPan, 'Color', [0.9 0.9 0.8], 'Position', [0 0 1 1]); %creating axes
end
backwardCompatTest()
p.dir=dirUser; %reallocate the p.dir to the input dir. chngDir loads the whole p struct and if the folder was moved or
%renamed, it would load the old invalid p.dir which gives
%errors..
p.dirS=p.dir; %same for that
p.del=strfind(p.dirS,filesep); %looking for delimiter in folder name
%check if the type of the image set is already defined
if isempty(p.operatingMode) || ((sum(strcmp(p.operatingMode,'single'), 'omitnan')==0)&&(sum(strcmp(p.operatingMode,'TL'), 'omitnan')==0))
p.definedOperatingMode=0;
end
if ~p.definedOperatingMode
p.focalframe=length(p.l);%otherwise, running into errors if no focalframe is defined...
Classify_callback;%classify the images as timelapse or single image sets
if p.nChannel > 1
p.channelindex = nan(length(p.l),1);
for chi = 1:p.nChannel
chpat = [p.channelPrefix, num2str(chi)];
p.channelindex(arrayfun(@(x) contains(x.name, chpat), p.l)) = chi;
end
for chi = 2:p.nChannel
fieldName = sprintf('l%d', chi); % Construct field name dynamically
p.(fieldName) = p.l(p.channelindex == chi);
end
p.l = p.l(p.channelindex == 1);
p.focalframe = length(p.l);
end
if strcmp(p.operatingMode,'TL'); p.i=length(p.l); end %if in TL mode, directly jump to the last frame if classify
chngList(2,0,zeros(0,1));
chngList(1,0,zeros(0,1));
else
if isempty(p.nChannel)
p.nChannel = 1;
end
end
if length(p.dir)>30%display dir name in GUI
hs.UserMessDir.String = ['...' p.dir(end-30:end)];
else
hs.UserMessDir.String = p.dir;
end
txtMsg= ''; text(0.25, 0.5, txtMsg,'Fontsize', 14);customdrawnow
axes(hs.Progress1); fill([0 0 0 0],[0,1,1,0],[0.5 0.7 0.8]), set(hs.Progress1,'Xlim',[0 1],'Ylim',[0 1], 'Xcolor','none','Ycolor','none');customdrawnow
if p.i<1 || p.i>length(p.l)
p.i=1;
end
set(hs.Classify, 'String', p.operatingModeStr);
p.compFileName=[];%reset that to reset the load comparison button action mode
p.progress.open=1; %files are open
hs.overlay.Value=p.overlayIMGstatus;%reset the overlay toggle
if isempty(p.roiType) || length(p.roiType)~=length(p.l)%check if the AA has the correct length, if not initialize with 0 -> whole image
p.roiType=zeros(length(p.l),1);
end
if ~isempty(p.RadMean) %Basically only occurs if switching from one mode to the other
if size(p.RadMean,1)~=size(p.colonyCenRad{p.focalframe},1)
p.RadMean(size(p.colonyCenRad{p.focalframe},1)+1:end,:)=[];
end
end
if isempty(p.umConversion) %|| length(p.umConversion)~=length(p.l) %initialize p.umConversion if not done yet
p.umConversion=nan(length(p.l),1);
end
Fvar.showImage=1;p.i=length(p.l);Fvar.TLrunning=0;%ensure that the image is shown correctly
p.disableSave=0;
% refresh(0)
if ~isfield(p,'vAA'); p.showROI=1; end %initialize p.showROI
if p.showGrayscale || ~strcmp(p.imgFormat, 'rgb') %define color of the colony Nr.
p.showNrCol='g';
else
p.showNrCol='k';
end
p.KymoChanged=0;
ProgressUpdate;
%and update the left/right arrows state if needed
if p.overlayIMGstatus && isempty(p.dirOverlay)
RemoveMultiEP_Callback
end
if strcmp(p.operatingMode,'TL') && ~isempty(p.focalframe)
p.i=p.focalframe;
elseif strcmp(p.operatingMode,'TL') && isempty(p.focalframe)
p.i=length(p.l);
elseif ~isempty(p.i)
p.i=1;
end
p.ShowCol=1;
hs.fig=axes('Parent', hs.FigPan, 'Color', [0.9 0.9 0.8], 'Position', [0 0 1 1]); %creating axes
refresh(0);
if length(p.l)==1 %let them disappear if only 1 image loaded
set(hs.RightButton, 'BackgroundColor', hs.btnCol.gray, 'Visible', 'off');
set(hs.LeftButton, 'BackgroundColor', hs.btnCol.gray, 'Visible', 'off');
else
if p.i==1
set(hs.LeftButton, 'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
set(hs.RightButton, 'BackgroundColor', hs.btnCol.green2, 'Enable', 'on');
elseif p.i==length(p.l)
set(hs.RightButton, 'BackgroundColor', hs.btnCol.gray, 'Enable', 'inactive');
set(hs.LeftButton, 'BackgroundColor', hs.btnCol.green2, 'Enable', 'on');
else
set(hs.RightButton, 'BackgroundColor', hs.btnCol.green2, 'Enable', 'on');
set(hs.LeftButton, 'BackgroundColor', hs.btnCol.green2, 'Enable', 'on');
end
end
set(hs.modColonyClick, 'Value', p.modColonyClick);
if ~strcmp(p.operatingMode, 'TL')
set(hs.GRdist, 'String', 'Growth rate vs Time');
else
set(hs.GRdist, 'String', 'Growth rate distribution');
end
Fvar.clickdisable= ~p.modColonyClick;
if p.showList
set (hs.ShowList, 'String', 'Hide')
else
set (hs.ShowList, 'String', 'Show')
end
if ~p.disableSave
saveall(p.dirS);
end
hs.UserMess.String='Loading finished';customdrawnow
end%load folder
function E=writeperm(dirUser)
[fid,errmsg] = fopen([dirUser,filesep,'testColTapp.m'],'a');
if ~isempty(errmsg)
E=1;
else
E=0;
fclose(fid);
delete([dirUser,filesep,'testColTapp.m']);
end
end
function errorloading=chngDir
%will return 1 if loading was correct. Loads a list of files in a
%directory. Looks if previous mat files were already save, and
%loads them accordingly.
dirTemp=p.dir;%store the indicated dir to ensure no errors occur if the folder was moved or renamed since last opening
%getting file list
errorloading=1;
clear l;
reduceKymo=0;
if ~exist('b','var')
b=struct();
end
if ~isstruct(b)
b=struct();
end
if ~isfield(b,'runningBatch')
b.runningBatch=0;
end
if b.runningBatch
p=struct();
VorEdg=struct();
p.dir=dirTemp;
p.dirS=dirTemp;
p.l=[];
end
for filextension=Fvar.imgextsion
clear keep;
l=dir([p.dir, filesep, '*',filextension{1}]); %lists all files with filextension
if ~isempty(l) %found files
for h=1:size(l,1)
keep(h)=(l(h).name(1)~='.'); %removes all directories and parents (files which start with '.')
end
if sum(keep)>length(p.l)
p.l=l(keep);
end
end
end
if ~isempty(dir([p.dir, filesep, '*','all.mat','*'])) %found a file countaing "all"
l=p.l; %saving the list variable
files=dir([p.dir, filesep, '*','all.mat','*']);
a=nan(length(files),1);
for ii=1:length(files)%copy the date of each file to a vector to be able to run max on it
try
a(ii)=datenum(files(ii).date);
catch %somehow datenum does not work
if ~isempty(strfind(files(ii).date,'Mrz'))
files(ii).date=strrep(files(ii).date,'Mrz','Mar');
try
a(ii)=datenum(files(ii).date);
catch
if b.batchmode==0
errordlg(['The date of the file ', files(ii).name, ' in the folder you try to load cannot be read. Please delete that and try again.']);
hs.UserMess.String='Error. Loading cancelled.'; customdrawnow
return ;
else
b.summary(b.TheOneRunning)=0;
return
end
end
end
end
end
[~, ind]=max(a);%find the most recent file and take that to load
try
fileAll=load([p.dir,filesep,files(ind).name]); %this contains, counts, i, Rad, RadMean, dir, minRad, maxRad and sensitivity
catch %somehow files can become corrupt, notify the user which one and cancel loading
if b.batchmode==0
errordlg(['The file called: ', files(ind).name, ' in the folder you try to load is corrupt. Please delete that and try again.']);
hs.UserMess.String='Error. Loading cancelled.'; customdrawnow
return
else
b.summary(b.TheOneRunning)=0;
return
end
end
if isfield(fileAll,'p')
if ~isfield(fileAll.p, 'coltappV')
p.coltappV = 1;
end
for fn=fieldnames(fileAll.p)'
p.(fn{1}) = fileAll.p.(fn{1});
%disp(fn{1}) %will display all loaded fieldnames
end
else %files created by previous versions of CTA
for fn=fieldnames(fileAll)'
p.(fn{1}) = fileAll.(fn{1});
% disp(fn{1})
end
end
if length(p.l)==length(l)
p.l=l;
reduceKymo=0;
else %reset things if the length of images is different than before
if ~b.runningBatch
if length(l)<length(p.l)
quest=(['There are fewer image files (', num2str(length(l)), ') in this folder than in the previous'...
' analysis file (', num2str(length(p.l)), ' images) in this folder. Do you want to reset all analysis '...
'or use the found number of ', num2str(length(l)), ' images?']);
done=0;
while ~done
answer = questdlg(quest,'Error','Reset',['use ', num2str(length(l)), ' images'],'Cancel loading','Reset');
switch answer
case 'Reset'
p.l=l;
p.colonyCenRad=cell(length(p.l),2); %creating empty cell with the nb of pictures
p.RadMean=[];
p.RadMeanUm=[];
errorloading=1;
reduceKymo=-1;
p.KymoChanged=1;