spm_ecat2nifti.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. function N = spm_ecat2nifti(fname,opts)
  2. % Import ECAT 7 images from CTI PET scanners
  3. % FORMAT N = spm_ecat2nifti(fname)
  4. % fname - name of ECAT file
  5. % opts - options structure
  6. %
  7. % N - NIfTI object (written in current directory)
  8. %__________________________________________________________________________
  9. % Copyright (C) 2005-2015 Wellcome Trust Centre for Neuroimaging
  10. % John Ashburner & Roger Gunn
  11. % $Id: spm_ecat2nifti.m 6315 2015-01-23 17:09:06Z guillaume $
  12. if nargin==1
  13. opts = struct('ext',spm_file_ext);
  14. else
  15. if opts.ext(1) ~= '.', opts.ext = ['.' opts.ext]; end
  16. end
  17. fp = fopen(fname,'r','ieee-be');
  18. if fp == -1,
  19. error(['Can''t open "' fname '".']);
  20. end
  21. mh = ECAT7_mheader(fp);
  22. if ~strcmp(mh.MAGIC_NUMBER,'MATRIX70v') &&...
  23. ~strcmp(mh.MAGIC_NUMBER,'MATRIX71v') &&...
  24. ~strcmp(mh.MAGIC_NUMBER,'MATRIX72v')
  25. fclose(fp);
  26. error(['"' fname '" does not appear to be ECAT 7 format.']);
  27. end
  28. if mh.FILE_TYPE ~= 7
  29. fclose(fp);
  30. error(['"' fname '" does not appear to be an image file.']);
  31. end
  32. list = s7_matlist(fp);
  33. matches = find((list(:,4) == 1) | (list(:,4) == 2));
  34. llist = list(matches,:);
  35. for i=1:size(llist,1)
  36. sh(i) = ECAT7_sheader(fp,llist(i,2));
  37. end
  38. fclose(fp);
  39. for i=1:size(llist,1)
  40. dim = [sh(i).X_DIMENSION sh(i).Y_DIMENSION sh(i).Z_DIMENSION];
  41. dtype = [4 1];
  42. off = 512*llist(i,2);
  43. scale = sh(i).SCALE_FACTOR*mh.ECAT_CALIBRATION_FACTOR;
  44. inter = 0;
  45. dati = file_array(fname,dim,dtype,off,scale,inter);
  46. dircos = diag([-1 -1 -1]);
  47. step = ([sh(i).X_PIXEL_SIZE sh(i).Y_PIXEL_SIZE sh(i).Z_PIXEL_SIZE]*10);
  48. start = -(dim(1:3)'/2).*step';
  49. mat = [[dircos*diag(step) dircos*start] ; [0 0 0 1]];
  50. matnum = sprintf('%.8x',list(i,1));
  51. nam = spm_file(fname,'basename');
  52. fnameo = fullfile(pwd,[nam '_' matnum opts.ext]);
  53. dato = file_array(fnameo,dim,[4 spm_platform('bigend')],0,scale,inter);
  54. N = nifti;
  55. N.dat = dato;
  56. N.mat = mat;
  57. N.mat0 = mat;
  58. N.mat_intent = 'aligned';
  59. N.mat0_intent = 'scanner';
  60. N.descrip = sh(i).ANNOTATION;
  61. N.timing = struct('toffset',sh(i).FRAME_START_TIME/1000,'tspace',sh(i).FRAME_DURATION/1000);
  62. create(N);
  63. for j=1:dim(3)
  64. N.dat(:,:,j) = dati(:,:,j);
  65. end
  66. N.extras = struct('mh',mh,'sh',sh(i));
  67. end
  68. %==========================================================================
  69. % function list = s7_matlist(fp)
  70. %==========================================================================
  71. function list = s7_matlist(fp)
  72. %S7_MATLIST List the available matrixes in an ECAT 7 file.
  73. % LIST = S7_MATLIST(FP) lists the available matrixes
  74. % in the file specified by FP.
  75. %
  76. % Columns in LIST:
  77. % 1 - Matrix identifier.
  78. % 2 - Matrix subheader record number
  79. % 3 - Last record number of matrix data block.
  80. % 4 - Matrix status:
  81. % 1 - exists - rw
  82. % 2 - exists - ro
  83. % 3 - matrix deleted
  84. %
  85. % I believe fp should be opened with:
  86. % fp = fopen(filename,'r','ieee-be');
  87. fseek(fp,512,'bof');
  88. block = fread(fp,128,'int');
  89. if size(block,1) ~= 128
  90. list = [];
  91. return;
  92. end
  93. block = reshape(block,4,32);
  94. list = [];
  95. while block(2,1) ~= 2
  96. if block(1,1)+block(4,1) ~= 31
  97. list = []; return;
  98. end
  99. list = [list block(:,2:32)];
  100. fseek(fp,512*(block(2,1)-1),'bof');
  101. block = fread(fp,128,'int');
  102. if size(block,1) ~= 128, list = []; return; end
  103. block = reshape(block,4,32);
  104. end
  105. list = [list block(:,2:(block(4,1)+1))];
  106. list = list';
  107. %==========================================================================
  108. % function SHEADER=ECAT7_sheader(fid,record)
  109. %==========================================================================
  110. function SHEADER=ECAT7_sheader(fid,record)
  111. %
  112. % Sub header read routine for ECAT 7 image files
  113. %
  114. % Roger Gunn, 260298
  115. off = (record-1)*512;
  116. status = fseek(fid, off,'bof');
  117. data_type = fread(fid,1,'uint16',0);
  118. num_dimensions = fread(fid,1,'uint16',0);
  119. x_dimension = fread(fid,1,'uint16',0);
  120. y_dimension = fread(fid,1,'uint16',0);
  121. z_dimension = fread(fid,1,'uint16',0);
  122. x_offset = fread(fid,1,'float32',0);
  123. y_offset = fread(fid,1,'float32',0);
  124. z_offset = fread(fid,1,'float32',0);
  125. recon_zoom = fread(fid,1,'float32',0);
  126. scale_factor = fread(fid,1,'float32',0);
  127. image_min = fread(fid,1,'int16',0);
  128. image_max = fread(fid,1,'int16',0);
  129. x_pixel_size = fread(fid,1,'float32',0);
  130. y_pixel_size = fread(fid,1,'float32',0);
  131. z_pixel_size = fread(fid,1,'float32',0);
  132. frame_duration = fread(fid,1,'uint32',0);
  133. frame_start_time = fread(fid,1,'uint32',0);
  134. filter_code = fread(fid,1,'uint16',0);
  135. x_resolution = fread(fid,1,'float32',0);
  136. y_resolution = fread(fid,1,'float32',0);
  137. z_resolution = fread(fid,1,'float32',0);
  138. num_r_elements = fread(fid,1,'float32',0);
  139. num_angles = fread(fid,1,'float32',0);
  140. z_rotation_angle = fread(fid,1,'float32',0);
  141. decay_corr_fctr = fread(fid,1,'float32',0);
  142. corrections_applied = fread(fid,1,'uint32',0);
  143. gate_duration = fread(fid,1,'uint32',0);
  144. r_wave_offset = fread(fid,1,'uint32',0);
  145. num_accepted_beats = fread(fid,1,'uint32',0);
  146. filter_cutoff_frequency = fread(fid,1,'float32',0);
  147. filter_resolution = fread(fid,1,'float32',0);
  148. filter_ramp_slope = fread(fid,1,'float32',0);
  149. filter_order = fread(fid,1,'uint16',0);
  150. filter_scatter_fraction = fread(fid,1,'float32',0);
  151. filter_scatter_slope = fread(fid,1,'float32',0);
  152. annotation = fread(fid,40,'char',0);
  153. mt_1_1 = fread(fid,1,'float32',0);
  154. mt_1_2 = fread(fid,1,'float32',0);
  155. mt_1_3 = fread(fid,1,'float32',0);
  156. mt_2_1 = fread(fid,1,'float32',0);
  157. mt_2_2 = fread(fid,1,'float32',0);
  158. mt_2_3 = fread(fid,1,'float32',0);
  159. mt_3_1 = fread(fid,1,'float32',0);
  160. mt_3_2 = fread(fid,1,'float32',0);
  161. mt_3_3 = fread(fid,1,'float32',0);
  162. rfilter_cutoff = fread(fid,1,'float32',0);
  163. rfilter_resolution = fread(fid,1,'float32',0);
  164. rfilter_code = fread(fid,1,'uint16',0);
  165. rfilter_order = fread(fid,1,'uint16',0);
  166. zfilter_cutoff = fread(fid,1,'float32',0);
  167. zfilter_resolution = fread(fid,1,'float32',0);
  168. zfilter_code = fread(fid,1,'uint16',0);
  169. zfilter_order = fread(fid,1,'uint16',0);
  170. mt_4_1 = fread(fid,1,'float32',0);
  171. mt_4_2 = fread(fid,1,'float32',0);
  172. mt_4_3 = fread(fid,1,'float32',0);
  173. scatter_type = fread(fid,1,'uint16',0);
  174. recon_type = fread(fid,1,'uint16',0);
  175. recon_views = fread(fid,1,'uint16',0);
  176. fill = fread(fid,1,'uint16',0);
  177. annotation = deblank(char(annotation.*(annotation>0))');
  178. SHEADER = struct('DATA_TYPE', data_type, ...
  179. 'NUM_DIMENSIONS', num_dimensions, ...
  180. 'X_DIMENSION', x_dimension, ...
  181. 'Y_DIMENSION', y_dimension, ...
  182. 'Z_DIMENSION', z_dimension, ...
  183. 'X_OFFSET', x_offset, ...
  184. 'Y_OFFSET', y_offset, ...
  185. 'Z_OFFSET', z_offset, ...
  186. 'RECON_ZOOM', recon_zoom, ...
  187. 'SCALE_FACTOR', scale_factor, ...
  188. 'IMAGE_MIN', image_min, ...
  189. 'IMAGE_MAX', image_max, ...
  190. 'X_PIXEL_SIZE', x_pixel_size, ...
  191. 'Y_PIXEL_SIZE', y_pixel_size, ...
  192. 'Z_PIXEL_SIZE', z_pixel_size, ...
  193. 'FRAME_DURATION', frame_duration, ...
  194. 'FRAME_START_TIME', frame_start_time, ...
  195. 'FILTER_CODE', filter_code, ...
  196. 'X_RESOLUTION', x_resolution, ...
  197. 'Y_RESOLUTION', y_resolution, ...
  198. 'Z_RESOLUTION', z_resolution, ...
  199. 'NUM_R_ELEMENTS', num_r_elements, ...
  200. 'NUM_ANGLES', num_angles, ...
  201. 'Z_ROTATION_ANGLE', z_rotation_angle, ...
  202. 'DECAY_CORR_FCTR', decay_corr_fctr, ...
  203. 'CORRECTIONS_APPLIED', corrections_applied, ...
  204. 'GATE_DURATION', gate_duration, ...
  205. 'R_WAVE_OFFSET', r_wave_offset, ...
  206. 'NUM_ACCEPTED_BEATS', num_accepted_beats, ...
  207. 'FILTER_CUTOFF_FREQUENCY', filter_cutoff_frequency, ...
  208. 'FILTER_RESOLUTION', filter_resolution, ...
  209. 'FILTER_RAMP_SLOPE', filter_ramp_slope, ...
  210. 'FILTER_ORDER', filter_order, ...
  211. 'FILTER_SCATTER_CORRECTION', filter_scatter_fraction, ...
  212. 'FILTER_SCATTER_SLOPE', filter_scatter_slope, ...
  213. 'ANNOTATION', annotation, ...
  214. 'MT_1_1', mt_1_1, ...
  215. 'MT_1_2', mt_1_2, ...
  216. 'MT_1_3', mt_1_3, ...
  217. 'MT_2_1', mt_2_1, ...
  218. 'MT_2_2', mt_2_2, ...
  219. 'MT_2_3', mt_2_3, ...
  220. 'MT_3_1', mt_3_1, ...
  221. 'MT_3_2', mt_3_2, ...
  222. 'MT_3_3', mt_3_3, ...
  223. 'RFILTER_CUTOFF', rfilter_cutoff, ...
  224. 'RFILTER_RESOLUTION', rfilter_resolution, ...
  225. 'RFILTER_CODE', rfilter_code, ...
  226. 'RFILTER_ORDER', rfilter_order, ...
  227. 'ZFILTER_CUTOFF', zfilter_cutoff, ...
  228. 'ZFILTER_RESOLUTION', zfilter_resolution, ...
  229. 'ZFILTER_CODE', zfilter_code, ...
  230. 'ZFILTER_ORDER', zfilter_order, ...
  231. 'MT_4_1', mt_4_1, ...
  232. 'MT_4_2', mt_4_2, ...
  233. 'MT_4_3', mt_4_3, ...
  234. 'SCATTER_TYPE', scatter_type, ...
  235. 'RECON_TYPE', recon_type, ...
  236. 'RECON_VIEWS', recon_views, ...
  237. 'FILL', fill);
  238. %==========================================================================
  239. % function [MHEADER]=ECAT7_mheader(fid)
  240. %==========================================================================
  241. function [MHEADER]=ECAT7_mheader(fid)
  242. %
  243. % Main header read routine for ECAT 7 image files
  244. %
  245. % Roger Gunn, 260298
  246. status = fseek(fid, 0,'bof');
  247. magic_number = fread(fid,14,'char',0);
  248. original_file_name = fread(fid,32,'char',0);
  249. sw_version = fread(fid,1,'uint16',0);
  250. system_type = fread(fid,1,'uint16',0);
  251. file_type = fread(fid,1,'uint16',0);
  252. serial_number = fread(fid,10,'char',0);
  253. scan_start_time = fread(fid,1,'uint32',0);
  254. isotope_name = fread(fid,8,'char',0);
  255. isotope_halflife = fread(fid,1,'float32',0);
  256. radiopharmaceutical = fread(fid,32,'char',0);
  257. gantry_tilt = fread(fid,1,'float32',0);
  258. gantry_rotation = fread(fid,1,'float32',0);
  259. bed_elevation = fread(fid,1,'float32',0);
  260. intrinsic_tilt = fread(fid,1,'float32',0);
  261. wobble_speed = fread(fid,1,'uint16',0);
  262. transm_source_type = fread(fid,1,'uint16',0);
  263. distance_scanned = fread(fid,1,'float32',0);
  264. transaxial_fov = fread(fid,1,'float32',0);
  265. angular_compression = fread(fid,1,'uint16',0);
  266. coin_samp_mode = fread(fid,1,'uint16',0);
  267. axial_samp_mode = fread(fid,1,'uint16',0);
  268. ecat_calibration_factor = fread(fid,1,'float32',0);
  269. calibration_units = fread(fid,1,'uint16',0);
  270. calibration_units_type = fread(fid,1,'uint16',0);
  271. compression_code = fread(fid,1,'uint16',0);
  272. study_type = fread(fid,12,'char',0);
  273. patient_id = fread(fid,16,'char',0);
  274. patient_name = fread(fid,32,'char',0);
  275. patient_sex = fread(fid,1,'char',0);
  276. patient_dexterity = fread(fid,1,'char',0);
  277. patient_age = fread(fid,1,'float32',0);
  278. patient_height = fread(fid,1,'float32',0);
  279. patient_weight = fread(fid,1,'float32',0);
  280. patient_birth_date = fread(fid,1,'uint32',0);
  281. physician_name = fread(fid,32,'char',0);
  282. operator_name = fread(fid,32,'char',0);
  283. study_description = fread(fid,32,'char',0);
  284. acquisition_type = fread(fid,1,'uint16',0);
  285. patient_orientation = fread(fid,1,'uint16',0);
  286. facility_name = fread(fid,20,'char',0);
  287. num_planes = fread(fid,1,'uint16',0);
  288. num_frames = fread(fid,1,'uint16',0);
  289. num_gates = fread(fid,1,'uint16',0);
  290. num_bed_pos = fread(fid,1,'uint16',0);
  291. init_bed_position = fread(fid,1,'float32',0);
  292. bed_position = zeros(15,1);
  293. for bed=1:15
  294. tmp = fread(fid,1,'float32',0);
  295. if ~isempty(tmp), bed_position(bed) = tmp; end
  296. end
  297. plane_separation = fread(fid,1,'float32',0);
  298. lwr_sctr_thres = fread(fid,1,'uint16',0);
  299. lwr_true_thres = fread(fid,1,'uint16',0);
  300. upr_true_thres = fread(fid,1,'uint16',0);
  301. user_process_code = fread(fid,10,'char',0);
  302. acquisition_mode = fread(fid,1,'uint16',0);
  303. bin_size = fread(fid,1,'float32',0);
  304. branching_fraction = fread(fid,1,'float32',0);
  305. dose_start_time = fread(fid,1,'uint32',0);
  306. dosage = fread(fid,1,'float32',0);
  307. well_counter_corr_factor = fread(fid,1,'float32',0);
  308. data_units = fread(fid,32,'char',0);
  309. septa_state = fread(fid,1,'uint16',0);
  310. fill = fread(fid,1,'uint16',0);
  311. magic_number = deblank(char(magic_number.*(magic_number>32))');
  312. original_file_name = deblank(char(original_file_name.*(original_file_name>0))');
  313. serial_number = deblank(char(serial_number.*(serial_number>0))');
  314. isotope_name = deblank(char(isotope_name.*(isotope_name>0))');
  315. radiopharmaceutical = deblank(char(radiopharmaceutical.*(radiopharmaceutical>0))');
  316. study_type = deblank(char(study_type.*(study_type>0))');
  317. patient_id = deblank(char(patient_id.*(patient_id>0))');
  318. patient_name = deblank(char(patient_name.*(patient_name>0))');
  319. patient_sex = deblank(char(patient_sex.*(patient_sex>0))');
  320. patient_dexterity = deblank(char(patient_dexterity.*(patient_dexterity>0))');
  321. physician_name = deblank(char(physician_name.*(physician_name>0))');
  322. operator_name = deblank(char(operator_name.*(operator_name>0))');
  323. study_description = deblank(char(study_description.*(study_description>0))');
  324. facility_name = deblank(char(facility_name.*(facility_name>0))');
  325. user_process_code = deblank(char(user_process_code.*(user_process_code>0))');
  326. data_units = deblank(char(data_units.*(data_units>0))');
  327. MHEADER = struct('MAGIC_NUMBER', magic_number, ...
  328. 'ORIGINAL_FILE_NAME', original_file_name, ...
  329. 'SW_VERSION', sw_version, ...
  330. 'SYSTEM_TYPE', system_type, ...
  331. 'FILE_TYPE', file_type, ...
  332. 'SERIAL_NUMBER', serial_number, ...
  333. 'SCAN_START_TIME', scan_start_time, ...
  334. 'ISOTOPE_NAME', isotope_name, ...
  335. 'ISOTOPE_HALFLIFE', isotope_halflife, ...
  336. 'RADIOPHARMACEUTICAL', radiopharmaceutical, ...
  337. 'GANTRY_TILT', gantry_tilt, ...
  338. 'GANTRY_ROTATION', gantry_rotation, ...
  339. 'BED_ELEVATION', bed_elevation, ...
  340. 'INTRINSIC_TILT', intrinsic_tilt, ...
  341. 'WOBBLE_SPEED', wobble_speed, ...
  342. 'TRANSM_SOURCE_TYPE', transm_source_type, ...
  343. 'DISTANCE_SCANNED', distance_scanned, ...
  344. 'TRANSAXIAL_FOV', transaxial_fov, ...
  345. 'ANGULAR_COMPRESSION', angular_compression, ...
  346. 'COIN_SAMP_MODE', coin_samp_mode, ...
  347. 'AXIAL_SAMP_MODE', axial_samp_mode, ...
  348. 'ECAT_CALIBRATION_FACTOR', ecat_calibration_factor, ...
  349. 'CALIBRATION_UNITS', calibration_units, ...
  350. 'CALIBRATION_UNITS_TYPE', calibration_units_type, ...
  351. 'COMPRESSION_CODE', compression_code, ...
  352. 'STUDY_TYPE', study_type, ...
  353. 'PATIENT_ID', patient_id, ...
  354. 'PATIENT_NAME', patient_name, ...
  355. 'PATIENT_SEX', patient_sex, ...
  356. 'PATIENT_DEXTERITY', patient_dexterity, ...
  357. 'PATIENT_AGE', patient_age, ...
  358. 'PATIENT_HEIGHT', patient_height, ...
  359. 'PATIENT_WEIGHT', patient_weight, ...
  360. 'PATIENT_BIRTH_DATE', patient_birth_date, ...
  361. 'PHYSICIAN_NAME', physician_name, ...
  362. 'OPERATOR_NAME', operator_name, ...
  363. 'STUDY_DESCRIPTION', study_description, ...
  364. 'ACQUISITION_TYPE', acquisition_type, ...
  365. 'PATIENT_ORIENTATION', patient_orientation, ...
  366. 'FACILITY_NAME', facility_name, ...
  367. 'NUM_PLANES', num_planes, ...
  368. 'NUM_FRAMES', num_frames, ...
  369. 'NUM_GATES', num_gates, ...
  370. 'NUM_BED_POS', num_bed_pos, ...
  371. 'INIT_BED_POSITION', init_bed_position, ...
  372. 'BED_POSITION', bed_position, ...
  373. 'PLANE_SEPARATION', plane_separation, ...
  374. 'LWR_SCTR_THRES', lwr_sctr_thres, ...
  375. 'LWR_TRUE_THRES', lwr_true_thres, ...
  376. 'UPR_TRUE_THRES', upr_true_thres, ...
  377. 'USER_PROCESS_CODE', user_process_code, ...
  378. 'ACQUISITION_MODE', acquisition_mode, ...
  379. 'BIN_SIZE', bin_size, ...
  380. 'BRANCHING_FRACTION', branching_fraction, ...
  381. 'DOSE_START_TIME', dose_start_time, ...
  382. 'DOSAGE', dosage, ...
  383. 'WELL_COUNTER_CORR_FACTOR', well_counter_corr_factor, ...
  384. 'DATA_UNITS', data_units, ...
  385. 'SEPTA_STATE', septa_state, ...
  386. 'FILL', fill);