Submitted by admin on Mon, 10/08/2018 - 08:13
The code below is dependent on GIFT, FSL and AFNI. It shows the 2nd level ICA since the 1st level can be done through GIFT, FSL melodic etc..
Transient information can be retrieved by using the saved subject's profile as weight (per the analysis of the paper) to be multiplied to the dynamic profiles given by GIG-ICA or any other back-reconstruction method (such as dual regression).
$ cat ica.jointICA4nii.sh
- #!/usr/bin/env bash
- #
- # gicaS.sh
- #% Init: 2013-11-06.13:37
- #% Version: 20170614.17:28 Xiaowei Song
- #% Copyright (C) 2013~2020 Xiaowei.Song <dawnwei.song@gmail.com>
- #% http://restfmri.net/forum/XiaoweiSong
- #% Distributed under terms of the AFL (Academy Free license).
- #
- CALLDIR="$( cd "$( dirname "${0}" )" && pwd )"
- elog(){ echo "$@" 1>&2 ; }
- echo "$(date) | $0 $*" >> $(basename $0).LOG
- source $(dawnbin)/slib.bash.sh
- shopt -s expand_aliases; source $(dawnbin)/slib.stack.sh
- usage(){ printf "
- Usage: (%s)
- ${0} [options]
- options:
- Spacial ICA by using GIFT
- 1. if multi nifti files input, default do Zconcat to make them in spatial dim
- 2. need manually concat in T dim if all inputs are 3D nifti ( such as thickness ) files
- " "$(grep -m1 '#% Version:' `readlink -f ${0}`)" 1>&2 ; }
- while [ $# -gt 0 ]; do
- case "$1" in
- '-v') VERBOSE=1 ; shift ;;
- '-d') DEBUG=1 ; shift ;;
- '-m'|'--mask') MASK=$2 ; shift 2 ;;
- '-dm'|'--rm-mean') DEMEAN=$2; shift 2 ;;
- -k|'-n') COMPNUM=$2; shift 2 ;;
- #usually be 99->30
- -evp|--expected-var-percent) EXPECTED_VAR_PERCENT=$2; shift 2;;
- '-p'|'--prefix') PREFIX=$2; shift 2 ;;
- --mst) MST=$2; shift 2;;
- -rd|--cut-dir) CUT_DIR=$2; shift 2;;
- '-*') elog 'Unknown parameters'; usage; exit 0 ;;
- *) break ;;
- esac
- done
- verbose=${VERBOSE:-0};
- if [ $# -eq 0 ] || ! IsFileExist $MASK ; then usage; exit 0; fi
- nii=$1
- bnii=$(basename $nii .nii)
- #%parse ICA options
- OPT4ICA=${ICAOPTIONS:-{}}
- fpca="${PREFIX:-${bnii}}_pca.nii"
- rm -f $fpca #clean, must do since SPM8 will only overwrite certain time points
- if ! IsFileLoadable $MASK; then
- elog "Mask not loadable: $MASK"
- #automask based on first input nii
- MASK=$(getmp).nii
- 3dAutomask -prefix $MASK $1
- fi
- read ax ay az <<<$(3dinfo -ni -nj -nk $MASK)
- mkStack inputs
- mkStack ftmps
- #build all input and zstack
- lst=${PREFIX:-jointICA}.lst
- while [[ $# -gt 0 ]]; do
- nii=$1
- pushs inputs $(rmExtDir4nii $nii)
- gz=${nii##*.}
- prefix=$(rmExtDir4nii $nii)
- if [[ gz == "$gz" ]]; then
- nii=$(getmp).nii
- pushs ftmps $nii
- gunzip -c $1 > $nii
- fi
- echo $(readlink -f $nii) ; shift;
- done > $lst
- showStack inputs
- #exit
- nnii=$(cat $lst|wc -l)
- #build jICA input
- nii=$(getmp).nii ; pushs ftmps $nii
- msk=$(getmp).nii ; pushs ftmps $msk
- 3dhdr $(cat $lst |xargs) $MASK
- if [[ 1 -eq $nnii ]]; then
- 3dcopy $(cat $lst |xargs) $nii #thus support nii.gz if only 1 input
- 3dcopy $MASK $msk
- else
- #3dZcat needs at least 2 inputs
- 3dZcat -prefix $nii $(cat $lst |xargs)
- 3dZcat -prefix $msk $(yes $MASK |head -n $nnii |xargs)
- fi
- result=${PREFIX:-${bnii}}_component_ica_.nii
- resultTC=${PREFIX:-${bnii}}_timecourses_ica_.txt
- rm $result $resultTC
- tmp=$(getmp).m
- cat > $tmp <<eom
- try
- [msko, hinfo]=icatb_read_data('$msk');
- msk=find(msko);
- data=icatb_read_data('$nii',[],msk);
- data=icatb_preproc_data(data, '${DEMEAN:-"Remove Mean Per voxel"}');
- %data will be 60K x 200
- %spacial ICA
- [~,S,V]=svd(data, 'econ');
- % V would be 200x200
- Lambda=diag(S);
- %Lambda = Lambda ./ sqrt(size(data, 1) - 1);
- %[Lambda, inds] = sort(Lambda.^2); %make sv ascending
- % no need to sort, default would be from Max to Min
- LambdaSq = Lambda.^2; %calculate variance for A'A
- nc=${COMPNUM:-30}
- evp=${EXPECTED_VAR_PERCENT:-0};
- if evp>0,
- cumVar=100*cumsum(LambdaSq)/sum(LambdaSq);
- nc=find(cumVar>=evp, 1);
- end
- %by default, choose 30 components
- pcaVar= sum(LambdaSq(1:nc))/sum(LambdaSq);
- %but Variance Percent have higher priority
- %dim reduction
- Lambda=diag(Lambda(1:nc)); %vec to diag matrix
- V=V(:,1:nc);
- %map to PCA
- whiteM = Lambda \ V'; %normalize by eigenvalue, complete whitening, will lose eigenvalue information
- %30x200
- dewhiteM = V * Lambda;
- %200x30
- pcasig=data*whiteM'; %60k x 30
- pcasig=pcasig * diag(1./std(pcasig));
- %print variance explained by the PCA
- fprintf(2, '\n%d x %d, %d x %d ', size(data), size(pcasig));
- fprintf(2, '\n### %.2g%% percent variance explained by %d PCA', 100*pcaVar, nc);
- %MST
- icasigR=cell(1, ${MST:-2});
- for i=1:${MST:-2},
- [algo, W, A, icasigR{i}]=icatb_icaAlgorithm('${ICAALGORITHM:-ICA-EBM}',pcasig', ${OPT4ICA}, i);
- %input data should be 30x60k
- end
- [corrMetric, W, A, icasig, bestRun]=icatb_bestRunSelection(icasigR, pcasig');
- %input data should be 30x60k
- %back-proj loadings to be full, i.e., to make each subject have a loading
- %pcasig = A*icasig (30x30 * 30x60k -> 30x60k)
- loadings=dewhiteM * A; %200x30 * 30x30 -> 200x30
- %data = loadings * icasig; %200x60k <- 200x30 * 30x60k
- SM=icasig; tc=loadings;
- icatb_saveICAData('$result', SM, tc, msk, size(SM, 1), hinfo, 'real');
- dlmwrite('$resultTC', tc,'delimiter','\t')
- % %rebuild 4D original dataset to nifti
- % hinfo=spm_vol('$MASK');
- % fname='${fpca}';
- % for t=1:size(pcasig, 2),
- % odat=zeros(size(msko));
- % odat(msk)=pcasig(:, t);
- % hinfo.fname=fname;
- % hinfo.n(1)=t;
- % hinfo.dt(1)=16; % single / float32
- % spm_write_vol(hinfo, odat(:,:,:));
- % end
- catch
- xiaowei_lasterror;
- end
- debug=${DEBUG:-0};
- if debug~=0,
- save('debug.mat');
- end
- exit
- eom
- matlab < $tmp
- if IsFileLoadable $result; then
- #cut Z-cat components back to each
- if [[ 1 -lt $nnii ]]; then
- mkStack fix4sform
- #for((i=0;i < $nnii ;i++)); do
- for((i=$nnii-1;i>=0;i--)); do
- s=$(echo $i|awk -v az=$az '{print az*$1}')
- e=$(echo $i|awk -v az=$az '{print az*(1+$1)-1}')
- pops inputs nii #pop out in reverse order
- 3dZcutup -prefix ${CUT_DIR:-.}/${nii}.nii -keep $s $e $result
- #save for nifti header sform/qform fixation, otherwise, the mm will be too huge for MNI
- pushs fix4sform ${CUT_DIR:-.}/${nii}.nii
- done
- #save nifti header of 1st dataset, which should have correct mm sform/qform matrix
- #then apply to remaining datasets
- pops fix4sform nii #save the 1st dataset's header
- elog "$nii sform/qform header will be saved"
- fslorient -getsform $nii > ${nii}.sform
- sform=${nii}.sform; onii=$nii
- for((i=$nnii-1;i>0;i--)); do
- pops fix4sform nii #pop out in reverse order
- elog "fixing $nii header to the sform/qform of $onii"
- fslorient -setsform $(cat $sform) $nii
- fslorient -copysform2qform $nii
- done
- fi
- else
- elog "Failed: $result "
- fi
- if [[ 0 -eq ${DEBUG:-0} ]]; then
- showStack ftmps
- eval "tmpf=$(showStack ftmps)"
- [[ -z "${tmpf[@]}" ]] || rm ${tmpf[@]}
- rm $tmp
- else
- elog $tmp
- fi
$ cat ica.jointICA4nii.sh
#!/usr/bin/env bash
#
# gicaS.sh
#% Init: 2013-11-06.13:37
#% Version: 20170614.17:28 Xiaowei Song
#% Copyright (C) 2013~2020 Xiaowei.Song <dawnwei.song@gmail.com>
#% http://restfmri.net
#% Distributed under terms of the AFL (Academy Free license).
#
CALLDIR="$( cd "$( dirname "${0}" )" && pwd )"
elog(){ echo "$@" 1>&2 ; }
echo "$(date) | $0 $*" >> $(basename $0).LOG
source $(dawnbin)/slib.bash.sh
shopt -s expand_aliases; source $(dawnbin)/slib.stack.sh
usage(){ printf "
Usage: (%s)
${0} [options]
options:
Spacial ICA by using GIFT
1. if multi nifti files input, default do Zconcat to make them in spatial dim
2. need manually concat in T dim if all inputs are 3D nifti ( such as thickness ) files
" "$(grep -m1 '#% Version:' `readlink -f ${0}`)" 1>&2 ; }
while [ $# -gt 0 ]; do
case "$1" in
'-v') VERBOSE=1 ; shift ;;
'-d') DEBUG=1 ; shift ;;
'-m'|'--mask') MASK=$2 ; shift 2 ;;
'-dm'|'--rm-mean') DEMEAN=$2; shift 2 ;;
-k|'-n') COMPNUM=$2; shift 2 ;;
#usually be 99->30
-evp|--expected-var-percent) EXPECTED_VAR_PERCENT=$2; shift 2;;
'-p'|'--prefix') PREFIX=$2; shift 2 ;;
--mst) MST=$2; shift 2;;
-rd|--cut-dir) CUT_DIR=$2; shift 2;;
'-*') elog 'Unknown parameters'; usage; exit 0 ;;
*) break ;;
esac
done
verbose=${VERBOSE:-0};
if [ $# -eq 0 ] || ! IsFileExist $MASK ; then usage; exit 0; fi
nii=$1
bnii=$(basename $nii .nii)
#%parse ICA options
OPT4ICA=${ICAOPTIONS:-{}}
fpca="${PREFIX:-${bnii}}_pca.nii"
rm -f $fpca #clean, must do since SPM8 will only overwrite certain time points
if ! IsFileLoadable $MASK; then
elog "Mask not loadable: $MASK"
#automask based on first input nii
MASK=$(getmp).nii
3dAutomask -prefix $MASK $1
fi
read ax ay az <<<$(3dinfo -ni -nj -nk $MASK)
mkStack inputs
mkStack ftmps
#build all input and zstack
lst=${PREFIX:-jointICA}.lst
while [[ $# -gt 0 ]]; do
nii=$1
pushs inputs $(rmExtDir4nii $nii)
gz=${nii##*.}
prefix=$(rmExtDir4nii $nii)
if [[ gz == "$gz" ]]; then
nii=$(getmp).nii
pushs ftmps $nii
gunzip -c $1 > $nii
fi
echo $(readlink -f $nii) ; shift;
done > $lst
showStack inputs
#exit
nnii=$(cat $lst|wc -l)
#build jICA input
nii=$(getmp).nii ; pushs ftmps $nii
msk=$(getmp).nii ; pushs ftmps $msk
3dhdr $(cat $lst |xargs) $MASK
if [[ 1 -eq $nnii ]]; then
3dcopy $(cat $lst |xargs) $nii #thus support nii.gz if only 1 input
3dcopy $MASK $msk
else
#3dZcat needs at least 2 inputs
3dZcat -prefix $nii $(cat $lst |xargs)
3dZcat -prefix $msk $(yes $MASK |head -n $nnii |xargs)
fi
result=${PREFIX:-${bnii}}_component_ica_.nii
resultTC=${PREFIX:-${bnii}}_timecourses_ica_.txt
rm $result $resultTC
tmp=$(getmp).m
cat > $tmp <<eom
try
[msko, hinfo]=icatb_read_data('$msk');
msk=find(msko);
data=icatb_read_data('$nii',[],msk);
data=icatb_preproc_data(data, '${DEMEAN:-"Remove Mean Per Timepoint"}');
%data will be 60K x 200
%spacial ICA
[~,S,V]=svd(data, 'econ');
% V would be 200x200
Lambda=diag(S);
%Lambda = Lambda ./ sqrt(size(data, 1) - 1);
%[Lambda, inds] = sort(Lambda.^2); %make sv ascending
% no need to sort, default would be from Max to Min
LambdaSq = Lambda.^2; %calculate variance for A'A
nc=${COMPNUM:-30}
evp=${EXPECTED_VAR_PERCENT:-0};
if evp>0,
cumVar=100*cumsum(LambdaSq)/sum(LambdaSq);
nc=find(cumVar>=evp, 1);
end
%by default, choose 30 components
pcaVar= sum(LambdaSq(1:nc))/sum(LambdaSq);
%but Variance Percent have higher priority
%dim reduction
Lambda=diag(Lambda(1:nc)); %vec to diag matrix
V=V(:,1:nc);
%map to PCA
whiteM = Lambda \ V'; %normalize by eigenvalue, complete whitening, will lose eigenvalue information
%30x200
dewhiteM = V * Lambda;
%200x30
pcasig=data*whiteM'; %60k x 30
pcasig=pcasig * diag(1./std(pcasig));
%print variance explained by the PCA
fprintf(2, '\n%d x %d, %d x %d ', size(data), size(pcasig));
fprintf(2, '\n### %.2g%% percent variance explained by %d PCA', 100*pcaVar, nc);
%MST
icasigR=cell(1, ${MST:-2});
for i=1:${MST:-2},
[algo, W, A, icasigR{i}]=icatb_icaAlgorithm('${ICAALGORITHM:-ICA-EBM}',pcasig', ${OPT4ICA}, i);
%input data should be 30x60k
end
[corrMetric, W, A, icasig, bestRun]=icatb_bestRunSelection(icasigR, pcasig');
%input data should be 30x60k
%back-proj loadings to be full, i.e., to make each subject have a loading
%pcasig = A*icasig (30x30 * 30x60k -> 30x60k)
loadings=dewhiteM * A; %200x30 * 30x30 -> 200x30
%data = loadings * icasig; %200x60k <- 200x30 * 30x60k
SM=icasig; tc=loadings;
icatb_saveICAData('$result', SM, tc, msk, size(SM, 1), hinfo, 'real');
dlmwrite('$resultTC', tc,'delimiter','\t')
% %rebuild 4D original dataset to nifti
% hinfo=spm_vol('$MASK');
% fname='${fpca}';
% for t=1:size(pcasig, 2),
% odat=zeros(size(msko));
% odat(msk)=pcasig(:, t);
% hinfo.fname=fname;
% hinfo.n(1)=t;
% hinfo.dt(1)=16; % single / float32
% spm_write_vol(hinfo, odat(:,:,:));
% end
catch
xiaowei_lasterror;
end
debug=${DEBUG:-0};
if debug~=0,
save('debug.mat');
end
exit
eom
#runxvfb matlabg < $tmp
matlabj < $tmp
if IsFileLoadable $result; then
#cut Z-cat components back to each
if [[ 1 -lt $nnii ]]; then
mkStack fix4sform
#for((i=0;i < $nnii ;i++)); do
for((i=$nnii-1;i>=0;i--)); do
s=$(echo $i|awk -v az=$az '{print az*$1}')
e=$(echo $i|awk -v az=$az '{print az*(1+$1)-1}')
pops inputs nii #pop out in reverse order
3dZcutup -prefix ${CUT_DIR:-.}/${nii}.nii -keep $s $e $result
#save for nifti header sform/qform fixation, otherwise, the mm will be too huge for MNI
pushs fix4sform ${CUT_DIR:-.}/${nii}.nii
done
#save nifti header of 1st dataset, which should have correct mm sform/qform matrix
#then apply to remaining datasets
pops fix4sform nii #save the 1st dataset's header
elog "$nii sform/qform header will be saved"
fslorient -getsform $nii > ${nii}.sform
sform=${nii}.sform; onii=$nii
for((i=$nnii-1;i>0;i--)); do
pops fix4sform nii #pop out in reverse order
elog "fixing $nii header to the sform/qform of $onii"
fslorient -setsform $(cat $sform) $nii
fslorient -copysform2qform $nii
done
fi
else
elog "Failed: $result "
fi
if [[ 0 -eq ${DEBUG:-0} ]]; then
showStack ftmps
eval "tmpf=$(showStack ftmps)"
[[ -z "${tmpf[@]}" ]] || rm ${tmpf[@]}
rm $tmp
else
elog $tmp
fi
Attachment | Size |
---|---|
slib.stack_.sh | 3.32 KB |
- admin's blog
- Log in or register to post comments
- 3145 reads