|
| 1 | +function nii=jnii2nii(jnii, varargin) |
| 2 | +% |
| 3 | +% nii=jnii2nii(jnii) |
| 4 | +% or |
| 5 | +% nii=jnii2nii(jniifile) |
| 6 | +% jnii2nii(jniifile, niifile) |
| 7 | +% |
| 8 | +% Covert a JNIfTI file or data structure to a NIfTI-1/2 structure or file |
| 9 | +% |
| 10 | +% This function is compatible with both MATLAB and GNU Octave. |
| 11 | +% It accepts .jnii and .bnii input files |
| 12 | +% |
| 13 | +% author: Qianqian Fang (q.fang <at> neu.edu) |
| 14 | +% |
| 15 | +% input: |
| 16 | +% jnii: a JNIfTI data structure (a struct with NIFTIHeader and NIFTIData fields); |
| 17 | +% if jnii is a string, it represents a JNIfTI file (.jnii/.bnii) |
| 18 | +% niifile: if the 2nd parameter is given as a file name, the converted nifti data |
| 19 | +% will be save as a nii file with filename specified by niifile. |
| 20 | +% if the filename in niifile contains .gz, the file will be compressed using |
| 21 | +% the zmat toolbox. |
| 22 | +% |
| 23 | +% output: |
| 24 | +% nii: is the converted nifti-1/2 data structure, it contains the below subfields |
| 25 | +% nii.img: the data volume read from the nii file |
| 26 | +% nii.hdr: extended raw file header, a structure that is byte-wise compatible with a |
| 27 | +% nifti-1 - in this case, typecast(nii.hdr,'uint8') must be 348+4=352 bytes, |
| 28 | +% including the raw nifti-1 hdr header (348 bytes) plus the 4-byte |
| 29 | +% extension flags), or |
| 30 | +% nifti-2 - in this case, typecast(nii.hdr,'uint8') must be 540+4=544 bytes, |
| 31 | +% including the raw nifti-2 hdr header (540 bytes) plus the 4-byte |
| 32 | +% extension flags) |
| 33 | +% if one run nii.hdr.extension=[]; the resulting struct is 348/540-byte in length |
| 34 | +% nii.hdr key subfileds include |
| 35 | +% |
| 36 | +% sizeof_hdr: must be 348 (for NIFTI-1) or 540 (for NIFTI-2) |
| 37 | +% dim: short array, dim(2: dim(1)+1) defines the array size |
| 38 | +% datatype: the type of data stored in each voxel |
| 39 | +% bitpix: total bits per voxel |
| 40 | +% magic: must be 'ni1\0' or 'n+1\0' for NIFTI-1 data, and 'ni2\0' or 'n+2\0' for NIFTI-2 data |
| 41 | +% |
| 42 | +% For the detailed nii header, please see |
| 43 | +% https://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1.h |
| 44 | +% |
| 45 | +% dependency: |
| 46 | +% |
| 47 | +% To load a JNIfTI file with compression or niifile ends with (.nii.gz/.hdr.gz/.img.gz), |
| 48 | +% one must install the ZMat Toolbox (http://github.com/fangq/zmat) and |
| 49 | +% JSONLab Toolbox (http://github.com/fangq/jsonlab); |
| 50 | +% |
| 51 | +% this file is part of JNIfTI specification: https://github.com/fangq/jnifti |
| 52 | +% |
| 53 | +% License: Apache 2.0, see https://github.com/fangq/jnifti for details |
| 54 | +% |
| 55 | + |
| 56 | +if(nargin<=0) |
| 57 | + help jnii2nii |
| 58 | + return; |
| 59 | +end |
| 60 | + |
| 61 | +if(~isstruct(jnii)) |
| 62 | + jnii=loadjnifti(jnii); |
| 63 | +end |
| 64 | + |
| 65 | +if(~(isfield(jnii,'NIFTIHeader') && isfield(jnii,'NIFTIData'))) |
| 66 | + error('input must be a valid JNIfTI structure (needs both NIFTIHeader and NIFTIData subfields)'); |
| 67 | +end |
| 68 | + |
| 69 | +niiformat='nifti1'; |
| 70 | + |
| 71 | +if((isfield(jnii.NIFTIHeader,'NIIFormat') && ismember(jnii.NIFTIHeader.NIIFormat(1:3),{'ni2','n+2'})) || max(jnii.NIFTIHeader.Dim)>=2^32) |
| 72 | + niiformat='nifti2'; |
| 73 | +end |
| 74 | + |
| 75 | +nii.hdr=nifticreate(jnii.NIFTIData, niiformat); |
| 76 | +nii.img=jnii.NIFTIData; |
| 77 | + |
| 78 | +if(isfield(jnii.NIFTIHeader,'NIIHeaderSize')) |
| 79 | + nii.hdr.sizeof_hdr =bytematch(jnii.NIFTIHeader, 'NIIHeaderSize', nii.hdr.sizeof_hdr); |
| 80 | +end |
| 81 | +if(isfield(nii.hdr,'data_type')) |
| 82 | + nii.hdr.data_type =bytematch(jnii.NIFTIHeader, 'A75DataTypeName', nii.hdr.data_type); |
| 83 | + nii.hdr.db_name =bytematch(jnii.NIFTIHeader, 'A75DBName', nii.hdr.db_name); |
| 84 | + nii.hdr.extents =bytematch(jnii.NIFTIHeader, 'A75Extends', nii.hdr.extents); |
| 85 | + nii.hdr.session_error =bytematch(jnii.NIFTIHeader, 'A75SessionError', nii.hdr.session_error); |
| 86 | + nii.hdr.regular =bytematch(jnii.NIFTIHeader, 'A75Regular', nii.hdr.regular); |
| 87 | +end |
| 88 | + |
| 89 | +dim_info=bitor(uint8(jnii.NIFTIHeader.DimInfo.Freq),bitshift(uint8(jnii.NIFTIHeader.DimInfo.Phase),3)); |
| 90 | +dim_info=bitor(dim_info,bitshift(uint8(jnii.NIFTIHeader.DimInfo.Slice),6)); |
| 91 | +nii.hdr.dim_info=cast(dim_info, class(nii.hdr.dim_info)); |
| 92 | + |
| 93 | +nii.hdr.dim(1)=cast(length(jnii.NIFTIHeader.Dim),class(nii.hdr.dim)); |
| 94 | +nii.hdr.dim(2:1+length(jnii.NIFTIHeader.Dim)) =bytematch(jnii.NIFTIHeader, 'Dim', nii.hdr.dim(2:1+length(jnii.NIFTIHeader.Dim))); |
| 95 | +nii.hdr.intent_p1 =bytematch(jnii.NIFTIHeader, 'Param1', nii.hdr.intent_p1); |
| 96 | +nii.hdr.intent_p2 =bytematch(jnii.NIFTIHeader, 'Param2', nii.hdr.intent_p2); |
| 97 | +nii.hdr.intent_p3 =bytematch(jnii.NIFTIHeader, 'Param3', nii.hdr.intent_p3); |
| 98 | + |
| 99 | +if(ischar(jnii.NIFTIHeader.Intent)) |
| 100 | + jnii.NIFTIHeader.Intent=niicodemap('intent',jnii.NIFTIHeader.Intent); |
| 101 | +end |
| 102 | +nii.hdr.intent_code =bytematch(jnii.NIFTIHeader, 'Intent', nii.hdr.intent_code); |
| 103 | +if(ischar(jnii.NIFTIHeader.DataType)) |
| 104 | + jnii.NIFTIHeader.DataType=niicodemap('datatype',jnii.NIFTIHeader.DataType); |
| 105 | +end |
| 106 | + |
| 107 | +nii.hdr.datatype =bytematch(jnii.NIFTIHeader, 'DataType', nii.hdr.datatype); |
| 108 | +nii.hdr.bitpix =bytematch(jnii.NIFTIHeader, 'BitDepth', nii.hdr.bitpix); |
| 109 | +nii.hdr.slice_start =bytematch(jnii.NIFTIHeader, 'FirstSliceID', nii.hdr.slice_start); |
| 110 | +nii.hdr.pixdim(1)=cast(length(jnii.NIFTIHeader.VoxelSize),class(nii.hdr.pixdim)); |
| 111 | +nii.hdr.pixdim(2:2+nii.hdr.dim(1)-1) =bytematch(jnii.NIFTIHeader, 'VoxelSize', nii.hdr.pixdim(2:2+nii.hdr.dim(1)-1)); |
| 112 | +nii.hdr.vox_offset =bytematch(jnii.NIFTIHeader, 'NIIByteOffset', nii.hdr.vox_offset); |
| 113 | +nii.hdr.scl_slope =bytematch(jnii.NIFTIHeader, 'ScaleSlope', nii.hdr.scl_slope); |
| 114 | +nii.hdr.scl_inter =bytematch(jnii.NIFTIHeader, 'ScaleOffset', nii.hdr.scl_inter); |
| 115 | +nii.hdr.slice_end =bytematch(jnii.NIFTIHeader, 'LastSliceID', nii.hdr.slice_end); |
| 116 | + |
| 117 | +if(ischar(jnii.NIFTIHeader.SliceType)) |
| 118 | + jnii.NIFTIHeader.SliceType=niicodemap('slicetype',jnii.NIFTIHeader.SliceType); |
| 119 | +end |
| 120 | +nii.hdr.slice_code =bytematch(jnii.NIFTIHeader, 'SliceType', nii.hdr.slice_code); |
| 121 | +if(ischar(jnii.NIFTIHeader.Unit.L)) |
| 122 | + jnii.NIFTIHeader.Unit.L=niicodemap('unit',jnii.NIFTIHeader.Unit.L); |
| 123 | +end |
| 124 | +if(ischar(jnii.NIFTIHeader.Unit.T)) |
| 125 | + jnii.NIFTIHeader.Unit.T=niicodemap('unit',jnii.NIFTIHeader.Unit.T); |
| 126 | +end |
| 127 | + |
| 128 | +xyzt_units=bitor(uint8(jnii.NIFTIHeader.Unit.L),uint8(jnii.NIFTIHeader.Unit.T)); |
| 129 | +nii.hdr.xyzt_units=cast(xyzt_units, class(nii.hdr.xyzt_units)); |
| 130 | + |
| 131 | +nii.hdr.cal_max =bytematch(jnii.NIFTIHeader, 'MaxIntensity', nii.hdr.cal_max); |
| 132 | +nii.hdr.cal_min =bytematch(jnii.NIFTIHeader, 'MinIntensity', nii.hdr.cal_min); |
| 133 | +nii.hdr.slice_duration =bytematch(jnii.NIFTIHeader, 'SliceTime', nii.hdr.slice_duration); |
| 134 | +nii.hdr.toffset =bytematch(jnii.NIFTIHeader, 'TimeOffset', nii.hdr.toffset); |
| 135 | +if(isfield(nii.hdr,'glmax')) |
| 136 | + nii.hdr.glmax =bytematch(jnii.NIFTIHeader, 'A75GlobalMax', nii.hdr.glmax); |
| 137 | + nii.hdr.glmin =bytematch(jnii.NIFTIHeader, 'A75GlobalMin', nii.hdr.glmin); |
| 138 | +end |
| 139 | + |
| 140 | +nii.hdr.descrip =bytematch(jnii.NIFTIHeader, 'Description', nii.hdr.descrip); |
| 141 | +nii.hdr.aux_file =bytematch(jnii.NIFTIHeader, 'AuxFile', nii.hdr.aux_file); |
| 142 | + |
| 143 | +nii.hdr.qform_code =bytematch(jnii.NIFTIHeader, 'QForm', nii.hdr.qform_code); |
| 144 | +nii.hdr.sform_code =bytematch(jnii.NIFTIHeader, 'SForm', nii.hdr.sform_code); |
| 145 | +nii.hdr.quatern_b =bytematch(jnii.NIFTIHeader, 'Quatern.b', nii.hdr.quatern_b); |
| 146 | +nii.hdr.quatern_c =bytematch(jnii.NIFTIHeader, 'Quatern.c', nii.hdr.quatern_c); |
| 147 | +nii.hdr.quatern_d =bytematch(jnii.NIFTIHeader, 'Quatern.d', nii.hdr.quatern_d); |
| 148 | +nii.hdr.qoffset_x =bytematch(jnii.NIFTIHeader, 'QuaternOffset.x', nii.hdr.qoffset_x); |
| 149 | +nii.hdr.qoffset_y =bytematch(jnii.NIFTIHeader, 'QuaternOffset.y', nii.hdr.qoffset_y); |
| 150 | +nii.hdr.qoffset_z =bytematch(jnii.NIFTIHeader, 'QuaternOffset.z', nii.hdr.qoffset_z); |
| 151 | +nii.hdr.srow_x =cast(jnii.NIFTIHeader.Affine(1,:), class(nii.hdr.srow_x)); |
| 152 | +nii.hdr.srow_y =cast(jnii.NIFTIHeader.Affine(2,:), class(nii.hdr.srow_y)); |
| 153 | +nii.hdr.srow_z =cast(jnii.NIFTIHeader.Affine(3,:), class(nii.hdr.srow_z)); |
| 154 | + |
| 155 | +nii.hdr.intent_name =bytematch(jnii.NIFTIHeader, 'Name', nii.hdr.intent_name); |
| 156 | +%nii.hdr.magic =bytematch(jnii.NIFTIHeader, 'NIIFormat', nii.hdr.magic); |
| 157 | + |
| 158 | +if(isfield(jnii.NIFTIHeader,'NIIExtender')) |
| 159 | + nii.hdr.extension =bytematch(jnii.NIFTIHeader, 'NIIExtender', nii.hdr.extension); |
| 160 | +end |
| 161 | +if(isfield(jnii.NIFTIHeader,'NIIQfac_')) |
| 162 | + nii.hdr.pixdim(1) =bytematch(jnii.NIFTIHeader, 'NIIQfac_', nii.hdr.pixdim(1)); |
| 163 | +end |
| 164 | +if(isfield(jnii.NIFTIHeader,'NIIUnused_')) |
| 165 | + nii.hdr.reserved =bytematch(jnii.NIFTIHeader, 'NIIUnused_', nii.hdr.reserved); |
| 166 | +end |
| 167 | + |
| 168 | +if(isfield(jnii,'NIFTIExtension') && iscell(jnii.NIFTIExtension)) |
| 169 | + nii.extension=jnii.NIFTIExtension; |
| 170 | + if(nii.hdr.extension(1)~=length(jnii.NIFTIExtension)) |
| 171 | + nii.hdr.extension(1)=length(jnii.NIFTIExtension); |
| 172 | + warning('header extension count does not match the extension data, force update'); |
| 173 | + end |
| 174 | +end |
| 175 | + |
| 176 | +if(nargin>=2 && ischar(varargin{1})) |
| 177 | + savenifti(nii.img, varargin{1}, nii.hdr); |
| 178 | +end |
| 179 | + |
| 180 | +%--------------------------------------------------------------------------- |
| 181 | + |
| 182 | +function dat=bytematch(jobj, key, orig) |
| 183 | +dtype=class(orig); |
| 184 | +dat=orig; |
| 185 | +if(isfield(jobj,key)) |
| 186 | + dat=cast(jobj.(key),dtype); |
| 187 | +else |
| 188 | + dat=cast(0,dtype); |
| 189 | +end |
| 190 | +if(length(dat)<length(orig)) |
| 191 | + dat(length(orig))=cast(0,dtype); |
| 192 | +end |
| 193 | +dat=dat(1:length(orig)); |
0 commit comments