cosmo fmri deoblique

function ds_plumb=cosmo_fmri_deoblique(ds)
% de-oblique a dataset
%
% Input:
%     ds                fmri dataset struct
%
% Output:
%
% Example:
%     % start with a simple dataset
%     x=cosmo_synthetic_dataset('size','huge','ntargets',1,'nchunks',1);
%     % make dataset oblique (manually)
%     x.a.vol.mat(1,1)=.8;
%     x.a.vol.mat(2,1)=.6;
%     y=cosmo_fmri_deoblique(x);
%     cosmo_disp(x.a.vol)
%     %|| .mat
%     %||   [ 0.8         0         0        -3
%     %||     0.6         2         0        -3
%     %||       0         0         2        -3
%     %||       0         0         0         1 ]
%     %|| .dim
%     %||   [ 20        17        19 ]
%     %|| .xform
%     %||   'scanner_anat'
%     cosmo_disp(y.a.vol)
%     %|| .mat
%     %||   [ 1         0         0      -3.2
%     %||     0         2         0      -2.4
%     %||     0         0         2        -3
%     %||     0         0         0         1 ]
%     %|| .dim
%     %||   [ 20        17        19 ]
%     %|| .xform
%     %||   'scanner_anat'
%     %
%     % other attributes are unchanged:
%     assert(isequal({x.samples x.fa x.sa x.a.fdim},...
%                    {y.samples y.fa y.sa y.a.fdim}));
%     %
%     % a plump dataset does not change after de-obliqueing
%     z=cosmo_fmri_deoblique(y);
%     isequal(y,z)
%     %|| true
%
% Notes:
%   - Using this function changes the location of the voxels in
%     world-space, that is world coordinates (x, y, z).
%   - This function is intended for AFNI and BrainVoyager, as these
%     programs prefer 'plump' (non-oblique) volumes.
%   - When using this function, it is recommended to inspect the result
%     visually.
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #

% get canonical orthogonal matrix
[unused,rot_ortho]=cosmo_fmri_orientation(ds);
mat=ds.a.vol.mat;


% convert base1 -> base0
mat(1:3,4)=mat(1:3,4)+mat(1:3,1:3)*[1 1 1]';

% use pixel dimension to set non-zero elements
mat_ortho=mat;
pixdim=sqrt(sum(mat(1:3,1:3).^2,1));
mat_ortho(1:3,1:3)=bsxfun(@times,rot_ortho(1:3,1:3),pixdim);

% convert base0 -> base1
mat_ortho(1:3,4)=mat_ortho(1:3,1:3)*-[1 1 1]'+mat_ortho(1:3,4);

% ensure single element in rotation part
assert(all(sum(mat_ortho(:,1:3)~=0,1)==1));
assert(all(sum(mat_ortho(1:3,1:3)~=0,2)==1));

ds_plumb=ds;
ds_plumb.a.vol.mat=mat_ortho;