123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- function N = spm_parrec2nifti(parfile,opts)
- % Import PAR/REC images from Philips scanners into NIfTI
- % FORMAT N = spm_parrec2nifti(parfile,opts)
- % parfile - name of PAR file
- % opts - options structure
- % .ext - NIfTI file extension {'img','nii'} [default: spm_file_ext]
- % .outdir - output directory [default: pwd]
- %
- % N - NIfTI object
- %__________________________________________________________________________
- % Copyright (C) 2015 Wellcome Trust Centre for Neuroimaging
- % Guillaume Flandin
- % $Id: spm_parrec2nifti.m 6703 2016-01-28 17:36:10Z guillaume $
- %-Display warning
- %--------------------------------------------------------------------------
- fprintf('*************************************************************\n');
- fprintf('** PRELIMINARY SUPPORT OF PHILIPS PAR/REC **\n');
- fprintf('** USE AT YOUR OWN RISK **\n');
- fprintf('*************************************************************\n');
- %-Get options
- %--------------------------------------------------------------------------
- if nargin < 2, opts = struct; end
- if ~isfield(opts,'ext'), opts.ext = spm_file_ext; end
- if opts.ext(1) ~= '.', opts.ext = ['.' opts.ext]; end
- if ~isfield(opts,'outdir') || isempty(opts.outdir)
- opts.outdir = pwd;
- end
- %-Read PAR header file
- %--------------------------------------------------------------------------
- hdr = spm_par_hdr(parfile);
- %-Find REC data file
- %--------------------------------------------------------------------------
- if strcmp(spm_file(parfile,'ext'),'PAR')
- recfile = spm_file(parfile,'ext','REC');
- else
- recfile = spm_file(parfile,'ext','rec');
- end
- d = dir(recfile);
- if isempty(d), error('Cannot find REC file "%s".',recfile); end
- bytes = d.bytes;
- %-Write NIfTI header
- %--------------------------------------------------------------------------
- dim = [hdr.ImageInfo(1).recon_resolution hdr.MaxNumberOfSlices hdr.MaxNumberOfDynamics];
- dim = double(dim);
- dtype = double(hdr.ImageInfo(1).image_pixel_size);
- if prod(dim)*dtype/8 ~= bytes
- % can happen for corrupted files or non dynamic data
- dim(4) = floor(bytes*8/dtype/prod(dim(1:3)));
- fprintf('Size of REC file does not match PAR file. ');
- fprintf('Setting dim(4) to %d.\n',dim(4));
- end
- % Two scaling options [using DV here]:
- % DV = displayed value on console
- % FP = floating point value
- scale = hdr.ImageInfo(1).rescale_slope;
- inter = hdr.ImageInfo(1).rescale_intercept;
- mat = spm_par_orient(hdr);
- switch dtype
- case 8
- dtype = spm_type('int8'); % uint8?
- case 16
- dtype = spm_type('int16'); % uint16?
- case 32
- dtype = spm_type('float32');
- case 64
- dtype = spm_type('float64');
- otherwise
- error('Unknown data type.');
- end
- ofile = spm_file(parfile,'path',opts.outdir,'ext',opts.ext);
- dato = file_array(ofile,dim,[dtype 0],0,scale,inter);
- N = nifti;
- N.dat = dato;
- N.mat = mat;
- N.mat0 = mat;
- N.mat_intent = 'Scanner';
- N.mat0_intent = 'Scanner';
- N.descrip = hdr.ProtocolName;
- %N.timing = struct('toffset',[],'tspace',[]); % store TR
- create(N);
- %-Write NifTI data
- %--------------------------------------------------------------------------
- dati = file_array(recfile,dim,[dtype 0],0,scale,inter);
- dato = N.dat;
- % should handle interleaved data
- % data should not be scaled/unscaled
- for i=1:dim(4)
- slice_order = [hdr.ImageInfo([hdr.ImageInfo.dynamic_scan_number]==i).slice_number];
- dato(:,:,:,i) = dati(:,:,slice_order,i);
- end
- %==========================================================================
- % FUNCTION hdr = spm_par_hdr(fname)
- %==========================================================================
- function hdr = spm_par_hdr(fname)
- % could yse fileread instead
- fid = fopen(fname,'rt');
- if fid == -1
- error('Cannot open "%s".',fname);
- end
- iid = [];
- j = 1;
- while 1
- l = fgetl(fid);
- if ~ischar(l), break, end
- l = strtrim(l);
- if isempty(l), continue, end
- switch l(1)
- case '#'
- if strncmp(l,'# CLINICAL TRYOUT',17)
- hdr.Version = fliplr(strtok(fliplr(l)));
- end
- if strncmp(l,'# Dataset name:',15)
- hdr.DatasetName = strtrim(l(16:end));
- end
- if strncmp(l,'# === IMAGE INFORMATION DEFINITION',34)
- l = fgetl(fid); % # The rest of this file contains...
- l = fgetl(fid); % #
- iid = spm_par_get_iid(fid);
- end
- case '.'
- [key,val] = strtok(l(2:end),':');
- e = spm_par_findindict(strtrim(key));
- if ~isempty(e)
- hdr.(e.name) = feval(e.fcn,sscanf(strtrim(val(2:end)),e.fmt));
- else
- fprintf('Unknown key "%s" - ignored.\n',strtrim(key));
- end
- otherwise
- if isempty(iid)
- fclose(fid);
- error('Cannot read image information without definition.');
- end
- C = textscan(l,[iid.typ]);
- o = 1;
- for i=1:numel(iid)
- for k=1:iid(i).n
- hdr.ImageInfo(j).(iid(i).name)(k) = C{o};
- o = o + 1;
- end
- end
- j = j + 1;
- end
- end
- fclose(fid);
- %==========================================================================
- % FUNCTION iid = spm_par_get_iid(fid)
- %==========================================================================
- function iid = spm_par_get_iid(fid)
- % get Image Information Definition
- n = 1;
- while 1
- l = fgetl(fid);
- if ~ischar(l), break, end
- l = strtrim(l(2:end));
- if isempty(l), break, end
- i = strfind(l,'(');
- if isempty(i), continue, else i = i(end); end
-
- name = strrep(strrep(strtrim(strtok(l(1:i-1),'(<')),' ','_'),'-','_');
- typ = strtrim(l(i:end));
- [m,typ] = strtok(typ(2:end-1),'*');
- if isempty(typ)
- typ = m; m = 1;
- else
- m = str2double(m);
- typ = typ(2:end);
- end
-
- iid(n).name = name;
- switch typ
- case 'integer'
- iid(n).typ = strtrim(repmat('%d',1,m));
- case 'float'
- iid(n).typ = strtrim(repmat('%f',1,m));
- case 'string'
- iid(n).typ = strtrim(repmat('%s',1,m));
- otherwise
- error('Unknown data type "%s".',typ);
- end
- iid(n).n = m;
- n = n + 1;
- end
- %==========================================================================
- % FUNCTION e = spm_par_findindict(key)
- %==========================================================================
- function e = spm_par_findindict(key)
- dict = spm_par_dict;
- for i=1:numel(dict)
- if strcmp(dict(i).key,key)
- e = dict(i);
- return
- end
- end
- e = [];
- %==========================================================================
- % FUNCTION dict = spm_par_dict
- %==========================================================================
- function d = spm_par_dict
- persistent dict;
- if ~isempty(dict)
- d = dict;
- return;
- end
- n = @(x) x;
- dict = {...
- 'Patient name', 'PatientName', '%s', n
- 'Examination name', 'ExaminationName', '%s', n
- 'Protocol name', 'ProtocolName', '%s', n
- 'Examination date/time', 'ExaminationDate', '%s', @(x) datevec(x,'yyyy.mm.dd / HH:MM:SS')
- 'Series Type', 'SeriesType', '%s', n
- 'Series_data_type', 'SeriesDataType', '%s', n
- 'Acquisition nr', 'AcquisitionNr', '%d', n
- 'Reconstruction nr', 'ReconstructionNr', '%d', n
- 'Scan Duration [sec]', 'ScanDuration', '%d', n
- 'Max. number of cardiac phases', 'MaxNumberCardiacPhases', '%d', n
- 'Max. number of echoes', 'MaxNumberOfEchoes', '%d', n
- 'Max. number of slices/locations', 'MaxNumberOfSlices', '%d', n
- 'Max. number of dynamics', 'MaxNumberOfDynamics', '%d', n
- 'Max. number of mixes', 'MaxNumberOfMixes', '%d', n
- 'Patient Position', 'PatientPosition', '%s', n
- 'Patient position', 'PatientPosition', '%s', n
- 'Preparation direction', 'PreparationDirection', '%s', n
- 'Technique', 'Technique', '%s', n
- 'Scan resolution (x, y)', 'ScanResolution', '%d %d', n
- 'Scan mode', 'ScanMode', '%s', n
- 'Repetition time [ms]', 'RepetitionTime', '%f', n
- 'Repetition time [msec]', 'RepetitionTime', '%f', n
- 'FOV (ap,fh,rl) [mm]', 'FOV', '%f %f %f', n
- 'Water Fat shift [pixels]', 'WaterFatShift', '%f', n
- 'Angulation midslice(ap,fh,rl)[degr]', 'AngulationMidslice', '%f %f %f', n
- 'Off Centre midslice(ap,fh,rl) [mm]', 'OffCentreMidslice', '%f %f %f', n
- 'Flow compensation <0=no 1=yes> ?', 'FlowCompensation', '%d', @logical
- 'Presaturation <0=no 1=yes> ?', 'Presaturation', '%d', @logical
- 'Phase encoding velocity [cm/sec]', 'PhaseEncodingVelocity', '%f %f %f', n
- 'MTC <0=no 1=yes> ?', 'MTC', '%d', @logical
- 'SPIR <0=no 1=yes> ?', 'SPIR', '%d', @logical
- 'EPI factor <0,1=no EPI>', 'EPIFactor', '%d', n
- 'Dynamic scan <0=no 1=yes> ?', 'DynamicScan', '%d', @logical
- 'Diffusion <0=no 1=yes> ?', 'Diffusion', '%d', @logical
- 'Diffusion echo time [ms]', 'DiffusionEchoTime', '%f', n
- 'Diffusion echo time [msec]', 'DiffusionEchoTime', '%f', n
- 'Max. number of diffusion values', 'MaxNumberOfDiffusionValues', '%d', n
- 'Max. number of gradient orients', 'MaxNumberOfGradientsOrients', '%d', n
- 'Number of label types <0=no ASL>', 'NumberOfLabelTypes', '%d', n
- };
- dict = struct(...
- 'key' , dict(:,1),...
- 'name', dict(:,2),...
- 'fmt' , dict(:,3),...
- 'fcn' , dict(:,4));
- d = dict;
- %==========================================================================
- % FUNCTION M = spm_par_orient(hdr)
- %==========================================================================
- function M = spm_par_orient(hdr)
- dim = double([hdr.ImageInfo(1).recon_resolution hdr.MaxNumberOfSlices]);
- to_center = [eye(3) -dim(:)/2];
- to_center(4,4) = 1;
- vox = diag([hdr.ImageInfo(1).pixel_spacing hdr.ImageInfo(1).slice_thickness+hdr.ImageInfo(1).slice_gap 1]);
- switch hdr.ImageInfo(1).slice_orientation
- case 1 % transversal
- to_pls = [0 1 0 0; 0 0 1 0; 1 0 0 0; 0 0 0 1];
- case 2 % sagittal
- to_pls = diag([1 -1 -1 1]);
- case 3 % coronal
- to_pls = [0 0 1 0; 0 -1 0 0; 1 0 0 0; 0 0 0 1];
- otherwise
- error('Unknown slice orientation.');
- end
- ang = hdr.ImageInfo(1).image_angulation * pi / 180; % {radians} [AP FH RL]
- rz = [cos(ang(3)) -sin(ang(3)) 0; sin(ang(3)) cos(ang(3)) 0; 0 0 1];
- ry = [cos(ang(2)) 0 sin(ang(2)); 0 1 0; -sin(ang(2)) 0 cos(ang(2))];
- rx = [1 0 0; 0 cos(ang(1)) -sin(ang(1)); 0 sin(ang(1)) cos(ang(1))];
- rot = rx * ry *rz;
- rot(4,4) = 1;
- pls = rot * to_pls * vox * to_center;
- pls(1:3,4) = pls(1:3,4) + hdr.ImageInfo(1).image_offcentre(:);
- pls_to_ras = [0 0 -1 0; -1 0 0 0; 0 1 0 0; 0 0 0 1];
-
- M = pls_to_ras * pls;
|