save_nii.m 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. % Save NIFTI dataset. Support both *.nii and *.hdr/*.img file extension.
  2. % If file extension is not provided, *.hdr/*.img will be used as default.
  3. %
  4. % Usage: save_nii(nii, filename, [old_RGB])
  5. %
  6. % nii.hdr - struct with NIFTI header fields (from load_nii.m or make_nii.m)
  7. %
  8. % nii.img - 3D (or 4D) matrix of NIFTI data.
  9. %
  10. % filename - NIFTI file name.
  11. %
  12. % old_RGB - an optional boolean variable to handle special RGB data
  13. % sequence [R1 R2 ... G1 G2 ... B1 B2 ...] that is used only by
  14. % AnalyzeDirect (Analyze Software). Since both NIfTI and Analyze
  15. % file format use RGB triple [R1 G1 B1 R2 G2 B2 ...] sequentially
  16. % for each voxel, this variable is set to FALSE by default. If you
  17. % would like the saved image only to be opened by AnalyzeDirect
  18. % Software, set old_RGB to TRUE (or 1). It will be set to 0, if it
  19. % is default or empty.
  20. %
  21. % Tip: to change the data type, set nii.hdr.dime.datatype,
  22. % and nii.hdr.dime.bitpix to:
  23. %
  24. % 0 None (Unknown bit per voxel) % DT_NONE, DT_UNKNOWN
  25. % 1 Binary (ubit1, bitpix=1) % DT_BINARY
  26. % 2 Unsigned char (uchar or uint8, bitpix=8) % DT_UINT8, NIFTI_TYPE_UINT8
  27. % 4 Signed short (int16, bitpix=16) % DT_INT16, NIFTI_TYPE_INT16
  28. % 8 Signed integer (int32, bitpix=32) % DT_INT32, NIFTI_TYPE_INT32
  29. % 16 Floating point (single or float32, bitpix=32) % DT_FLOAT32, NIFTI_TYPE_FLOAT32
  30. % 32 Complex, 2 float32 (Use float32, bitpix=64) % DT_COMPLEX64, NIFTI_TYPE_COMPLEX64
  31. % 64 Double precision (double or float64, bitpix=64) % DT_FLOAT64, NIFTI_TYPE_FLOAT64
  32. % 128 uint RGB (Use uint8, bitpix=24) % DT_RGB24, NIFTI_TYPE_RGB24
  33. % 256 Signed char (schar or int8, bitpix=8) % DT_INT8, NIFTI_TYPE_INT8
  34. % 511 Single RGB (Use float32, bitpix=96) % DT_RGB96, NIFTI_TYPE_RGB96
  35. % 512 Unsigned short (uint16, bitpix=16) % DT_UNINT16, NIFTI_TYPE_UNINT16
  36. % 768 Unsigned integer (uint32, bitpix=32) % DT_UNINT32, NIFTI_TYPE_UNINT32
  37. % 1024 Signed long long (int64, bitpix=64) % DT_INT64, NIFTI_TYPE_INT64
  38. % 1280 Unsigned long long (uint64, bitpix=64) % DT_UINT64, NIFTI_TYPE_UINT64
  39. % 1536 Long double, float128 (Unsupported, bitpix=128) % DT_FLOAT128, NIFTI_TYPE_FLOAT128
  40. % 1792 Complex128, 2 float64 (Use float64, bitpix=128) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128
  41. % 2048 Complex256, 2 float128 (Unsupported, bitpix=256) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128
  42. %
  43. % Part of this file is copied and modified from:
  44. % http://www.mathworks.com/matlabcentral/fileexchange/1878-mri-analyze-tools
  45. %
  46. % NIFTI data format can be found on: http://nifti.nimh.nih.gov
  47. %
  48. % - Jimmy Shen (jimmy@rotman-baycrest.on.ca)
  49. % - "old_RGB" related codes in "save_nii.m" are added by Mike Harms (2006.06.28)
  50. %
  51. function save_nii(nii, fileprefix, old_RGB)
  52. if ~exist('nii','var') | isempty(nii) | ~isfield(nii,'hdr') | ...
  53. ~isfield(nii,'img') | ~exist('fileprefix','var') | isempty(fileprefix)
  54. error('Usage: save_nii(nii, filename, [old_RGB])');
  55. end
  56. if isfield(nii,'untouch') & nii.untouch == 1
  57. error('Usage: please use ''save_untouch_nii.m'' for the untouched structure.');
  58. end
  59. if ~exist('old_RGB','var') | isempty(old_RGB)
  60. old_RGB = 0;
  61. end
  62. v = version;
  63. % Check file extension. If .gz, unpack it into temp folder
  64. %
  65. if length(fileprefix) > 2 & strcmp(fileprefix(end-2:end), '.gz')
  66. if ~strcmp(fileprefix(end-6:end), '.img.gz') & ...
  67. ~strcmp(fileprefix(end-6:end), '.hdr.gz') & ...
  68. ~strcmp(fileprefix(end-6:end), '.nii.gz')
  69. error('Please check filename.');
  70. end
  71. if str2num(v(1:3)) < 7.1 | ~usejava('jvm')
  72. error('Please use MATLAB 7.1 (with java) and above, or run gunzip outside MATLAB.');
  73. else
  74. gzFile = 1;
  75. fileprefix = fileprefix(1:end-3);
  76. end
  77. end
  78. filetype = 1;
  79. % Note: fileprefix is actually the filename you want to save
  80. %
  81. if findstr('.nii',fileprefix) & strcmp(fileprefix(end-3:end), '.nii')
  82. filetype = 2;
  83. fileprefix(end-3:end)='';
  84. end
  85. if findstr('.hdr',fileprefix) & strcmp(fileprefix(end-3:end), '.hdr')
  86. fileprefix(end-3:end)='';
  87. end
  88. if findstr('.img',fileprefix) & strcmp(fileprefix(end-3:end), '.img')
  89. fileprefix(end-3:end)='';
  90. end
  91. write_nii(nii, filetype, fileprefix, old_RGB);
  92. % gzip output file if requested
  93. %
  94. if exist('gzFile', 'var')
  95. if filetype == 1
  96. gzip([fileprefix, '.img']);
  97. delete([fileprefix, '.img']);
  98. gzip([fileprefix, '.hdr']);
  99. delete([fileprefix, '.hdr']);
  100. elseif filetype == 2
  101. gzip([fileprefix, '.nii']);
  102. delete([fileprefix, '.nii']);
  103. end;
  104. end;
  105. if filetype == 1
  106. % So earlier versions of SPM can also open it with correct originator
  107. %
  108. M=[[diag(nii.hdr.dime.pixdim(2:4)) -[nii.hdr.hist.originator(1:3).*nii.hdr.dime.pixdim(2:4)]'];[0 0 0 1]];
  109. save([fileprefix '.mat'], 'M');
  110. end
  111. return % save_nii
  112. %-----------------------------------------------------------------------------------
  113. function write_nii(nii, filetype, fileprefix, old_RGB)
  114. hdr = nii.hdr;
  115. if isfield(nii,'ext') & ~isempty(nii.ext)
  116. ext = nii.ext;
  117. [ext, esize_total] = verify_nii_ext(ext);
  118. else
  119. ext = [];
  120. end
  121. switch double(hdr.dime.datatype),
  122. case 1,
  123. hdr.dime.bitpix = int16(1 ); precision = 'ubit1';
  124. case 2,
  125. hdr.dime.bitpix = int16(8 ); precision = 'uint8';
  126. case 4,
  127. hdr.dime.bitpix = int16(16); precision = 'int16';
  128. case 8,
  129. hdr.dime.bitpix = int16(32); precision = 'int32';
  130. case 16,
  131. hdr.dime.bitpix = int16(32); precision = 'float32';
  132. case 32,
  133. hdr.dime.bitpix = int16(64); precision = 'float32';
  134. case 64,
  135. hdr.dime.bitpix = int16(64); precision = 'float64';
  136. case 128,
  137. hdr.dime.bitpix = int16(24); precision = 'uint8';
  138. case 256
  139. hdr.dime.bitpix = int16(8 ); precision = 'int8';
  140. case 511,
  141. hdr.dime.bitpix = int16(96); precision = 'float32';
  142. case 512
  143. hdr.dime.bitpix = int16(16); precision = 'uint16';
  144. case 768
  145. hdr.dime.bitpix = int16(32); precision = 'uint32';
  146. case 1024
  147. hdr.dime.bitpix = int16(64); precision = 'int64';
  148. case 1280
  149. hdr.dime.bitpix = int16(64); precision = 'uint64';
  150. case 1792,
  151. hdr.dime.bitpix = int16(128); precision = 'float64';
  152. otherwise
  153. error('This datatype is not supported');
  154. end
  155. hdr.dime.glmax = round(double(max(nii.img(:))));
  156. hdr.dime.glmin = round(double(min(nii.img(:))));
  157. if filetype == 2
  158. fid = fopen(sprintf('%s.nii',fileprefix),'w');
  159. if fid < 0,
  160. msg = sprintf('Cannot open file %s.nii.',fileprefix);
  161. error(msg);
  162. end
  163. hdr.dime.vox_offset = 352;
  164. if ~isempty(ext)
  165. hdr.dime.vox_offset = hdr.dime.vox_offset + esize_total;
  166. end
  167. hdr.hist.magic = 'n+1';
  168. save_nii_hdr(hdr, fid);
  169. if ~isempty(ext)
  170. save_nii_ext(ext, fid);
  171. end
  172. else
  173. fid = fopen(sprintf('%s.hdr',fileprefix),'w');
  174. if fid < 0,
  175. msg = sprintf('Cannot open file %s.hdr.',fileprefix);
  176. error(msg);
  177. end
  178. hdr.dime.vox_offset = 0;
  179. hdr.hist.magic = 'ni1';
  180. save_nii_hdr(hdr, fid);
  181. if ~isempty(ext)
  182. save_nii_ext(ext, fid);
  183. end
  184. fclose(fid);
  185. fid = fopen(sprintf('%s.img',fileprefix),'w');
  186. end
  187. ScanDim = double(hdr.dime.dim(5)); % t
  188. SliceDim = double(hdr.dime.dim(4)); % z
  189. RowDim = double(hdr.dime.dim(3)); % y
  190. PixelDim = double(hdr.dime.dim(2)); % x
  191. SliceSz = double(hdr.dime.pixdim(4));
  192. RowSz = double(hdr.dime.pixdim(3));
  193. PixelSz = double(hdr.dime.pixdim(2));
  194. x = 1:PixelDim;
  195. if filetype == 2 & isempty(ext)
  196. skip_bytes = double(hdr.dime.vox_offset) - 348;
  197. else
  198. skip_bytes = 0;
  199. end
  200. if double(hdr.dime.datatype) == 128
  201. % RGB planes are expected to be in the 4th dimension of nii.img
  202. %
  203. if(size(nii.img,4)~=3)
  204. error(['The NII structure does not appear to have 3 RGB color planes in the 4th dimension']);
  205. end
  206. if old_RGB
  207. nii.img = permute(nii.img, [1 2 4 3 5 6 7 8]);
  208. else
  209. nii.img = permute(nii.img, [4 1 2 3 5 6 7 8]);
  210. end
  211. end
  212. if double(hdr.dime.datatype) == 511
  213. % RGB planes are expected to be in the 4th dimension of nii.img
  214. %
  215. if(size(nii.img,4)~=3)
  216. error(['The NII structure does not appear to have 3 RGB color planes in the 4th dimension']);
  217. end
  218. if old_RGB
  219. nii.img = permute(nii.img, [1 2 4 3 5 6 7 8]);
  220. else
  221. nii.img = permute(nii.img, [4 1 2 3 5 6 7 8]);
  222. end
  223. end
  224. % For complex float32 or complex float64, voxel values
  225. % include [real, imag]
  226. %
  227. if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792
  228. real_img = real(nii.img(:))';
  229. nii.img = imag(nii.img(:))';
  230. nii.img = [real_img; nii.img];
  231. end
  232. if skip_bytes
  233. fwrite(fid, zeros(1,skip_bytes), 'uint8');
  234. end
  235. fwrite(fid, nii.img, precision);
  236. % fwrite(fid, nii.img, precision, skip_bytes); % error using skip
  237. fclose(fid);
  238. return; % write_nii