function out = spm_dartel_import(job)
% Import subjects' data for use with Dartel
% FORMAT spm_dartel_import(job)
% job.matnames  - Names of *_seg_sn.mat files to use
% job.odir      - Output directory
% job.bb        - Bounding box
% job.vox       - Voxel sizes
% job.GM/WM/CSF - Options fo different tissue classes
% job.image     - Options for resliced original image
%
% Rigidly aligned images are generated using info from the seg_sn.mat
% files.  These can be resliced GM, WM or CSF, but also various resliced
% forms of the original image (skull-stripped, bias corrected etc).
%___________________________________________________________________________

% John Ashburner
% Copyright (C) 2006-2022 Wellcome Centre for Human Neuroimaging


matnames = job.matnames;
for i=1:numel(matnames)
    p(i) = load(matnames{i});
end
if numel(p)>0
    tmp = strvcat(p(1).VG.fname);
    p(1).VG = spm_vol(tmp);
    b0  = spm_load_priors(p(1).VG);
end
odir = job.odir{1};
bb   = job.bb;
vox  = job.vox;
iopt = job.image;
opt  = [job.GM, job.WM, job.CSF];
for i=1:numel(p)
    preproc_apply(p(i),odir,b0,bb,vox,iopt,opt,matnames{i});
end

out.cfiles = cell(numel(matnames),numel(opt));
if job.image
    out.files  = cell(numel(matnames),1);
end
for i=1:numel(matnames)
    [pth,nam,ext] = fileparts(matnames{i});
    nam = nam(1:(numel(nam)-7));
    if job.image
        fname = fullfile(odir,['r',nam, '.nii']);
        out.files{i} = fname;
    end
    for k1=1:numel(opt)
        if opt(k1)
            fname            = fullfile(odir,['r','c', num2str(k1), nam, '.nii']);
            out.cfiles{i,k1} = fname;
        end
    end
end


%==========================================================================

%==========================================================================
function preproc_apply(p,odir,b0,bb,vx,iopt,opt,matname)
[pth0,nam,ext,num] = spm_fileparts(matname);
[pth ,nam,ext,num] = spm_fileparts(p.VF(1).fname);
P = path_search([nam,ext],{pth,odir,pwd,pth0});
if isempty(P)
    fprintf('Could not find "%s"\n', [nam,ext]);
    return;
end
p.VF.fname = P;
T    = p.flags.Twarp;
bsol = p.flags.Tbias;
d2   = [size(T) 1];
d    = p.VF.dim(1:3);

[x1,x2,o] = ndgrid(1:d(1),1:d(2),1);
x3  = 1:d(3);
d3  = [size(bsol) 1];
B1  = spm_dctmtx(d(1),d2(1));
B2  = spm_dctmtx(d(2),d2(2));
B3  = spm_dctmtx(d(3),d2(3));
bB3 = spm_dctmtx(d(3),d3(3),x3);
bB2 = spm_dctmtx(d(2),d3(2),x2(1,:)');
bB1 = spm_dctmtx(d(1),d3(1),x1(:,1));

mg  = p.flags.mg;
mn  = p.flags.mn;
vr  = p.flags.vr;
K   = length(p.flags.mg);
Kb  = length(p.flags.ngaus);

lkp = []; for k=1:Kb, lkp = [lkp ones(1,p.flags.ngaus(k))*k]; end

spm_progress_bar('init',length(x3),['Working on ' nam],'Planes completed');
M = p.VG(1).mat\p.flags.Affine*p.VF.mat;

if iopt, idat = zeros(d(1:3),'single'); end
dat = {zeros(d(1:3),'uint8'),zeros(d(1:3),'uint8'),zeros(d(1:3),'uint8')};

for z=1:length(x3)

    % Bias corrected image
    f          = spm_sample_vol(p.VF,x1,x2,o*x3(z),0);
    msk        = (f==0) | ~isfinite(f);
    if ~isempty(bsol)
        cr     = exp(transf(bB1,bB2,bB3(z,:),bsol)).*f;
    else
        cr     = f;
    end

    if iopt
        if bitand(iopt,2)
            idat(:,:,z) = cr;
        else
            idat(:,:,z) = f;
        end
    end

    [t1,t2,t3] = defs(T,z,B1,B2,B3,x1,x2,x3,M);
    q          = zeros([d(1:2) Kb]);
    bg         = ones(d(1:2));
    bt         = zeros([d(1:2) Kb]);
    for k1=1:Kb
        bt(:,:,k1) = spm_sample_priors(b0{k1},t1,t2,t3,k1==Kb);
    end
    b = zeros([d(1:2) K]);
    for k=1:K
        b(:,:,k) = bt(:,:,lkp(k))*mg(k);
    end
    s = sum(b,3);
    for k=1:K
        p1            = exp((cr-mn(k)).^2/(-2*vr(k)))/sqrt(2*pi*vr(k)+eps);
        q(:,:,lkp(k)) = q(:,:,lkp(k)) + p1.*b(:,:,k)./s;
    end
    sq = sum(q,3)+eps;
    for k1=1:3
        tmp            = q(:,:,k1);
        tmp            = tmp./sq;
        tmp(msk)       = 0;
        dat{k1}(:,:,z) = uint8(round(255 * tmp));
    end
    spm_progress_bar('set',z);
end
spm_progress_bar('clear');

%[dat{1},dat{2},dat{3}] = clean_gwc(dat{1},dat{2},dat{3}, 2);
if iopt
    if bitand(iopt,2)
        nwm = 0;
        swm = 0;
        for z=1:numel(x3)
            nwm = nwm + sum(sum(double(dat{2}(:,:,z))));
            swm = swm + sum(sum(double(dat{2}(:,:,z)).*idat(:,:,z)));
        end
        idat = idat*(double(nwm)/double(swm));
    end
    if bitand(iopt,4)
        for z=1:numel(x3)
           %msk         = double(dat{1}(:,:,z)) ...
           %            + double(dat{2}(:,:,z)) ...
           %        + 0.5*double(dat{3}(:,:,z));
           %msk         = msk<128;
           %tmp         = idat(:,:,z);
           %tmp(msk)    = 0;
           %idat(:,:,z) = tmp;
           wt           = (double(dat{1}(:,:,z))+double(dat{2}(:,:,z)))/255;
           idat(:,:,z)  = idat(:,:,z).*wt;
        end
    end
    for z=1:numel(x3)
        tmp               = idat(:,:,z);
        tmp(~isfinite(double(tmp))) = 0;
        idat(:,:,z)       = tmp;
    end
end

% Sort out bounding box etc
[bb1,vx1] = spm_get_bbox(p.VG(1), 'old');
bb(~isfinite(bb)) = bb1(~isfinite(bb));
if ~isfinite(vx), vx = abs(prod(vx1))^(1/3); end
bb(1,:) = vx*ceil(bb(1,:)/vx);
bb(2,:) = vx*floor(bb(2,:)/vx);

% Figure out the mapping from the volumes to create to the original
mm = [
    bb(1,1) bb(1,2) bb(1,3)
    bb(2,1) bb(1,2) bb(1,3)
    bb(1,1) bb(2,2) bb(1,3)
    bb(2,1) bb(2,2) bb(1,3)
    bb(1,1) bb(1,2) bb(2,3)
    bb(2,1) bb(1,2) bb(2,3)
    bb(1,1) bb(2,2) bb(2,3)
    bb(2,1) bb(2,2) bb(2,3)]';

vx2 = inv(p.VG(1).mat)*[mm ; ones(1,8)];

odim   = abs(round((bb(2,:)-bb(1,:))/vx))+1;
%dimstr = sprintf('%dx%dx%d',odim);
dimstr  = '';

vx1 = [
    1       1       1
    odim(1) 1       1
    1       odim(2) 1
    odim(1) odim(2) 1
    1       1       odim(3)
    odim(1) 1       odim(3)
    1       odim(2) odim(3)
    odim(1) odim(2) odim(3)]';
M      = p.Affine*vx2/[vx1 ; ones(1,8)];
mat0   = p.VF.mat*M;
mat    = [mm ; ones(1,8)]/[vx1 ; ones(1,8)];

fwhm = max(vx./sqrt(sum(p.VF.mat(1:3,1:3).^2))-1,0.01);

for k1=1:numel(opt)
    if opt(k1)
        dat{k1} = decimate(dat{k1},fwhm);
        VT      = struct('fname',fullfile(odir,['r',dimstr,'c', num2str(k1), nam, '.nii']),...
            'dim',  odim,...
            'dt',   [spm_type('uint8') spm_platform('bigend')],...
            'pinfo',[1/255 0]',...
            'mat',mat);
        VT = spm_create_vol(VT);

        Ni             = nifti(VT.fname);
        Ni.mat0        = mat0;
        Ni.mat_intent  = 'Aligned';
        Ni.mat0_intent = 'Aligned';
        create(Ni);

        for i=1:odim(3)
            tmp = spm_slice_vol(dat{k1},M*spm_matrix([0 0 i]),odim(1:2),1)/255;
            VT  = spm_write_plane(VT,tmp,i);
        end
    end
end

if iopt
        %idat = decimate(idat,fwhm);
        VT      = struct('fname',fullfile(odir,['r',dimstr,nam, '.nii']),...
            'dim',  odim,...
            'dt',   [spm_type('float32') spm_platform('bigend')],...
            'pinfo',[1 0]',...
            'mat',mat);
        VT.descrip = 'Resliced';
        if bitand(iopt,2), VT.descrip = [VT.descrip ', bias corrected']; end
        if bitand(iopt,4), VT.descrip = [VT.descrip ', skull stripped']; end

        VT = spm_create_vol(VT);

        Ni             = nifti(VT.fname);
        Ni.mat0        = mat0;
        Ni.mat_intent  = 'Aligned';
        Ni.mat0_intent = 'Aligned';
        create(Ni);

        for i=1:odim(3)
            tmp = spm_slice_vol(idat,M*spm_matrix([0 0 i]),odim(1:2),1);
            VT  = spm_write_plane(VT,tmp,i);
        end
end


%==========================================================================

%==========================================================================
function [x1,y1,z1] = defs(sol,z,B1,B2,B3,x0,y0,z0,M)
x1a = x0    + transf(B1,B2,B3(z,:),sol(:,:,:,1));
y1a = y0    + transf(B1,B2,B3(z,:),sol(:,:,:,2));
z1a = z0(z) + transf(B1,B2,B3(z,:),sol(:,:,:,3));
x1  = M(1,1)*x1a + M(1,2)*y1a + M(1,3)*z1a + M(1,4);
y1  = M(2,1)*x1a + M(2,2)*y1a + M(2,3)*z1a + M(2,4);
z1  = M(3,1)*x1a + M(3,2)*y1a + M(3,3)*z1a + M(3,4);


%==========================================================================

%==========================================================================
function t = transf(B1,B2,B3,T)
d2 = [size(T) 1];
t1 = reshape(reshape(T, d2(1)*d2(2),d2(3))*B3', d2(1), d2(2));
t  = B1*t1*B2';


%==========================================================================

%==========================================================================
function dat = decimate(dat,fwhm)
% Convolve the volume in memory (fwhm in voxels).
lim = ceil(2*fwhm);
s  = fwhm/sqrt(8*log(2));
x  = -lim(1):lim(1); x = spm_smoothkern(fwhm(1),x); x  = x/sum(x);
y  = -lim(2):lim(2); y = spm_smoothkern(fwhm(2),y); y  = y/sum(y);
z  = -lim(3):lim(3); z = spm_smoothkern(fwhm(3),z); z  = z/sum(z);
i  = (length(x) - 1)/2;
j  = (length(y) - 1)/2;
k  = (length(z) - 1)/2;
spm_conv_vol(dat,dat,x,y,z,-[i j k]);


%==========================================================================

%==========================================================================
function [g,w,c] = clean_gwc(g,w,c, level)
if nargin<4, level = 1; end

b    = w;
b(1) = w(1);

% Build a 3x3x3 seperable smoothing kernel
%--------------------------------------------------------------------------
kx=[0.75 1 0.75];
ky=[0.75 1 0.75];
kz=[0.75 1 0.75];
sm=sum(kron(kron(kz,ky),kx))^(1/3);
kx=kx/sm; ky=ky/sm; kz=kz/sm;

th1 = 0.15;
if level==2, th1 = 0.2; end
% Erosions and conditional dilations
%--------------------------------------------------------------------------
niter = 32;
spm_progress_bar('Init',niter,'Extracting Brain','Iterations completed');
for j=1:niter
        if j>2, th=th1; else th=0.6; end % Dilate after two its of erosion.
        for i=1:size(b,3)
                gp = double(g(:,:,i));
                wp = double(w(:,:,i));
                bp = double(b(:,:,i))/255;
                bp = (bp>th).*(wp+gp);
                b(:,:,i) = uint8(round(bp));
        end
        spm_conv_vol(b,b,kx,ky,kz,-[1 1 1]);
        spm_progress_bar('Set',j);
end
th = 0.05;
for i=1:size(b,3)
        gp       = double(g(:,:,i))/255;
        wp       = double(w(:,:,i))/255;
        cp       = double(c(:,:,i))/255;
        bp       = double(b(:,:,i))/255;
        bp       = ((bp>th).*(wp+gp))>th;
        g(:,:,i) = uint8(round(255*gp.*bp./(gp+wp+cp+eps)));
        w(:,:,i) = uint8(round(255*wp.*bp./(gp+wp+cp+eps)));
        c(:,:,i) = uint8(round(255*(cp.*bp./(gp+wp+cp+eps)+cp.*(1-bp))));
end
spm_progress_bar('Clear');


%==========================================================================

%==========================================================================
function pthnam = path_search(nam,pth)
pthnam = '';
for i=1:numel(pth)
    if exist(fullfile(pth{i},nam),'file')
        pthnam = fullfile(pth{i},nam);
        return;
    end
end
