-
Notifications
You must be signed in to change notification settings - Fork 2
/
jnii2nii.m
193 lines (171 loc) · 8.97 KB
/
jnii2nii.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
function nii = jnii2nii(jnii, varargin)
%
% nii=jnii2nii(jnii)
% or
% nii=jnii2nii(jniifile)
% jnii2nii(jniifile, niifile)
%
% Covert a JNIfTI file or data structure to a NIfTI-1/2 structure or file
%
% This function is compatible with both MATLAB and GNU Octave.
% It accepts .jnii and .bnii input files
%
% author: Qianqian Fang (q.fang <at> neu.edu)
%
% input:
% jnii: a JNIfTI data structure (a struct with NIFTIHeader and NIFTIData fields);
% if jnii is a string, it represents a JNIfTI file (.jnii/.bnii)
% niifile: if the 2nd parameter is given as a file name, the converted nifti data
% will be save as a nii file with filename specified by niifile.
% if the filename in niifile contains .gz, the file will be compressed using
% the zmat toolbox.
%
% output:
% nii: is the converted nifti-1/2 data structure, it contains the below subfields
% nii.img: the data volume read from the nii file
% nii.hdr: extended raw file header, a structure that is byte-wise compatible with a
% nifti-1 - in this case, typecast(nii.hdr,'uint8') must be 348+4=352 bytes,
% including the raw nifti-1 hdr header (348 bytes) plus the 4-byte
% extension flags), or
% nifti-2 - in this case, typecast(nii.hdr,'uint8') must be 540+4=544 bytes,
% including the raw nifti-2 hdr header (540 bytes) plus the 4-byte
% extension flags)
% if one run nii.hdr.extension=[]; the resulting struct is 348/540-byte in length
% nii.hdr key subfileds include
%
% sizeof_hdr: must be 348 (for NIFTI-1) or 540 (for NIFTI-2)
% dim: short array, dim(2: dim(1)+1) defines the array size
% datatype: the type of data stored in each voxel
% bitpix: total bits per voxel
% magic: must be 'ni1\0' or 'n+1\0' for NIFTI-1 data, and 'ni2\0' or 'n+2\0' for NIFTI-2 data
%
% For the detailed nii header, please see
% https://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1.h
%
% dependency:
%
% To load a JNIfTI file with compression or niifile ends with (.nii.gz/.hdr.gz/.img.gz),
% one must install the ZMat Toolbox (http://github.com/NeuroJSON/zmat) and
% JSONLab Toolbox (http://github.com/NeuroJSON/jsonlab);
%
% this file is part of JNIfTI specification: https://github.com/NeuroJSON/jnifti
%
% License: Apache 2.0, see https://github.com/NeuroJSON/jnifti for details
%
if (nargin <= 0)
help jnii2nii;
return
end
if (~isstruct(jnii))
jnii = loadjnifti(jnii);
end
if (~(isfield(jnii, 'NIFTIHeader') && isfield(jnii, 'NIFTIData')))
error('input must be a valid JNIfTI structure (needs both NIFTIHeader and NIFTIData subfields)');
end
niiformat = 'nifti1';
if ((isfield(jnii.NIFTIHeader, 'NIIFormat') && ismember(jnii.NIFTIHeader.NIIFormat(1:3), {'ni2', 'n+2'})) || max(jnii.NIFTIHeader.Dim) >= 2^32)
niiformat = 'nifti2';
end
nii.hdr = nifticreate(jnii.NIFTIData, niiformat);
nii.img = jnii.NIFTIData;
if (isfield(jnii.NIFTIHeader, 'NIIHeaderSize'))
nii.hdr.sizeof_hdr = bytematch(jnii.NIFTIHeader, 'NIIHeaderSize', nii.hdr.sizeof_hdr);
end
if (isfield(nii.hdr, 'data_type'))
nii.hdr.data_type = bytematch(jnii.NIFTIHeader, 'A75DataTypeName', nii.hdr.data_type);
nii.hdr.db_name = bytematch(jnii.NIFTIHeader, 'A75DBName', nii.hdr.db_name);
nii.hdr.extents = bytematch(jnii.NIFTIHeader, 'A75Extends', nii.hdr.extents);
nii.hdr.session_error = bytematch(jnii.NIFTIHeader, 'A75SessionError', nii.hdr.session_error);
nii.hdr.regular = bytematch(jnii.NIFTIHeader, 'A75Regular', nii.hdr.regular);
end
dim_info = bitor(uint8(jnii.NIFTIHeader.DimInfo.Freq), bitshift(uint8(jnii.NIFTIHeader.DimInfo.Phase), 3));
dim_info = bitor(dim_info, bitshift(uint8(jnii.NIFTIHeader.DimInfo.Slice), 6));
nii.hdr.dim_info = cast(dim_info, class(nii.hdr.dim_info));
nii.hdr.dim(1) = cast(length(jnii.NIFTIHeader.Dim), class(nii.hdr.dim));
nii.hdr.dim(2:1 + length(jnii.NIFTIHeader.Dim)) = bytematch(jnii.NIFTIHeader, 'Dim', nii.hdr.dim(2:1 + length(jnii.NIFTIHeader.Dim)));
nii.hdr.intent_p1 = bytematch(jnii.NIFTIHeader, 'Param1', nii.hdr.intent_p1);
nii.hdr.intent_p2 = bytematch(jnii.NIFTIHeader, 'Param2', nii.hdr.intent_p2);
nii.hdr.intent_p3 = bytematch(jnii.NIFTIHeader, 'Param3', nii.hdr.intent_p3);
if (ischar(jnii.NIFTIHeader.Intent))
jnii.NIFTIHeader.Intent = niicodemap('intent', jnii.NIFTIHeader.Intent);
end
nii.hdr.intent_code = bytematch(jnii.NIFTIHeader, 'Intent', nii.hdr.intent_code);
if (ischar(jnii.NIFTIHeader.DataType))
jnii.NIFTIHeader.DataType = niicodemap('datatype', jnii.NIFTIHeader.DataType);
end
nii.hdr.datatype = bytematch(jnii.NIFTIHeader, 'DataType', nii.hdr.datatype);
nii.hdr.bitpix = bytematch(jnii.NIFTIHeader, 'BitDepth', nii.hdr.bitpix);
nii.hdr.slice_start = bytematch(jnii.NIFTIHeader, 'FirstSliceID', nii.hdr.slice_start);
nii.hdr.pixdim(1) = cast(length(jnii.NIFTIHeader.VoxelSize), class(nii.hdr.pixdim));
nii.hdr.pixdim(2:2 + nii.hdr.dim(1) - 1) = bytematch(jnii.NIFTIHeader, 'VoxelSize', nii.hdr.pixdim(2:2 + nii.hdr.dim(1) - 1));
nii.hdr.vox_offset = bytematch(jnii.NIFTIHeader, 'NIIByteOffset', nii.hdr.vox_offset);
nii.hdr.scl_slope = bytematch(jnii.NIFTIHeader, 'ScaleSlope', nii.hdr.scl_slope);
nii.hdr.scl_inter = bytematch(jnii.NIFTIHeader, 'ScaleOffset', nii.hdr.scl_inter);
nii.hdr.slice_end = bytematch(jnii.NIFTIHeader, 'LastSliceID', nii.hdr.slice_end);
if (ischar(jnii.NIFTIHeader.SliceType))
jnii.NIFTIHeader.SliceType = niicodemap('slicetype', jnii.NIFTIHeader.SliceType);
end
nii.hdr.slice_code = bytematch(jnii.NIFTIHeader, 'SliceType', nii.hdr.slice_code);
if (ischar(jnii.NIFTIHeader.Unit.L))
jnii.NIFTIHeader.Unit.L = niicodemap('unit', jnii.NIFTIHeader.Unit.L);
end
if (ischar(jnii.NIFTIHeader.Unit.T))
jnii.NIFTIHeader.Unit.T = niicodemap('unit', jnii.NIFTIHeader.Unit.T);
end
xyzt_units = bitor(uint8(jnii.NIFTIHeader.Unit.L), uint8(jnii.NIFTIHeader.Unit.T));
nii.hdr.xyzt_units = cast(xyzt_units, class(nii.hdr.xyzt_units));
nii.hdr.cal_max = bytematch(jnii.NIFTIHeader, 'MaxIntensity', nii.hdr.cal_max);
nii.hdr.cal_min = bytematch(jnii.NIFTIHeader, 'MinIntensity', nii.hdr.cal_min);
nii.hdr.slice_duration = bytematch(jnii.NIFTIHeader, 'SliceTime', nii.hdr.slice_duration);
nii.hdr.toffset = bytematch(jnii.NIFTIHeader, 'TimeOffset', nii.hdr.toffset);
if (isfield(nii.hdr, 'glmax'))
nii.hdr.glmax = bytematch(jnii.NIFTIHeader, 'A75GlobalMax', nii.hdr.glmax);
nii.hdr.glmin = bytematch(jnii.NIFTIHeader, 'A75GlobalMin', nii.hdr.glmin);
end
nii.hdr.descrip = bytematch(jnii.NIFTIHeader, 'Description', nii.hdr.descrip);
nii.hdr.aux_file = bytematch(jnii.NIFTIHeader, 'AuxFile', nii.hdr.aux_file);
nii.hdr.qform_code = bytematch(jnii.NIFTIHeader, 'QForm', nii.hdr.qform_code);
nii.hdr.sform_code = bytematch(jnii.NIFTIHeader, 'SForm', nii.hdr.sform_code);
nii.hdr.quatern_b = bytematch(jnii.NIFTIHeader, 'Quatern.b', nii.hdr.quatern_b);
nii.hdr.quatern_c = bytematch(jnii.NIFTIHeader, 'Quatern.c', nii.hdr.quatern_c);
nii.hdr.quatern_d = bytematch(jnii.NIFTIHeader, 'Quatern.d', nii.hdr.quatern_d);
nii.hdr.qoffset_x = bytematch(jnii.NIFTIHeader, 'QuaternOffset.x', nii.hdr.qoffset_x);
nii.hdr.qoffset_y = bytematch(jnii.NIFTIHeader, 'QuaternOffset.y', nii.hdr.qoffset_y);
nii.hdr.qoffset_z = bytematch(jnii.NIFTIHeader, 'QuaternOffset.z', nii.hdr.qoffset_z);
nii.hdr.srow_x = cast(jnii.NIFTIHeader.Affine(1, :), class(nii.hdr.srow_x));
nii.hdr.srow_y = cast(jnii.NIFTIHeader.Affine(2, :), class(nii.hdr.srow_y));
nii.hdr.srow_z = cast(jnii.NIFTIHeader.Affine(3, :), class(nii.hdr.srow_z));
nii.hdr.intent_name = bytematch(jnii.NIFTIHeader, 'Name', nii.hdr.intent_name);
% nii.hdr.magic =bytematch(jnii.NIFTIHeader, 'NIIFormat', nii.hdr.magic);
if (isfield(jnii.NIFTIHeader, 'NIIExtender'))
nii.hdr.extension = bytematch(jnii.NIFTIHeader, 'NIIExtender', nii.hdr.extension);
end
if (isfield(jnii.NIFTIHeader, 'NIIQfac_'))
nii.hdr.pixdim(1) = bytematch(jnii.NIFTIHeader, 'NIIQfac_', nii.hdr.pixdim(1));
end
if (isfield(jnii.NIFTIHeader, 'NIIUnused_'))
nii.hdr.reserved = bytematch(jnii.NIFTIHeader, 'NIIUnused_', nii.hdr.reserved);
end
if (isfield(jnii, 'NIFTIExtension') && iscell(jnii.NIFTIExtension))
nii.extension = jnii.NIFTIExtension;
if (nii.hdr.extension(1) ~= length(jnii.NIFTIExtension))
nii.hdr.extension(1) = length(jnii.NIFTIExtension);
warning('header extension count does not match the extension data, force update');
end
end
if (nargin >= 2 && ischar(varargin{1}))
savenifti(nii.img, varargin{1}, nii.hdr);
end
% ---------------------------------------------------------------------------
function dat = bytematch(jobj, key, orig)
dtype = class(orig);
dat = orig;
if (isfield(jobj, key))
dat = cast(jobj.(key), dtype);
else
dat = cast(0, dtype);
end
if (length(dat) < length(orig))
dat(length(orig)) = cast(0, dtype);
end
dat = dat(1:length(orig));