-
Notifications
You must be signed in to change notification settings - Fork 5
/
cat_conf_stools.m
2345 lines (2107 loc) · 92.5 KB
/
cat_conf_stools.m
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 stools = cat_conf_stools(expert)
%_______________________________________________________________________
% wrapper for calling CAT surface utilities
% ______________________________________________________________________
%
% Christian Gaser, Robert Dahnke
% Structural Brain Mapping Group (https://neuro-jena.github.io)
% Departments of Neurology and Psychiatry
% Jena University Hospital
% ______________________________________________________________________
% $Id$
%#ok<*NOCOM>
% try to estimate number of processor cores
try
numcores = cat_get_defaults('extopts.nproc');
% because of poor memory management use only half of the cores for windows
if ispc
numcores = round(numcores/2);
end
numcores = max(numcores,1);
catch
numcores = 0;
end
% force running in the foreground if only one processor was found or for compiled version
% or for Octave
if numcores == 1 || isdeployed || strcmpi(spm_check_version,'octave'), numcores = 0; end
if ~exist('expert','var')
expert = 0; % switch to de/activate further GUI options
end
% parallelize
% ____________________________________________________________________
nproc = cfg_entry;
nproc.tag = 'nproc';
nproc.name = 'Split job into separate processes';
nproc.strtype = 'w';
nproc.val = {numcores};
nproc.num = [1 1];
nproc.help = {
'In order to use multi-threading the CAT12 segmentation job with multiple subjects can be split into separate processes that run in the background. You can even close Matlab, which will not affect the processes that will run in the background without GUI. If you do not want to run processes in the background then set this value to 0.'
''
'Please note that no additional modules in the batch can be run except CAT12 segmentation. Any dependencies will be broken for subsequent modules.'
};
% do not process, if result already exists
% ____________________________________________________________________
lazy = cfg_menu;
lazy.tag = 'lazy';
lazy.name = 'Lazy processing';
lazy.labels = {'Yes','No'};
lazy.values = {1,0};
lazy.val = {0};
lazy.help = {
'Do not process data if the result already exists. '
};
% merge hemispheres
% ____________________________________________________________________
merge_hemi = cfg_menu;
merge_hemi.tag = 'merge_hemi';
merge_hemi.name = 'Merge hemispheres';
merge_hemi.labels = {
'No - save resampled data for each hemisphere',...
'Yes - merge hemispheres'
};
merge_hemi.values = {0,1};
merge_hemi.val = {1};
merge_hemi.hidden = expert<1;
merge_hemi.help = {
'Meshes for left and right hemisphere can be merged to one single mesh. This simplifies the analysis because only one analysis has to be made for both hemispheres and this is the recommended approach.'
'However, this also means that data size is doubled for one single analysis which might be too memory demanding for studies with several hundreds or even more files. If your model cannot be estimated due to memory issues you should not merge the resampled data.'
};
% default mesh
% ____________________________________________________________________
mesh32k = cfg_menu;
mesh32k.hidden = expert<1;
mesh32k.tag = 'mesh32k';
mesh32k.name = 'Resample Size';
mesh32k.labels = {
'32k mesh (HCP)',...
'164k mesh (Freesurfer)'
};
mesh32k.values = {1,0};
mesh32k.val = {1};
mesh32k.help = {
'Resampling can be done either to a higher resolution 164k mesh that is compatible to Freesurfer data or to a lower resolution 32k mesh (average vertex spacing of ~2 mm) that is compatible to the Human Connectome Project (HCP).'
'The HCP mesh has the advantage of being processed and handled much faster and with less memory demands. Another advantage is that left and right hemispheres are aligned to optionally allow a direct comparison between hemispheres.'
};
%% import GUIs
% ------------------------------------------------------------------------
[surfresamp,surfresamp_fs] = cat_surf_resamp_GUI(expert,nproc,merge_hemi,mesh32k,lazy);
[vol2surf,vol2tempsurf] = cat_surf_vol2surf_GUI(expert,merge_hemi,mesh32k);
[surfcalc,surfcalcsub] = cat_surf_calc_GUI(expert);
renderresults = cat_surf_results_GUI(expert);
surfextract = cat_surf_parameters_GUI(expert,nproc,lazy);
flipsides = cat_surf_flipsides_GUI(expert);
surf2roi = cat_surf_surf2roi_GUI(expert,nproc);
roi2surf = cat_roi_roi2surf_GUI(expert);
surfstat = cat_surf_stat_GUI;
surfcon = cat_surf_spm_cfg_con;
surfres = cat_surf_spm_cfg_results;
vx2surf = cat_surf_vx2surf_GUI(expert,nproc,lazy);
%% Toolset
% ---------------------------------------------------------------------
stools = cfg_choice;
stools.name = 'Surface Tools';
stools.tag = 'stools';
stools.values = { ...
surfextract, ... .cat.stools
surfresamp, ... .cat.stools
surfresamp_fs,... .cat.stools
vol2surf, ... .cat.stools
vol2tempsurf, ... .cat.stools
vx2surf, ... .cat.stools (expert)
surfcalc, ... .cat.stools
surfcalcsub, ... .cat.stools
surf2roi, ... .cat.rtools?
roi2surf, ... .cat.rtools? (developer)
flipsides, ... .cat.stools (developer)
surfstat ...
surfcon ...
surfres ...
renderresults, ... .cat.disp/plot/write?
};
%==========================================================================
% subfunctions of batch GUIs
%==========================================================================
function res = cat_surf_spm_cfg_results
% Surface based version of the SPM result function (tiny changes).
res = spm_cfg_results;
res.prog = @cat_spm_results_ui;
res.name = ['Surface ' res.name];
function con = cat_surf_spm_cfg_con
% Surface based version of the SPM contrast tools that only change the
% dependency settings updated here in vout_stats.
con = spm_cfg_con;
con.name = ['Surface ' con.name];
con.vout = @vout_stats; % gifti rather than nifti output
function dep = vout_stats(varargin)
% Surface based version of the SPM contrast tools that only change the
% dependency settings updated here.
dep(1) = cfg_dep;
dep(1).sname = 'SPM.mat File';
dep(1).src_output = substruct('.','spmmat');
dep(1).tgt_spec = cfg_findspec({{'filter','mat','strtype','e'}});
dep(2) = cfg_dep;
dep(2).sname = 'All Con Surfaces';
dep(2).src_output = substruct('.','con');
dep(2).tgt_spec = cfg_findspec({{'filter','gifti','strtype','e'}});
dep(3) = cfg_dep;
dep(3).sname = 'All Stats Surfaces';
dep(3).src_output = substruct('.','spm');
dep(3).tgt_spec = cfg_findspec({{'filter','gifti','strtype','e'}});
function surfstat = cat_surf_stat_GUI
% Surface based version of the SPM result GUI.
% This function include multipe updates to (i) deactivate buttons that
% are not working for surfaces and (ii) new control functions to avoid
% problems with the object rotation function (that also rotate the result
% tables and not only the surfaces), but also (iii) some visual updates
% with predefined settings for result visualization.
spmmat = cfg_files;
spmmat.tag = 'spmmat';
spmmat.name = 'Select SPM.mat files';
spmmat.filter = {'mat'};
spmmat.ufilter = '^SPM\.mat$';
spmmat.num = [1 inf];
spmmat.help = {'Select the SPM.mat file that contains the design specification.'};
surfstat = cfg_exbranch;
surfstat.tag = 'SPM';
surfstat.name = 'Estimate Surface Model';
surfstat.val = {spmmat};
surfstat.prog = @cat_stat_spm;
surfstat.vout = @vout_cat_stat_spm;
surfstat.help = {
''};
function vx2surf = cat_surf_vx2surf_GUI(expert,nproc,lazy)
% This is a voxel-based projection of values to the surface.
% surf
surf = cfg_files;
surf.tag = 'surf';
surf.name = 'Left central surfaces';
surf.filter = 'gifti';
surf.ufilter = '^lh.central';
surf.num = [1 Inf];
surf.help = {'Select central surfaces.'};
% name of the measure
name = cfg_entry;
name.tag = 'name';
name.name = 'Name';
name.strtype = 's';
name.num = [1 Inf];
name.val = {'vxvol'};
name.help = {
'Name of the measure that is used in the surface file name, e.g., "roi_volume" will result in "lh.roi_volume.S01" for a subject S01. '
'The surface data has to be smoothed and normalized in the next step. '
''
};
iname = name;
iname.val = {'vxint'};
dname = name;
dname.val = {'vxdist'};
% distance weighting function [high low]
dweighting = cfg_entry;
dweighting.tag = 'dweighting';
dweighting.name = 'Weighting / limitation [Low High High Low]';
dweighting.strtype = 'r';
dweighting.num = [1 4];
dweighting.val = {[0 0 0 10]};
dweighting.help = {
['Distance based weighting outside and inside the surface from high to low. ' ...
'I.e. [2 0 5 10] means full weighting at 0 mm distance and zero weighting at ' ...
'2 mm distance outside of the surface and full weighting from 0 to 5 mm inside ' ...
'the surface with linear decrease from 1 to 0 between 5 and 10 mm inside of the surface. ']
''
};
norm = cfg_menu;
norm.tag = 'norm';
norm.name = 'Final normalization';
norm.val = {''};
norm.help = {
['For many measures a log10 normalization is useful to obtain normal distributed data ' ...
'but also to handle exponential dependencies to brain size. Moreover, it is important ' ...
'to use TIV as general confound in the analysis. ']
''};
if expert>1
norm.labels = {'none','log10a','log10b','log10c','log10d','log10e'};
norm.values = {'','log10a','log10b','log10c','log10d','log10e'};
norm.help = [ norm.help ; {
' log10a = @(val) log10(val * 9/10 + 1)'
' log10b = @(val) log10(val * 99/100 + 1)/2'
' log10c = @(val) log10(val * 999/1000 + 1)/3'
' log10d = @(val) log10(val * 9999/1000 + 1)/4'
' log10e = @(val) log10(val * 99999/1000 + 1)/5'
}];
else
norm.labels = {'none','log10','log10p'};
norm.values = {'','log10a','log10p'};
norm.help = [ norm.help ; {
' log10 = @(val) log10(val * 9/10 + 1)'
' log10p = @(val) log10(val * 999/1000 + 1)/3'
}];
end
% average
average = cfg_menu;
average.tag = 'vweighting';
average.name = 'Average function';
if expert
average.labels = {'mean','median','standard deviation','variance','minimum','maximum'};
average.values = {'mean','median','std','var','min','max'};
else
average.labels = {'mean','standard deviation','variance'};
average.values = {'mean','std','var'};
end
average.val = {'mean'};
average.help = {'Average function for the projection of multiple voxels.' ''};
% msk
rimage = cfg_files;
rimage.tag = 'rimage';
rimage.name = 'Region/tissue (partial) volume mask';
rimage.help = {'Select images that define the tissue/region that should be projected to the surface. ' ''};
rimage.filter = 'image';
rimage.ufilter = '.*';
rimage.num = [1 Inf];
rimage2 = rimage;
rimage2.tag = 'rimage2';
rimage2.name = 'Second region mask for relativation';
rimage2.help = {'i.e. WMH vs. WMV.'};
rimage2.val = {''};
rimage2.num = [0 Inf];
% int
iimage = cfg_files;
iimage.tag = 'iimage';
iimage.name = 'Intensity map';
iimage.help = {'Select images those values are projected within the masked region. ' ''};
iimage.filter = 'image';
iimage.ufilter = '.*';
iimage.num = [1 Inf];
if 0
% complex version
sdist = average;
sdist.tag = 'sdist';
sdist.name = 'Surface distance (average function)';
odist = cfg_menu;
odist.tag = 'odist';
odist.name = 'Object distance (type)';
odist.labels = {'nearest','nearest with erosion'};
odist.values = {'near','nearerode'};
odist.val = {'near'};
odist.help = {
['The nearest option estimates a distance map from the object structure. ' ...
'It maps the inverse value (1/d) because the distance objects are expected to have lower effect in general. ' ...
'The second option estimates multiple distance maps by stepwise erode all structures. ']
};
dmetric = cfg_choice;
dmetric.tag = 'dmetric';
dmetric.name = 'Distance metric';
dmetric.values = {sdist,odist};
dmetric.val = {odist};
dmetric.help = {
['Average distance from the surface to the object or from the object to the surface. ' ...
'The surface distance estimate a voxel-based distance map and then average the values. ' ...
'The object based distance on the other side estimates (multiple) voxel-based distance maps to read out the value at the surface position. ' ...
'Hence, the closes structure (e.g. small lesions) normaly defines the distance but if erosion is used also larger far distance structures can taken into account. ']
''};
else
% simple version
dmetric = cfg_menu;
dmetric.tag = 'odist';
dmetric.name = 'Distance metric';
dmetric.labels = {'Mean surface distance (Push)','Minimum object distance (Pull)'};
dmetric.values = {'sdist','odist'};
dmetric.val = {'odist'};
dmetric.help = {
['Average distance from the surface to the object or from the object to the surface. ' ...
'The surface distance is measured for each voxel and average for the closest vertex. ' ...
'The object based distance on the other side estimates (multiple) voxel-based distance maps to read out the value at the surface position. ' ...
'Hence, the closes structure (e.g. small lesions) normaly defines the distance but if erosion is used also larger far distance structures can taken into account. ']
''};
end
inverse = cfg_menu;
inverse.tag = 'inverse';
inverse.name = 'Inverse metric';
inverse.labels = {'Yes','No'};
inverse.values = {1,0};
inverse.val = {1};
inverse.help = {
'Use inverse distance measures 1/d with 1 if the object is close and 0 if it is far away. Use log10 scaling. '
''};
outdir = cfg_files;
outdir.tag = 'outdir';
outdir.name = 'Output Directory';
outdir.filter = 'dir';
outdir.ufilter = '.*';
outdir.num = [0 1];
outdir.val{1} = {''};
outdir.help = {
'Files produced by this function will be written into this output directory. If no directory is given, images will be written to current working directory. If both output filename and output directory contain a directory, then output filename takes precedence.'
};
% distance weighting function [high low]
smoothing = cfg_entry;
smoothing.tag = 'smooth';
smoothing.name = 'smoothing';
smoothing.strtype = 'r';
smoothing.num = [1 1];
smoothing.val = {0};
smoothing.hidden = expert<2;
smoothing.help = {
'Distance based weighting from high to low, i.e. [0 10] means full weighting at 0 mm distance and zero weighting at 10 mm distance. '
''
};
% measures
vmeasure = cfg_branch;
vmeasure.tag = 'vmeasure';
vmeasure.name = 'Volume measure';
if expert>1
vmeasure.val = {rimage,rimage2,name,dweighting,norm,inverse};
else
vmeasure.val = {rimage,rimage2,name,dweighting,norm};
end
vmeasure.help = {
'Extraction of local volume values of a specied tissue or region. Modulated push from voxel- to surface-space. '};
imeasure = cfg_branch;
imeasure.tag = 'imeasure';
imeasure.name = 'Intensity measure';
if expert>1
imeasure.val = {rimage,iimage,iname,dweighting,norm,average};
else
imeasure.val = {rimage,iimage,iname,dweighting,norm};
end
imeasure.help = {
'Extraction of local intensity values of one map in the regions defined by another. '};
dmeasure = cfg_branch;
dmeasure.tag = 'dmeasure';
dmeasure.name = 'Distance measure';
if expert>1
dmeasure.val = {rimage,dname,dweighting,norm,dmetric};
else
dmeasure.val = {rimage,dname,dweighting,norm};
end
dmeasure.help = {
'Extraction of local intensity values of one map in the regions defined by another. '};
% predefined measures
% --- volume measures -------------------------------------------------
GMV = cfg_menu;
GMV.tag = 'GMV';
GMV.name = 'GM volume';
GMV.labels = {'Yes','No'};
GMV.values = {1,0};
GMV.val = {0};
GMV.hidden = expert<1;
GMV.help = {
['Map local GM volume within 3 mm distance to the surface. ' ...
'The results are similar to the GM thickness map and represents the simplyfied form V_GM = A_GM * T_GM. ']
''};
WMV = GMV;
WMV.tag = 'WMV';
WMV.name = 'WM volume';
WMV.hidden = expert<1;
WMV.help = {
['Map local WM volume within 10 mm distance to the surface. ' ...
'Especially the motorcortex and occipital areas have an enlarged volume compared to other ares. ' ...
'The enlargement could be related to the amount of myelination and hence depend on the preprocessing. ']
''};
WMHV = GMV;
WMHV.tag = 'WMHV';
WMHV.name = 'WMH volume';
WMHV.hidden = expert<1;
WMHV.help = {
'Map local WMH volume within 10 mm distance to the surface. '
''
'See also WMH vs WM volume measure.'
''};
WMHVvsWMV = GMV;
WMHVvsWMV.tag = 'WMHVvsWMV';
WMHVvsWMV.name = 'WMH vs. WM volume';
WMHVvsWMV.hidden= expert<1;
WMHVvsWMV.help = {
'Estimate the relation between the mapped local WMH and WM volume within 10 mm distance. '
''};
WMVvsGMV = GMV;
WMVvsGMV.tag = 'WMVvsGMV';
WMVvsGMV.name = 'WM vs. GM volume';
WMVvsGMV.hidden = expert<2;
WMVvsGMV.help = {
'This describes the relation between the local amount of WM to GM and is some kind of folding measure. '
''};
% intensity
WMmnI = GMV;
WMmnI.tag = 'WMmnI';
WMmnI.name = 'WM mean intensity';
WMmnI.hidden = expert<2;
WMmnI.help = {
'This describes the mean intensity of the WM in a distance of 7 voxels and describes the impact of WMHs in the volume. '
''
'See also WM intensity variance.'
''};
WMsdI = GMV;
WMsdI.tag = 'WMsdI';
WMsdI.name = 'WM intensity variance';
WMsdI.hidden = expert<2;
WMsdI.help = {
['This describes the standard deviation of the intensity within the WM of a 7x7x7 box and describes the impact of WMHs in the volume. ' ...
'In contrast to the WM mean intensity it is less effected by WMHs and more sensitive to PVSs. ']
''
'See also WM mean intensity. '
''};
GMmnI = GMV;
GMmnI.tag = 'GMmnI';
GMmnI.name = 'GM mean intensity';
GMmnI.hidden = expert<2;
GMmnI.help = {
'This describes the mean intensity of the GM in a 5x5x5 box and describes the myelination of the cortex. '
''};
% distances
WMD = GMV;
WMD.tag = 'WMD';
WMD.name = 'WM distance';
WMD.hidden = expert<1;
WMD.help = {
['This another way to measures the cortical thickness with GMT = WMD * 2, ' ...
'because the central surface runs in the middle of the cortex. ']
'However, this is just an example to test the distance measure in general and it is better to use the thickness itself. '
''};
WMHD = GMV;
WMHD.tag = 'WMHD';
WMHD.name = 'WMH distance';
WMHD.hidden = expert<1;
WMHD.help = {
'This describes the distance to the closest WMH. The measure is similar to the WMV. '
''};
% PVSdist
xmeasure = cfg_branch;
xmeasure.tag = 'xmeasure';
xmeasure.name = 'Predefined measures';
xmeasure.val = {GMV,WMV,WMHV,WMHVvsWMV,WMVvsGMV,WMmnI,WMsdI,GMmnI,WMD,WMHD};
xmeasure.help = {
'The are some predefined measures to project local tissue properties to the surface.'};
% measure {vol, int, dist, idist)
measures = cfg_repeat;
measures.tag = 'measures';
measures.name = 'Measures';
measures.num = [1 inf];
measures.values = {xmeasure, vmeasure, imeasure, dmeasure};
measures.val = {xmeasure};
measures.help = {
'Application of predefined measures or own defintion of volume-, intensity-, distance-based ways to map voxel-based informations to the surface. ' ''};
interp = cfg_menu;
interp.tag = 'interp';
interp.name = 'Interpolation';
interp.labels = {'yes','no'};
interp.values = {1,0};
interp.val = {0};
interp.hidden = expert<2;
interp.help = {
['Use interpolated voxel grid to improve mapping quality. ' ...
'However, it is expected that there are only small improvements that are not ' ...
'relevant because strong smoothing is also required by anatomical constrains. '] ''};
% opts
opts = cfg_exbranch;
opts.tag = 'opts';
opts.name = 'Options';
if expert
opts.val = {interp,outdir,nproc}; % lazy,nproc,verb
else
opts.val = {outdir,nproc};
end
opts.help = {'General processing options of all measures. ' ''};
% main
vx2surf = cfg_exbranch;
vx2surf.tag = 'vx2surf';
vx2surf.name = 'Map voxel-data to the surface (IN DEVELOPMENT)';
vx2surf.val = {surf,measures,opts}; %
vx2surf.prog = @cat_surf_vx2surf;
vx2surf.vout = @vout_cat_surf_vx2surf;
vx2surf.help = {
['Voxel-based projection of volume values to the individual surface that is still IN DEVELOPMENT. ' ...
'The approach aligns all voxels within a specified tissue/ROI to its closest surface vertex. ' ...
'The volume, intensity, or distance values were averaged in a user specified way and saved as a raw surface measure ' ...
'that has to be smoothed and resampled. ']
''};
vx2surf.hidden = expert<2;
return
function surf2roi = cat_surf_surf2roi_GUI(expert,nproc)
%% surface to ROI (in template space)
% ---------------------------------------------------------------------
% * CxN cdata files [ thickness , curvature , ... any other file ] in template space [ resampled ]
% * M atlas files [ choose files ]
% * average measures [ mean , std , median , max , min , mean95p ]
%
% - csv export (multiple files) > catROIs_ATLAS_SUBJECT
% - xml export (one file) > catROIs_ATLAS_SUBJECT
% ---------------------------------------------------------------------
% surface ROIs have sidewise index?!
% ---------------------------------------------------------------------
% set of cdata files
if expert && 0 % this is not ready now
cdata = cfg_files;
cdata.tag = 'cdata';
cdata.name = '(Left) Surface Data Files';
cdata.filter = 'any';
cdata.ufilter = 'lh.(?!cent|pial|white|sphe|defe|hull|pbt).*';
cdata.num = [1 Inf];
cdata.help = {'Surface data files. Both sides will be processed'};
else % only smoothed/resampled
cdata = cfg_files;
cdata.tag = 'cdata';
cdata.name = '(Left) Surface Data Files';
cdata.filter = 'any';
cdata.ufilter = '^lh.(?!cent|pial|white|sphe|defe|hull|pbt).*';
cdata.num = [1 Inf];
cdata.help = {'Surface data files. Both sides will be processed'};
end
cdata_sample = cfg_repeat;
cdata_sample.tag = 'cdata_sub.';
cdata_sample.name = 'Surface Data';
cdata_sample.values = {cdata};
cdata_sample.num = [1 Inf];
cdata_sample.help = {[...
'Specify data for each measure (i.e. thickness, gyrification, ...). ' ...
'All measures must have the same size and same order. ' ...
''
]};
% ROI files
ROIs = cfg_files;
ROIs.tag = 'rdata';
ROIs.name = '(Left) ROI atlas files';
ROIs.filter = 'any';
ROIs.ufilter = '^lh.*\.annot$';
ROIs.dir = fullfile(fileparts(mfilename('fullpath')),'atlases_surfaces');
ROIs.num = [1 Inf];
%ROIs.hidden = expert<2;
ROIs.help = {'These are the ROI atlas files. Both sides will be processed.'};
% not used
%{
% ROI area
area = cfg_menu;
area.tag = 'area';
area.name = 'Estimate ROI Area';
area.labels = {'No','Yes'};
area.values = {0,1};
area.val = {1};
area.help = {'Estimate area of each ROI.'};
% ROI area
vernum = cfg_menu;
vernum.tag = 'vernum';
vernum.name = 'Count ROI Vertices';
vernum.labels = {'No','Yes'};
vernum.values = {0,1};
vernum.val = {1};
vernum.help = {'Count vertices of each ROI.'};
%}
% average mode within a ROI
% mean
avg.mean = cfg_menu;
avg.mean.tag = 'mean';
avg.mean.name = 'Mean Estimation';
avg.mean.labels = {'No','Yes'};
avg.mean.values = {0,1};
avg.mean.val = {1};
avg.mean.help = {'Set mean value estimation per ROI.'};
% std
avg.std = cfg_menu;
avg.std.tag = 'std';
avg.std.name = 'STD Estimation';
avg.std.labels = {'No','Yes'};
avg.std.values = {0,1};
avg.std.val = {1};
avg.std.help = {'Set standard deviation estimation per ROI.'};
% min
avg.min = cfg_menu;
avg.min.tag = 'min';
avg.min.name = 'Minimum Estimation';
avg.min.labels = {'No','Yes'};
avg.min.values = {0,1};
avg.min.val = {0};
avg.min.help = {'Set minimum estimation per ROI.'};
% max
avg.max = cfg_menu;
avg.max.tag = 'max';
avg.max.name = 'Maximum Estimation';
avg.max.labels = {'No','Yes'};
avg.max.values = {0,1};
avg.max.val = {0};
avg.max.help = {'Set maximum estimation per ROI.'};
% median
avg.median = cfg_menu;
avg.median.tag = 'median';
avg.median.name = 'Median Estimation';
avg.median.labels = {'No','Yes'};
avg.median.values = {0,1};
avg.median.val = {0};
avg.median.help = {'Set median estimation per ROI.'};
% all functions
avg.main = cfg_branch;
avg.main.tag = 'avg';
avg.main.name = 'ROI Average Functions';
avg.main.val = {
avg.mean ...
avg.std ...
avg.min ...
avg.max ...
avg.median ...
};
avg.main.hidden = expert<2;
nproc.hidden = expert<2;
%% main function
surf2roi = cfg_exbranch;
surf2roi.tag = 'surf2roi';
surf2roi.name = 'Extract ROI-based surface values';
% CG 20200820: here we still have to use the differentiation between different modes
% because the developer settings are not yet working
switch expert
case 2
surf2roi.val = {
cdata_sample ...
ROIs ...
nproc ...
avg.main};
case {0, 1}
surf2roi.val = {cdata_sample,ROIs};
end
surf2roi.prog = @cat_surf_surf2roi;
surf2roi.vout = @vout_surf_surf2roi;
surf2roi.help = {
'While ROI-based values for VBM (volume) data are automatically saved in the label folder as XML file it is necessary to additionally extract these values for surface data. This has to be done after preprocessing the data and creating cortical surfaces. '
''
'You can extract ROI-based values for cortical thickness but also for any other surface parameter that was extracted using the "Extract Additional Surface Parameters" function.'
''
'Please note that these values are extracted from data in native space without any smoothing. As default the mean inside a ROI is calculated and saved as XML file in the label folder.'
};
%==========================================================================
function [vol2surf,vol2tempsurf] = cat_surf_vol2surf_GUI(expert,merge_hemi,mesh32k)
%% map volumetric data
%-----------------------------------------------------------------------
datafieldname = cfg_entry;
datafieldname.tag = 'datafieldname';
datafieldname.name = 'Output Name';
datafieldname.strtype = 's';
datafieldname.num = [1 Inf];
datafieldname.val = {'intensity'};
datafieldname.help = {
'Name that is prepended to the filename of the mapped volume.'
''
};
interp = cfg_menu;
interp.tag = 'interp';
interp.name = 'Interpolation Type';
interp.labels = {'Nearest neighbour','Linear','Cubic'};
interp.values = {{'nearest_neighbour'},{'linear'},{'cubic'}};
interp.val = {{'linear'}};
interp.hidden = expert<1;
interp.help = {
'Volume extraction interpolation type. '
' -linear: Use linear interpolation (default).'
' -nearest_neighbour: Use nearest neighbour interpolation.'
' -cubic: Use cubic interpolation.'
''
};
% sample function
sample = cfg_menu;
sample.tag = 'sample';
sample.name = 'Sampling Function';
sample.labels = {'Mean','Median','Weighted mean','Maximum','Minimum','Absolute maximum','Multi-values'};
sample.values = {{'avg'},{'median'},{'weighted_avg'},{'max'},{'min'},{'maxabs'},{'multi'}};
sample.val = {{'maxabs'}};
sample.help = {
'Sampling function to combine the values of the grid along the surface normals.'
' Mean: Use average for mapping along normals.'
' Median: Use median for mapping along normals.'
' Weighted mean: Use weighted average with gaussian kernel for mapping along normals. The kernel is so defined that values at the boundary are weighted with 50% while center is weighted with 100% (useful for (r)fMRI data.'
' Maximum: Use maximum value for mapping along normals.'
' Minimum: Use minimum value for mapping along normals.'
' Absolute maximum: Use absolute maximum value for mapping along normals (useful for mapping contrast images from 1st-level fMRI analysis).'
' Multi-values: Map data for each grid step separately and save files with indicated grid value. Please note that this option is intended for high-resolution (f)MRI data only (e.g. 0.5mm voxel size).'
''
};
%% -- sampling points and average function
% startpoint
abs_startpoint = cfg_entry;
abs_startpoint.tag = 'startpoint';
abs_startpoint.name = 'Startpoint';
abs_startpoint.strtype = 'r';
abs_startpoint.val = {-0.5};
abs_startpoint.num = [1 1];
abs_startpoint.help = {
'Absolute position of the start point of the grid along the surface normals in mm according to the surface. Give negative value for a start point outside of the surface (CSF direction, outwards). '
};
rel_startpoint = abs_startpoint;
rel_startpoint.val = {-0.6};
rel_startpoint.help = {
'Relative position of the start point of the grid along the surface normals according to a tissue class. A value of "-0.5" begins at the GM/CSF border and even lower values define a start point outside of the tissue class (CSF direction, outwards) which is the default to ensure that all values are mapped. A value of "0" means that the central surface is used as starting point and "0.5" is related to the GM/WM border.'
};
% steps
abs_steps = cfg_entry;
abs_steps.tag = 'steps';
abs_steps.name = 'Steps';
abs_steps.strtype = 'w';
abs_steps.val = {7};
abs_steps.num = [1 1];
abs_steps.help = {
'Number of grid steps. '
};
rel_steps = abs_steps;
% endpoint
abs_endpoint = cfg_entry;
abs_endpoint.tag = 'endpoint';
abs_endpoint.name = 'Endpoint';
abs_endpoint.strtype = 'r';
abs_endpoint.val = {0.5};
abs_endpoint.num = [1 1];
abs_endpoint.help = {
'Absolute position of the end point of the grid along the surface normals (pointing inwards) in mm according to the surface. '
};
rel_endpoint = abs_endpoint;
rel_endpoint.val = {0.6};
rel_endpoint.help = {
'Relative position of the end point of the grid along the surface normals (pointing inwards) according to a tissue class. A value of "0.5" ends at the GM/WM border and values > 0.5 define an end point outside of the tissue class (WM direction, inwards) which is the default to ensure that all values are mapped. A value of "0" ends at the central surface.'
};
% tissue class
rel_class = cfg_menu;
rel_class.tag = 'class';
rel_class.name = 'Tissue Class';
rel_class.labels = {'GM'};
rel_class.values = {'GM'};
rel_class.val = {'GM'};
rel_class.help = {
'Tissue class for which the relative positions are estimated.'
};
% tissue class
abs_class = cfg_menu;
abs_class.tag = 'surface';
abs_class.name = 'Surface';
abs_class.labels = {'WM Surface','Central Surface','Pial Surface'};
abs_class.values = {'WM','Central','Pial'};
abs_class.val = {'Central'};
abs_class.help = {
'Surface (or tissue boundary) for which the absolute positions are estimated.'
};
% absolute position
abs_mapping = cfg_branch;
abs_mapping.tag = 'abs_mapping';
abs_mapping.name = 'Absolute Grid Position From a Surface';
abs_mapping.val = {
abs_class ...
abs_startpoint ...
abs_steps ...
abs_endpoint ...
};
abs_mapping.help = {
'Map volumetric data from abolute grid positions from a surface (or tissue boundary).'
};
%% relative mapping with equi-distance approach
rel_mapping = cfg_branch;
rel_mapping.tag = 'rel_mapping';
rel_mapping.name = 'Relative Grid Position Within a Tissue Class (Equi-distance Model)';
rel_mapping.val = {
rel_class ...
rel_startpoint ...
rel_steps ...
rel_endpoint ...
};
rel_mapping.help = {
'Map volumetric data from relative grid positions within a tissue class using equi-distance approach. Here, the grid lines have equal distances between the tissues.'
};
%% relative mapping with equi-volume approach
rel_equivol_mapping = cfg_branch;
rel_equivol_mapping.tag = 'rel_equivol_mapping';
rel_equivol_mapping.name = 'Relative Grid Position Within a Tissue Class (Equi-volume Model)';
rel_equivol_mapping.val = {
rel_class ...
rel_startpoint ...
rel_steps ...
rel_endpoint ...
};
rel_equivol_mapping.help = {
'Map volumetric data from relative positions within a tissue class using equi-volume approach. '
'This option is using the approach by Bok (Z. Gesamte Neurol. Psychiatr. 12, 682-750, 1929). '
'Here, the volume between the grids is constant. The correction is based on Waehnert et al. (NeuroImage, 93: 210-220, 2014).'
''
};
%% -- Mapping function
mapping = cfg_choice;
mapping.tag = 'mapping';
mapping.name = 'Mapping Function';
mapping.values = {
abs_mapping ...
rel_equivol_mapping ...
};
mapping.val = {rel_equivol_mapping};
mapping.help = {
'Volume extraction type. '
' Absolute Grid Position From a Surface (or Tissue Boundary):'
' Extract values around a surface or tissue boundary with a specified absolute sample '
' distance and either combine these values or save values separately.'
' Relative Grid Position Within a Tissue Class (Equi-volume approach):'
' Extract values within a tissue class with a specified relative sample distance'
' that is corrected for constant volume between the grids and either combine these values or save values separetely.'
''
};
if expert > 1
mapping.values{3} = rel_mapping;
mapping.help = [ mapping.help; {
' Relative Grid Position Within a Tissue Class (Equi-distance approach):'
' Extract values within a tissue class with a specified relative sample distance'
' with equally distributed distances and either combine these values or save values separately.'
''
}];
end
mapping_native = mapping;
% extract volumetric data in individual space
%-----------------------------------------------------------------------
data_surf_sub_lh = cfg_files;
data_surf_sub_lh.tag = 'data_mesh_lh';
data_surf_sub_lh.name = '(Left) Individual Surfaces';
data_surf_sub_lh.filter = 'gifti';
data_surf_sub_lh.ufilter = '^lh.central.(?!nofix).*';
data_surf_sub_lh.num = [1 Inf];
data_surf_sub_lh.help = {
'Select left subject surface files.'
'Right side will be automatically processed.'
};
data_sub = cfg_files;
data_sub.tag = 'data_vol';
data_sub.name = '(Co-registered) Volumes in Native Space';
data_sub.filter = 'image';
data_sub.ufilter = '^(?!wm|wp|m0wp|mwp|wc).*'; % no normalized images
data_sub.num = [1 Inf];
data_sub.help = {
'Select volumes in native (subject) space.'
'Please note that these images have to be in the same space as the T1-image that was used to extract the cortical surface. An optional co-registration might be necessary if you have functional or structural data that are not yet aligned to the T1-image.'
};
vol2surf = cfg_exbranch;
vol2surf.tag = 'vol2surf';
vol2surf.name = 'Map Volume (Native Space) to Individual Surface';
vol2surf.val = {
data_sub ...
data_surf_sub_lh ...
sample ...
interp ...
datafieldname ...
mapping_native ...
};
vol2surf.prog = @cat_surf_vol2surf;
vol2surf.vout = @vout_vol2surf;
vol2surf.help = {
'Map volume (native space) to individual surface. These mapped volumes have to be finally resampled and smoothed before any statistical analysis.'
''
'The output will be named:'
' [rh|lh].OutputName_VolumeName'
''
};
data_surf_avg_lh = cfg_files;
data_surf_avg_lh.tag = 'data_mesh_lh';
data_surf_avg_lh.name = '(Left) Template Hemisphere';
data_surf_avg_lh.filter = 'gifti';
data_surf_avg_lh.ufilter = '^lh.*';
data_surf_avg_lh.num = [1 1];
data_surf_avg_lh.val{1} = {fullfile(fileparts(mfilename('fullpath')),'templates_surfaces',['lh.central.' cat_get_defaults('extopts.shootingsurf') '.gii'])};
data_surf_avg_lh.dir = fullfile(fileparts(mfilename('fullpath')));
data_surf_avg_lh.help = {
'Select left template surface file. '
'Right hemisphere will be automatically processed.'
};
data_norm = cfg_files;
data_norm.tag = 'data_vol';