📄 xform_nii.m
字号:
% internal function
% 'xform_nii.m' is an internal function called by "load_nii.m", so
% you do not need run this program by yourself. It does simplified
% NIfTI sform/qform affine transform, and supports some of the
% affine transforms, including translation, reflection, and
% orthogonal rotation (N*90 degree).
%
% For other affine transforms, e.g. any degree rotation, shearing
% etc. you will have to use the included 'reslice_nii.m' program
% to reslice the image volume. 'reslice_nii.m' is not called by
% any other program, and you have to run 'reslice_nii.m' explicitly
% for those NIfTI files that you want to reslice them.
%
% Since 'xform_nii.m' does not involve any interpolation or any
% slice change, the original image volume is supposed to be
% untouched, although it is translated, reflected, or even
% orthogonally rotated, based on the affine matrix in the
% NIfTI header.
%
% However, the affine matrix in the header of a lot NIfTI files
% contain slightly non-orthogonal rotation. Therefore, optional
% input parameter 'tolerance' is used to allow some distortion
% in the loaded image for any non-orthogonal rotation or shearing
% of NIfTI affine matrix. If you set 'tolerance' to 0, it means
% that you do not allow any distortion. If you set 'tolerance' to
% 1, it means that you do not care any distortion. The image will
% fail to be loaded if it can not be tolerated. The tolerance will
% be set to 0.1 (10%), if it is default or empty.
%
% Because 'reslice_nii.m' has to perform 3D interpolation, it can
% be slow depending on image size and affine matrix in the header.
%
% After you perform the affine transform, the 'nii' structure
% generated from 'xform_nii.m' or new NIfTI file created from
% 'reslice_nii.m' will be in RAS orientation, i.e. X axis from
% Left to Right, Y axis from Posterior to Anterior, and Z axis
% from Inferior to Superior.
%
% NOTE: This function should be called immediately after load_nii.
%
% Usage: [ nii ] = xform_nii(nii, [tolerance], [preferredForm])
%
% nii - NIFTI structure (returned from load_nii)
%
% tolerance (optional) - distortion allowed for non-orthogonal rotation
% or shearing in NIfTI affine matrix. It will be set to 0.1 (10%),
% if it is default or empty.
%
% preferredForm (optional) - selects which transformation from voxels
% to RAS coordinates; values are s,q,S,Q. Lower case s,q indicate
% "prefer sform or qform, but use others if preferred not present".
% Upper case indicate the program is forced to use the specificied
% tranform or fail loading. 'preferredForm' will be 's', if it is
% default or empty. - Jeff Gunter
%
% NIFTI data format can be found on: http://nifti.nimh.nih.gov
%
% - Jimmy Shen (jimmy@rotman-baycrest.on.ca)
%
function nii = xform_nii(nii, tolerance, preferredForm)
% save a copy of the header as it was loaded. This is the
% header before any sform, qform manipulation is done.
%
nii.original.hdr = nii.hdr;
if ~exist('tolerance','var') | isempty(tolerance)
tolerance = 0.1;
elseif(tolerance<=0)
tolerance = eps;
end
if ~exist('preferredForm','var') | isempty(preferredForm)
preferredForm= 's'; % Jeff
end
% if scl_slope field is nonzero, then each voxel value in the
% dataset should be scaled as: y = scl_slope * x + scl_inter
% I bring it here because hdr will be modified by change_hdr.
%
if nii.hdr.dime.scl_slope ~= 0 & ...
ismember(nii.hdr.dime.datatype, [2,4,8,16,64,256,512,768]) & ...
(nii.hdr.dime.scl_slope ~= 1 | nii.hdr.dime.scl_inter ~= 0)
nii.img = ...
nii.hdr.dime.scl_slope * double(nii.img) + nii.hdr.dime.scl_inter;
if nii.hdr.dime.datatype == 64
nii.hdr.dime.datatype = 64;
nii.hdr.dime.bitpix = 64;
else
nii.img = single(nii.img);
nii.hdr.dime.datatype = 16;
nii.hdr.dime.bitpix = 32;
end
nii.hdr.dime.glmax = max(double(nii.img(:)));
nii.hdr.dime.glmin = min(double(nii.img(:)));
% set scale to non-use, because it is applied in xform_nii
%
nii.hdr.dime.scl_slope = 0;
end
% However, the scaling is to be ignored if datatype is DT_RGB24.
% If datatype is a complex type, then the scaling is to be applied
% to both the real and imaginary parts.
%
if nii.hdr.dime.scl_slope ~= 0 & ...
ismember(nii.hdr.dime.datatype, [32,1792])
nii.img = ...
nii.hdr.dime.scl_slope * double(nii.img) + nii.hdr.dime.scl_inter;
if nii.hdr.dime.datatype == 32
nii.img = single(nii.img);
end
nii.hdr.dime.glmax = max(double(nii.img(:)));
nii.hdr.dime.glmin = min(double(nii.img(:)));
% set scale to non-use, because it is applied in xform_nii
%
nii.hdr.dime.scl_slope = 0;
end
% There is no need for this program to transform Analyze data
%
if nii.filetype == 0 & exist([nii.fileprefix '.mat'],'file')
load([nii.fileprefix '.mat']); % old SPM affine matrix
R=M(1:3,1:3);
T=M(1:3,4);
T=R*ones(3,1)+T;
M(1:3,4)=T;
nii.hdr.hist.qform_code=0;
nii.hdr.hist.sform_code=1;
nii.hdr.hist.srow_x=M(1,:);
nii.hdr.hist.srow_y=M(2,:);
nii.hdr.hist.srow_z=M(3,:);
elseif nii.filetype == 0
nii.hdr.hist.rot_orient = [];
nii.hdr.hist.flip_orient = [];
return; % no sform/qform for Analyze format
end
hdr = nii.hdr;
[hdr,orient]=change_hdr(hdr,tolerance,preferredForm);
% flip and/or rotate image data
%
if ~isequal(orient, [1 2 3])
old_dim = hdr.dime.dim([2:4]);
% More than 1 time frame
%
if ndims(nii.img) > 3
pattern = 1:prod(old_dim);
else
pattern = [];
end
if ~isempty(pattern)
pattern = reshape(pattern, old_dim);
end
% calculate for rotation after flip
%
rot_orient = mod(orient + 2, 3) + 1;
% do flip:
%
flip_orient = orient - rot_orient;
for i = 1:3
if flip_orient(i)
if ~isempty(pattern)
pattern = flipdim(pattern, i);
else
nii.img = flipdim(nii.img, i);
end
end
end
% get index of orient (rotate inversely)
%
[tmp rot_orient] = sort(rot_orient);
new_dim = old_dim;
new_dim = new_dim(rot_orient);
hdr.dime.dim([2:4]) = new_dim;
new_pixdim = hdr.dime.pixdim([2:4]);
new_pixdim = new_pixdim(rot_orient);
hdr.dime.pixdim([2:4]) = new_pixdim;
% re-calculate originator
%
tmp = hdr.hist.originator([1:3]);
tmp = tmp(rot_orient);
flip_orient = flip_orient(rot_orient);
for i = 1:3
if flip_orient(i) & ~isequal(tmp(i), 0)
tmp(i) = new_dim(i) - tmp(i) + 1;
end
end
hdr.hist.originator([1:3]) = tmp;
hdr.hist.rot_orient = rot_orient;
hdr.hist.flip_orient = flip_orient;
% do rotation:
%
if ~isempty(pattern)
pattern = permute(pattern, rot_orient);
pattern = pattern(:);
nii.img = reshape(nii.img, [prod(new_dim) hdr.dime.dim(5:8)]);
nii.img = nii.img(pattern, :);
nii.img = reshape(nii.img, [new_dim hdr.dime.dim(5:8)]);
else
nii.img = permute(nii.img, rot_orient);
end
else
hdr.hist.rot_orient = [];
hdr.hist.flip_orient = [];
end
nii.hdr = hdr;
return; % xform_nii
%-----------------------------------------------------------------------
function [hdr, orient] = change_hdr(hdr, tolerance, preferredForm)
orient = [1 2 3];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -