diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..e69de29 diff --git a/mpi_code/AGLOGO_MACAQUE_DTI.xlsx b/mpi_code/AGLOGO_MACAQUE_DTI.xlsx new file mode 100644 index 0000000..f905a66 Binary files /dev/null and b/mpi_code/AGLOGO_MACAQUE_DTI.xlsx differ diff --git a/mpi_code/mex_anz/ANALYZE75.pdf b/mpi_code/mex_anz/ANALYZE75.pdf new file mode 100644 index 0000000..97683de Binary files /dev/null and b/mpi_code/mex_anz/ANALYZE75.pdf differ diff --git a/mpi_code/mex_anz/Analyze_usage.pdf b/mpi_code/mex_anz/Analyze_usage.pdf new file mode 100644 index 0000000..5b8a8e6 Binary files /dev/null and b/mpi_code/mex_anz/Analyze_usage.pdf differ diff --git a/mpi_code/mex_anz/Contents.m b/mpi_code/mex_anz/Contents.m new file mode 100644 index 0000000..ad9382d --- /dev/null +++ b/mpi_code/mex_anz/Contents.m @@ -0,0 +1,23 @@ +% UTILS/MEX_ANZ +% This direcotry contains utility functions to handle ANALYZE-7 format. +% +% SCRIPTS : +% bru2spm - dumps Brucker 2dseq as ANALYZE-7 format for SPM. +% anz_read - reads ANALYZE iamge/header. +% anz_write - writes ANALYZE image/header. +% hdr_init - initializes ANALIZE(TM) header structure. +% hdr_read - reads ANALYZE header. +% hdr_write - create a ANALYZE header file. +% mexanz - creates mex programs. +% +% MEX : +% swapbytes - swaps bytes of given data. +% +% INFO : +% ANALYZE75.pdf - description for ANALYZE-7 header format. +% +% VERSION : +% 0.90 06.06.05 YM +% 0.91 11.10.07 YM update contents.m +% +% See also SPM2 diff --git a/mpi_code/mex_anz/anz_read.m b/mpi_code/mex_anz/anz_read.m new file mode 100644 index 0000000..62fbaa7 --- /dev/null +++ b/mpi_code/mex_anz/anz_read.m @@ -0,0 +1,97 @@ +function [IMG HDR] = anz_read(filename) +%ANZ_READ - reads ANALYZE image/header +% [IMG HDR] = ANZ_READ(IMGFILE) reads ANALYZE(TM) image. +% +% VERSION : +% 0.90 12.01.07 YM pre-release +% 0.91 28.02.07 YM use uigetfile() +% 0.92 06.08.07 YM bug fix when big-endian +% 0.93 07.04.08 YM filename can be as .raw +% +% See also ANZ_WRITE HDR_READ UTLSWAPBYTES + +if nargin == 0 & nargout == 0, help anz_read; return; end + +IMG = []; HDR = []; +if ~exist('filename','var'), filename = ''; end + +if isempty(filename), + [tmpf,tmpp] = uigetfile({'*.img;*.hdr','ANALYZE data (*.img/*hdr)';'*.*','All Files (*.*)'},... + 'Pick an ANALYZE file'); + if tmpf == 0, return; end + filename = fullfile(tmpp,tmpf); + clear tmpf tmpp; +end + +[fp,fr,fe] = fileparts(filename); + +if strcmpi(fe,'.hdr'), + % filename as 'header' file. + imgfile = fullfile(fp,sprintf('%s.img',fr)); +else + % filename as 'image' file, can be like *.raw or so. + imgfile = fullfile(fp,sprintf('%s%s',fr,fe)); +end +hdrfile = fullfile(fp,sprintf('%s.hdr',fr)); + + +if ~exist(hdrfile,'file'), + error('%s: ''%s'' not found.',mfilename,hdrfile); +end + +HDR = hdr_read(hdrfile); +if isempty(HDR), return; end + +% checks need to swap bytes or not +fid = fopen(hdrfile,'r'); +hsize = fread(fid, 1, 'int32=>int32'); +fclose(fid); +if hsize > hex2dec('01000000'), + SWAP_BYTES = 1; +else + SWAP_BYTES = 0; +end + + +if ~exist(imgfile,'file'), + error('%s: ''%s'' not found.',mfilename,imgfile); +end + +% /* Acceptable values for datatype */ +% #define DT_NONE 0 +% #define DT_UNKNOWN 0 +% #define DT_BINARY 1 +% #define DT_UNSIGNED_CHAR 2 +% #define DT_SIGNED_SHORT 4 +% #define DT_SIGNED_INT 8 +% #define DT_FLOAT 16 +% #define DT_COMPLEX 32 +% #define DT_DOUBLE 64 +% #define DT_RGB 128 +% #define DT_ALL 255 +fid = fopen(imgfile,'rb'); +if HDR.dime.datatype == 2, + IMG = fread(fid,inf,'uint8=>uint8'); +elseif HDR.dime.datatype == 4, + IMG = fread(fid,inf,'int16=>int16'); + if SWAP_BYTES > 0, IMG = utlswapbytes(IMG); end +elseif HDR.dime.datatype == 8, + IMG = fread(fid,inf,'int32=>int32'); + if SWAP_BYTES > 0, IMG = utlswapbytes(IMG); end +elseif HDR.dime.datatype == 16, + IMG = fread(fid,inf,'float=>float'); + if SWAP_BYTES > 0, IMG = utlswapbytes(IMG); end +elseif HDR.dime.datatype == 64, + IMG = fread(fid,inf,'double=>double'); +else + fprintf('\n %s: unsupported datatype(=%d).\n',mfilename,HDR.dime.datatype); + IMG = NaN(HDR.dime.dim([1:HDR.dime.dim(1)]+1)); +end +fclose(fid); + + +IMG = reshape(IMG,HDR.dime.dim([1:HDR.dime.dim(1)]+1)); + + + +return diff --git a/mpi_code/mex_anz/anz_view.m b/mpi_code/mex_anz/anz_view.m new file mode 100644 index 0000000..3ad5567 --- /dev/null +++ b/mpi_code/mex_anz/anz_view.m @@ -0,0 +1,1129 @@ +function varargout = anz_view(varargin) +%ANZ_VIEW - displays ANALYZE format images +% ANZ_VIEW(IMGFILE,...) displays ANALYZE format images. +% +% EXAMPLE : +% >> anz_view(''); +% >> anz_view('D99_T1weighted.img'); +% +% VERSION : +% 0.90 02.05.08 YM pre-release +% 0.91 05.05.08 YM improved memory usage +% +% See also anz_read anz_write + +if nargin == 0, help anz_view; return; end + +% execute callback function then return; +if ischar(varargin{1}) & ~isempty(findstr(varargin{1},'Callback')), + if nargout + [varargout{1:nargout}] = feval(varargin{:}); + else + feval(varargin{:}); + end + return; +end + + +% DEFAULT CONTROL SETTINGS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% ANAP.anz_view.xxxx +ANAP.anz_view.anascale = []; +ANAP.anz_view.colormap = 'gray'; +ANAP.anz_view.xreverse = 0; +ANAP.anz_view.yreverse = 0; +ANAP.anz_view.zreverse = 1; + +IMGFILE = varargin{1}; +for N = 2:2:length(varargin), + switch lower(varargin{N}), + case {'anascale','scale'} + ANAP.anz_view.anascale = varargin{N+1}; + case {'cmap','colormap','color'} + ANAP.anz_view.colormap = varargin{N+1}; + case {'xreverse'} + ANAP.anz_view.xreverse = varargin{N+1}; + case {'yreverse'} + ANAP.anz_view.yreverse = varargin{N+1}; + case {'zreverse'} + ANAP.anz_view.zreverse = varargin{N+1}; + end +end + + +% GET SCREEN SIZE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +oldunits = get(0,'units'); +set(0,'units','char'); +SZscreen = get(0,'ScreenSize'); +set(0,'units',oldunits); +scrW = SZscreen(3); scrH = SZscreen(4); + +figW = 175; figH = 55; +figX = 31; figY = scrH-figH-5; + +%[figX figY figW figH] + + +% CREATE A MAIN FIGURE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +hMain = figure(... + 'Name',sprintf('%s: %s',mfilename,datestr(now)),... + 'NumberTitle','off', 'toolbar','figure',... + 'Tag','main', 'units','char', 'pos',[figX figY figW figH],... + 'HandleVisibility','on', 'Resize','on',... + 'DoubleBuffer','on', 'BackingStore','on', 'Visible','on',... + 'DefaultAxesFontSize',10,... + 'DefaultAxesFontName', 'Comic Sans MS',... + 'DefaultAxesfontweight','bold',... + 'PaperPositionMode','auto', 'PaperType','A4', 'PaperOrientation', 'landscape'); + + + +% WIDGETS TO ANALYZE FILE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +XDSP = 10; H = figH - 2.5; +AnzFileTxt = uicontrol(... + 'Parent',hMain,'Style','Text',... + 'Units','char','Position',[XDSP H-0.3 30 1.5],... + 'String','FILE:','FontWeight','bold',... + 'HorizontalAlignment','left',... + 'Tag','AnzFileTxt',... + 'BackgroundColor',get(hMain,'Color')); +AnzFileEdt = uicontrol(... + 'Parent',hMain,'Style','Edit',... + 'Units','char','Position',[XDSP+8 H 96 1.5],... + 'Callback','anz_view(''Main_Callback'',gcbo,''init'',guidata(gcbo))',... + 'String',IMGFILE,'Tag','AnzFileEdt',... + 'HorizontalAlignment','left',... + 'TooltipString','ANALYZE file',... + 'FontWeight','Bold'); +AnzReadBtn = uicontrol(... + 'Parent',hMain,'Style','PushButton',... + 'Units','char','Position',[XDSP+105 H 15 1.5],... + 'Callback','anz_view(''Main_Callback'',gcbo,''browse-file'',guidata(gcbo))',... + 'Tag','AnzReadBtn','String','Browse...',... + 'TooltipString','browse a ANALYZE file','FontWeight','Bold'); +% AnzSaveBtn = uicontrol(... +% 'Parent',hMain,'Style','PushButton',... +% 'Units','char','Position',[XDSP+106 H 15 1.5],... +% 'Callback','anz_view(''Main_Callback'',gcbo,''save-file'',guidata(gcbo))',... +% 'Tag','AnzSaveBtn','String','Save...',... +% 'TooltipString','save a ANALYZE file','FontWeight','Bold'); + +cmaps = {'gray','jet','autumn','hot','cool','bone','copper','pink','red','green','blue','yellow'}; +idx = find(strcmpi(cmaps,ANAP.anz_view.colormap)); +if isempty(idx), + fprintf('WARNING %s: unknown colormap name ''%s''.\n',mfilename,ANAP.mview.colormap); + idx = 1; +end +ColormapCmb = uicontrol(... + 'Parent',hMain,'Style','Popupmenu',... + 'Units','char','Position',[XDSP+123 H 15 1.5],... + 'Callback','anz_view(''Main_Callback'',gcbo,''update-cmap'',guidata(gcbo))',... + 'String',cmaps,'Value',idx,'Tag','ColormapCmb',... + 'TooltipString','Select colormap',... + 'FontWeight','bold'); +clear cmaps idx; +AnaScaleEdt = uicontrol(... + 'Parent',hMain,'Style','Edit',... + 'Units','char','Position',[XDSP+139 H 20 1.5],... + 'Callback','anz_view(''Main_Callback'',gcbo,''update-anascale'',guidata(gcbo))',... + 'String',deblank(sprintf('%g ',ANAP.anz_view.anascale)),'Tag','AnaScaleEdt',... + 'HorizontalAlignment','center',... + 'TooltipString','set anatomy scaling, [min max gamma]',... + 'FontWeight','bold'); + + + + +% AXES for plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% AXES FOR LIGHT BOX %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +H = 3; XSZ = 55; YSZ = 20; +XDSP=10; +LightiboxAxs = axes(... + 'Parent',hMain,'Tag','LightboxAxs',... + 'Units','char','Position',[XDSP H XSZ*2+12 YSZ*2+6.5],... + 'Box','off','color','black','Visible','off'); + + + + +% AXES FOR ORTHOGONL VIEW %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +H = 28; XSZ = 55; YSZ = 20; +XDSP=10; +CoronalTxt = uicontrol(... + 'Parent',hMain,'Style','Text',... + 'Units','char','Position',[XDSP H+YSZ 20 1.5],... + 'String','Coronal (X-Z)','FontWeight','bold',... + 'HorizontalAlignment','left',... + 'Tag','CoronalTxt',... + 'BackgroundColor',get(hMain,'Color')); +CoronalEdt = uicontrol(... + 'Parent',hMain,'Style','Edit',... + 'Units','char','Position',[XDSP+22 H+YSZ+0.2 8 1.5],... + 'Callback','anz_view(''OrthoView_Callback'',gcbo,''edit-coronal'',guidata(gcbo))',... + 'String','','Tag','CoronalEdt',... + 'HorizontalAlignment','center',... + 'TooltipString','set coronal slice',... + 'FontWeight','Bold'); +CoronalSldr = uicontrol(... + 'Parent',hMain,'Style','slider',... + 'Units','char','Position',[XDSP+XSZ*0.6 H+YSZ+0.2 XSZ*0.4 1.2],... + 'Callback','anz_view(''OrthoView_Callback'',gcbo,''slider-coronal'',guidata(gcbo))',... + 'Tag','CoronalSldr','SliderStep',[1 4],... + 'TooltipString','coronal slice'); +CoronalAxs = axes(... + 'Parent',hMain,'Tag','CoronalAxs',... + 'Units','char','Position',[XDSP H XSZ YSZ],... + 'Box','off','Color','black'); +SagitalTxt = uicontrol(... + 'Parent',hMain,'Style','Text',... + 'Units','char','Position',[XDSP+10+XSZ H+YSZ 20 1.5],... + 'String','Sagital (Y-Z)','FontWeight','bold',... + 'HorizontalAlignment','left',... + 'Tag','SagitalTxt',... + 'BackgroundColor',get(hMain,'Color')); +SagitalEdt = uicontrol(... + 'Parent',hMain,'Style','Edit',... + 'Units','char','Position',[XDSP+10+XSZ+22 H+YSZ+0.2 8 1.5],... + 'Callback','anz_view(''OrthoView_Callback'',gcbo,''edit-sagital'',guidata(gcbo))',... + 'String','','Tag','SagitalEdt',... + 'HorizontalAlignment','center',... + 'TooltipString','set sagital slice',... + 'FontWeight','Bold'); +SagitalSldr = uicontrol(... + 'Parent',hMain,'Style','slider',... + 'Units','char','Position',[XDSP+10+XSZ*1.6 H+YSZ+0.2 XSZ*0.4 1.2],... + 'Callback','anz_view(''OrthoView_Callback'',gcbo,''slider-sagital'',guidata(gcbo))',... + 'Tag','SagitalSldr','SliderStep',[1 4],... + 'TooltipString','sagital slice'); +SagitalAxs = axes(... + 'Parent',hMain,'Tag','SagitalAxs',... + 'Units','char','Position',[XDSP+10+XSZ H XSZ YSZ],... + 'Box','off','Color','black'); + + +H = 3; +TransverseTxt = uicontrol(... + 'Parent',hMain,'Style','Text',... + 'Units','char','Position',[XDSP H+YSZ 20 1.5],... + 'String','Transverse (X-Y)','FontWeight','bold',... + 'HorizontalAlignment','left',... + 'Tag','TransverseTxt',... + 'BackgroundColor',get(hMain,'Color')); +TransverseEdt = uicontrol(... + 'Parent',hMain,'Style','Edit',... + 'Units','char','Position',[XDSP+22 H+YSZ+0.2 8 1.5],... + 'Callback','anz_view(''OrthoView_Callback'',gcbo,''edit-transverse'',guidata(gcbo))',... + 'String','','Tag','TransverseEdt',... + 'HorizontalAlignment','center',... + 'TooltipString','set transverse slice',... + 'FontWeight','Bold'); +TransverseSldr = uicontrol(... + 'Parent',hMain,'Style','slider',... + 'Units','char','Position',[XDSP+XSZ*0.6 H+YSZ+0.2 XSZ*0.4 1.2],... + 'Callback','anz_view(''OrthoView_Callback'',gcbo,''slider-transverse'',guidata(gcbo))',... + 'Tag','TransverseSldr','SliderStep',[1 4],... + 'TooltipString','transverse slice'); +TransverseAxs = axes(... + 'Parent',hMain,'Tag','TransverseAxs',... + 'Units','char','Position',[XDSP H XSZ YSZ],... + 'Box','off','Color','black'); + +TriplotAxs = axes(... + 'Parent',hMain,'Tag','TriplotAxs',... + 'Units','char','Position',[XDSP+10+XSZ H XSZ YSZ],... + 'Box','off','color','white'); + + + + + +% VIEW MODE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +H = 28; +XDSP=XDSP+XSZ+7; +ViewModeCmb = uicontrol(... + 'Parent',hMain,'Style','Popupmenu',... + 'Units','char','Position',[XDSP+10+XSZ H+YSZ 32 1.5],... + 'Callback','anz_view(''Main_Callback'',gcbo,''view-mode'',guidata(gcbo))',... + 'String',{'orthogonal','lightbox-cor','lightbox-sag','lightbox-trans'},... + 'Tag','ViewModeCmb','Value',1,... + 'TooltipString','Select the view mode',... + 'FontWeight','bold'); +ViewPageList = uicontrol(... + 'Parent',hMain,'Style','Listbox',... + 'Units','char','Position',[XDSP+10+XSZ H+10 32 9],... + 'String',{'page1','page2','page3','page4'},... + 'Callback','anz_view(''Main_Callback'',gcbo,''view-page'',guidata(gcbo))',... + 'HorizontalAlignment','left',... + 'FontName','Comic Sans MS','FontSize',9,... + 'Tag','ViewPageList','Background','white'); + + +% INFORMATION TEXT %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +InfoTxt = uicontrol(... + 'Parent',hMain,'Style','Listbox',... + 'Units','char','Position',[XDSP+10+XSZ H+2.5 32 7],... + 'String',{'session','group','datsize','resolution'},... + 'HorizontalAlignment','left',... + 'FontName','Comic Sans MS','FontSize',9,... + 'Tag','InfoTxt','Background','white'); + + + + +% AXES FOR COLORBAR %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +H = 3; +ColorbarAxs = axes(... + 'Parent',hMain,'Tag','ColorbarAxs',... + 'units','char','Position',[XDSP+10+XSZ H XSZ*0.1 YSZ],... + 'FontSize',8,... + 'Box','off','YAxisLocation','right','XTickLabel',{},'XTick',[]); + + +% CHECK BOX FOR X,Y,Z direction %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +XReverseCheck = uicontrol(... + 'Parent',hMain,'Style','Checkbox',... + 'Units','char','Position',[XDSP+10+XSZ+15 H+YSZ/2 20 1.5],... + 'Tag','XReverseCheck','Value',ANAP.anz_view.xreverse,... + 'Callback','anz_view(''OrthoView_Callback'',gcbo,''dir-reverse'',guidata(gcbo))',... + 'String','X-Reverse','FontWeight','bold',... + 'TooltipString','Xdir reverse','BackgroundColor',get(hMain,'Color')); +YReverseCheck = uicontrol(... + 'Parent',hMain,'Style','Checkbox',... + 'Units','char','Position',[XDSP+10+XSZ+15 H+YSZ/2-2.5 20 1.5],... + 'Tag','YReverseCheck','Value',ANAP.anz_view.yreverse,... + 'Callback','anz_view(''OrthoView_Callback'',gcbo,''dir-reverse'',guidata(gcbo))',... + 'String','Y-Reverse','FontWeight','bold',... + 'TooltipString','Ydir reverse','BackgroundColor',get(hMain,'Color')); +ZReverseCheck = uicontrol(... + 'Parent',hMain,'Style','Checkbox',... + 'Units','char','Position',[XDSP+10+XSZ+15 H+YSZ/2-2.5*2 20 1.5],... + 'Callback','anz_view(''OrthoView_Callback'',gcbo,''dir-reverse'',guidata(gcbo))',... + 'Tag','ZReverseCheck','Value',ANAP.anz_view.zreverse,... + 'String','Z-Reverse','FontWeight','bold',... + 'TooltipString','Zdir reverse','BackgroundColor',get(hMain,'Color')); + + +% CHECK BOX FOR "cross-hair" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CrosshairCheck = uicontrol(... + 'Parent',hMain,'Style','Checkbox',... + 'Units','char','Position',[XDSP+10+XSZ+15 H+YSZ/2-7.5 20 1.5],... + 'Callback','anz_view(''OrthoView_Callback'',gcbo,''crosshair'',guidata(gcbo))',... + 'Tag','CrosshairCheck','Value',1,... + 'String','Crosshair','FontWeight','bold',... + 'TooltipString','show a crosshair','BackgroundColor',get(hMain,'Color')); + + + + + +% get widgets handles at this moment +HANDLES = findobj(hMain); + + +% INITIALIZE THE APPLICATION +setappdata(hMain,'ANA',[]); +setappdata(hMain,'ANAP',ANAP); +Main_Callback(SagitalAxs,'init'); +set(hMain,'visible','on'); + + + +% NOW SET "UNITS" OF ALL WIDGETS AS "NORMALIZED". +HANDLES = HANDLES(find(HANDLES ~= hMain)); +set(HANDLES,'units','normalized'); + + +% RETURNS THE WINDOW HANDLE IF REQUIRED. +if nargout, + varargout{1} = hMain; +end + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function Main_Callback(hObject,eventdata,handles) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +wgts = guihandles(hObject); + +switch lower(eventdata), + case {'init'} + + IMGFILE = get(wgts.AnzFileEdt,'String'); + if isempty(IMGFILE), return; end + + if ~exist(IMGFILE,'file'), + fprintf('\nERROR %s: ''%s'' not found.\n',mfilename,IMGFILE); + end + + [img hdr] = anz_read(IMGFILE); + if ~ischar(hdr.dime.datatype), + switch hdr.dime.datatype, + case 1 + hdr.dime.datatype = 'binary'; + case 2 + hdr.dime.datatype = 'uint8'; + case 4 + hdr.dime.datatype = 'int16'; + case 8 + hdr.dime.datatype = 'int32'; + case 16 + hdr.dime.datatype = 'single'; + case 32 + hdr.dime.datatype = 'complex'; + case 64 + hdr.dime.datatype = 'double'; + case 128 + hdr.dime.datatype = 'rgb'; + otherwise + hdr.dime.datatype = 'unknown'; + end + end + + + ANA.imgfile = IMGFILE; + ANA.hdr = hdr; + ANA.dat = img; + ANA.ds = hdr.dime.pixdim(2:4); + clear hdr img; + + ANAP = getappdata(wgts.main,'ANAP'); + + % converts ANA.dat into RGB + anaminv = 0; + anamaxv = 0; + anagamma = 1.8; + if isfield(ANAP,'anz_view') & isfield(ANAP.anz_view,'anascale') & ~ ... + isempty(ANAP.anz_view.anascale), + if length(ANAP.anz_view.anascale) == 1, + anamaxv = ANAP.anz_view.anascale; + else + anaminv = ANAP.anz_view.anascale(1); + anamaxv = ANAP.anz_view.anascale(2); + if length(ANAP.anz_view.anascale) > 2, + anagamma = ANAP.anz_view.anascale(3); + end + end + end + if anamaxv == 0, + tmpana = double(ANA.dat); + %anamaxv = round(mean(tmpana(:))*3.5); + anamaxv = round(double(max(ANA.dat(:)))*0.7); + end + ANA.ana256 = subScaleAnatomy(ANA.dat,anaminv,anamaxv,anagamma); + ANA.scale = [anaminv anamaxv anagamma]; + clear tmpana anaminv anamaxv anagamma; + + setappdata(wgts.main,'ANA',ANA); + + INFTXT = {}; + INFTXT{end+1} = sprintf('dim: [%s]',deblank(sprintf('%d ',size(ANA.dat)))); + INFTXT{end+1} = sprintf('res: [%s]',deblank(sprintf('%g ',ANA.ds))); + INFTXT{end+1} = sprintf('data: %s',ANA.hdr.dime.datatype); + set(wgts.InfoTxt,'String',INFTXT); + + + set(wgts.AnaScaleEdt,'String',sprintf('%g %g %g',ANA.scale)); + + % initialize view + OrthoView_Callback(hObject(1),'init',[]); + LightboxView_Callback(hObject(1),'init',[]); + + Main_Callback(hObject,'redraw',[]); + + + case {'browse-file'} + [f,d] = uigetfile( ... + {'*.img', 'All ANALYZE Files (*.img)'; ... + '*.*', 'All Files (*.*)'}, ... + 'Pick ANALYZE file'); + if isequal(f,0) | isequal(d,0), return; end + IMGFILE = fullfile(d,f); + + setappdata(wgts.main,'ANA',[]); + set(wgts.AnzFileEdt,'String',IMGFILE); + Main_Callback(hObject,'init',[]); + + case {'update-cmap'} + % update tick for colorbar + GRAHANDLE = getappdata(wgts.main,'GRAHANDLE'); + if ~isempty(GRAHANDLE), + ANA = getappdata(wgts.main,'ANA'); + MINV = ANA.scale(1); MAXV = ANA.scale(2); + ydat = [0:255]/255 * (MAXV - MINV) + MINV; + set(GRAHANDLE.colorbar,'ydata',ydat); + set(wgts.ColorbarAxs,'ylim',[MINV MAXV]); + end + + CMAP = subGetColormap(wgts); + axes(wgts.ColorbarAxs); colormap(CMAP); + setappdata(wgts.main,'CMAP',CMAP); + + Main_Callback(hObject,'redraw',[]); + + + + case {'update-anascale'} + anascale = str2num(get(wgts.AnaScaleEdt,'String')); + if length(anascale) ~= 3, return; end + ANA = getappdata(wgts.main,'ANA'); + if isempty(ANA), return; end + ANA.ana256 = subScaleAnatomy(ANA.dat,anascale(1),anascale(2),anascale(3)); + setappdata(wgts.main,'ANA',ANA); clear ANA anascale; + Main_Callback(hObject,'update-cmap',[]); + %Main_Callback(hObject,'redraw',[]); + + case {'redraw'} + ViewMode = get(wgts.ViewModeCmb,'String'); + ViewMode = ViewMode{get(wgts.ViewModeCmb,'Value')}; + if strcmpi(ViewMode,'orthogonal'), + OrthoView_Callback(hObject,'redraw',[]); + else + LightboxView_Callback(hObject,'redraw',[]); + end + %fprintf('redraw\n'); + + case {'view-mode'} + ViewMode = get(wgts.ViewModeCmb,'String'); + ViewMode = ViewMode{get(wgts.ViewModeCmb,'Value')}; + hL = [wgts.LightboxAxs]; + hO = [wgts.CoronalTxt, wgts.CoronalEdt, wgts.CoronalSldr, wgts.CoronalAxs,... + wgts.SagitalTxt, wgts.SagitalEdt, wgts.SagitalSldr, wgts.SagitalAxs,... + wgts.TransverseTxt, wgts.TransverseEdt, wgts.TransverseSldr, wgts.TransverseAxs,... + wgts.CrosshairCheck]; + + if strcmpi(ViewMode,'orthogonal'), + set(hL,'visible','off'); + set(findobj(hL),'visible','off'); + set(hO,'visible','on'); + h = findobj([wgts.CoronalAxs, wgts.SagitalAxs, wgts.TransverseAxs, wgts.TriplotAxs]); + set(h,'visible','on'); + else + set(hL,'visible','on'); + set(findobj(hL),'visible','on'); + set(hO,'visible','off'); + h = findobj([wgts.CoronalAxs, wgts.SagitalAxs, wgts.TransverseAxs, wgts.TriplotAxs]); + set(h,'visible','off'); + LightboxView_Callback(hObject,'init',[]); + LightboxView_Callback(hObject,'redraw',[]); + end + + case {'view-page'} + ViewMode = get(wgts.ViewModeCmb,'String'); + ViewMode = ViewMode{get(wgts.ViewModeCmb,'Value')}; + if ~isempty(strfind(ViewMode,'lightbox')), + LightboxView_Callback(hObject,'redraw',[]); + end + + otherwise +end + +return; + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION to handle orthogonal view +function OrthoView_Callback(hObject,eventdata,handles) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +wgts = guihandles(get(hObject,'Parent')); +ANA = getappdata(wgts.main,'ANA'); + +switch lower(eventdata), + case {'init'} + + iX = 1; iY = 1; iZ = 1; + nX = size(ANA.dat,1); nY = size(ANA.dat,2); nZ = size(ANA.dat,3); + % set slider edit value + set(wgts.SagitalEdt, 'String', sprintf('%d',iX)); + set(wgts.CoronalEdt, 'String', sprintf('%d',iY)); + set(wgts.TransverseEdt,'String', sprintf('%d',iZ)); + % set slider, add +0.01 to prevent error. + set(wgts.SagitalSldr, 'Min',1,'Max',nX+0.01,'Value',iX); + set(wgts.CoronalSldr, 'Min',1,'Max',nY+0.01,'Value',iY); + set(wgts.TransverseSldr,'Min',1,'Max',nZ+0.01,'Value',iZ); + % set slider step, it is normalized from 0 to 1, not min/max + set(wgts.SagitalSldr, 'SliderStep',[1, 2]/max(1,nX)); + set(wgts.CoronalSldr, 'SliderStep',[1, 2]/max(1,nY)); + set(wgts.TransverseSldr,'SliderStep',[1, 2]/max(1,nZ)); + + CMAP = subGetColormap(wgts); + setappdata(wgts.main,'CMAP',CMAP); + + AXISCOLOR = [0.8 0.2 0.8]; + % now draw images + axes(wgts.SagitalAxs); cla; + tmpimg = squeeze(ANA.ana256(iX,:,:)); + hSag = image(1:nY,1:nZ,ind2rgb(tmpimg',CMAP)); + set(hSag,... + 'ButtonDownFcn','anz_view(''OrthoView_Callback'',gcbo,''button-sagital'',guidata(gcbo))'); + set(wgts.SagitalAxs,'tag','SagitalAxs'); % set this again, some will reset. + axes(wgts.CoronalAxs); cla; + tmimg = squeeze(ANA.ana256(:,iY,:)); + hCor = image(1:nX,1:nZ,ind2rgb(tmpimg',CMAP)); + set(hCor,... + 'ButtonDownFcn','anz_view(''OrthoView_Callback'',gcbo,''button-coronal'',guidata(gcbo))'); + set(wgts.CoronalAxs,'tag','CoronalAxs'); % set this again, some will reset. + axes(wgts.TransverseAxs); cla; + tmpimg = squeeze(ANA.ana256(:,:,iZ)); + hTra = image(1:nX,1:nY,ind2rgb(tmpimg',CMAP)); + set(hTra,... + 'ButtonDownFcn','anz_view(''OrthoView_Callback'',gcbo,''button-transverse'',guidata(gcbo))'); + set(wgts.TransverseAxs,'tag','TransverseAxs'); % set this again, some will reset. + + % now draw a color bar + MINV = ANA.scale(1); MAXV = ANA.scale(2); + axes(wgts.ColorbarAxs); cla; + ydat = [0:255]/255 * (MAXV - MINV) + MINV; + hColorbar = imagesc(1,ydat,[0:255]'); colormap(CMAP); + set(wgts.ColorbarAxs,'Tag','ColorbarAxs'); % set this again, some will reset. + set(wgts.ColorbarAxs,'ylim',[MINV MAXV],... + 'YAxisLocation','right','XTickLabel',{},'XTick',[],'Ydir','normal'); + + haxs = [wgts.SagitalAxs, wgts.CoronalAxs, wgts.TransverseAxs]; + set(haxs,'fontsize',8,'xcolor',AXISCOLOR,'ycolor',AXISCOLOR); + GRAHANDLE.sagital = hSag; + GRAHANDLE.coronal = hCor; + GRAHANDLE.transverse = hTra; + GRAHANDLE.colorbar = hColorbar; + + % draw crosshair(s) + axes(wgts.SagitalAxs); + hSagV = line([iY iY],[ 1 nZ],'color','y'); + hSagH = line([ 1 nY],[iZ iZ],'color','y'); + set([hSagV hSagH],... + 'ButtonDownFcn','anz_view(''OrthoView_Callback'',gcbo,''button-sagital'',guidata(gcbo))'); + axes(wgts.CoronalAxs); + hCorV = line([iX iX],[ 1 nZ],'color','y'); + hCorH = line([ 1 nX],[iZ iZ],'color','y'); + set([hCorV hCorH],... + 'ButtonDownFcn','anz_view(''OrthoView_Callback'',gcbo,''button-coronal'',guidata(gcbo))'); + axes(wgts.TransverseAxs); + hTraV = line([iX iX],[ 1 nY],'color','y'); + hTraH = line([ 1 nX],[iY iY],'color','y'); + set([hTraV hTraH],... + 'ButtonDownFcn','anz_view(''OrthoView_Callback'',gcbo,''button-transverse'',guidata(gcbo))'); + if get(wgts.CrosshairCheck,'Value') == 0, + set([hSagV hSagH hCorV hCorH hTraV hTraH],'visible','off'); + end + + GRAHANDLE.sagitalV = hSagV; + GRAHANDLE.sagitalH = hSagH; + GRAHANDLE.coronalV = hCorV; + GRAHANDLE.coronalH = hCorH; + GRAHANDLE.transverseV = hTraV; + GRAHANDLE.transverseH = hTraH; + + % tri-plot + axes(wgts.TriplotAxs); cla; + [xi,yi,zi] = meshgrid(iX,1:nY,1:nZ); + hSag = surface(... + 'xdata',reshape(xi,[nY,nZ]),'ydata',reshape(yi,[nY,nZ]),'zdata',reshape(zi,[nY,nZ]),... + 'cdata',squeeze(ANA.ana256(:,iX,:)),... + 'facecolor','texturemap','edgecolor','none',... + 'CDataMapping','direct','linestyle','none'); + [xi,yi,zi] = meshgrid(1:nX,iY,1:nZ); + hCor = surface(... + 'xdata',reshape(xi,[nX,nZ]),'ydata',reshape(yi,[nX,nZ]),'zdata',reshape(zi,[nX,nZ]),... + 'cdata',squeeze(ANA.ana256(iY,:,:)),... + 'facecolor','texturemap','edgecolor','none',... + 'CDataMapping','direct','linestyle','none'); + [xi,yi,zi] = meshgrid(1:nX,1:nY,iZ); + hTra = surface(... + 'xdata',1:nX,'ydata',1:nY,'zdata',reshape(zi,[nY,nX]),... + 'cdata',permute(squeeze(ANA.ana256(:,:,iZ)),[2 1 3]),... + 'facecolor','texturemap','edgecolor','none',... + 'CDataMapping','direct','linestyle','none'); + + set(gca,'Tag','TriplotAxs'); + set(gca,'fontsize',8,... + 'xlim',[1 nX],'ylim',[1 nY],'zlim',[1 nZ],'zdir','reverse'); + view(50,36); grid on; + xlabel('X'); ylabel('Y'); zlabel('Z'); + + GRAHANDLE.triSagital = hSag; + GRAHANDLE.triCoronal = hCor; + GRAHANDLE.triTransverse = hTra; + + setappdata(wgts.main,'GRAHANDLE',GRAHANDLE); + + OrthoView_Callback(hObject,'dir-reverse',[]); + + case {'redraw'} + OrthoView_Callback(hObject,'slider-sagital',[]); + OrthoView_Callback(hObject,'slider-coronal',[]); + OrthoView_Callback(hObject,'slider-transverse',[]); + + case {'slider-sagital'} + GRAHANDLE = getappdata(wgts.main,'GRAHANDLE'); + if ~isempty(GRAHANDLE), + CMAP = getappdata(wgts.main,'CMAP'); + iX = round(get(wgts.SagitalSldr,'Value')); + tmpimg = squeeze(ANA.ana256(iX,:,:)); + set(GRAHANDLE.sagital,'cdata',ind2rgb(tmpimg',CMAP)); + set(GRAHANDLE.coronalV, 'xdata',[iX iX]); + set(GRAHANDLE.transverseV,'xdata',[iX iX]); + set(wgts.SagitalEdt,'String',sprintf('%d',iX)); + xdata = get(GRAHANDLE.triSagital,'xdata'); + xdata(:) = iX; + set(GRAHANDLE.triSagital,'xdata',xdata,'cdata',tmpimg); + end + + + case {'slider-coronal'} + GRAHANDLE = getappdata(wgts.main,'GRAHANDLE'); + if ~isempty(GRAHANDLE) + CMAP = getappdata(wgts.main,'CMAP'); + iY = round(get(wgts.CoronalSldr,'Value')); + tmpimg = squeeze(ANA.ana256(:,iY,:)); + set(GRAHANDLE.coronal,'cdata',ind2rgb(tmpimg',CMAP)); + set(GRAHANDLE.sagitalV, 'xdata',[iY iY]); + set(GRAHANDLE.transverseH,'ydata',[iY iY]); + set(wgts.CoronalEdt,'String',sprintf('%d',iY)); + ydata = get(GRAHANDLE.triCoronal,'ydata'); + ydata(:) = iY; + set(GRAHANDLE.triCoronal,'ydata',ydata,'cdata',tmpimg); + end + + case {'slider-transverse'} + GRAHANDLE = getappdata(wgts.main,'GRAHANDLE'); + if ~isempty(GRAHANDLE) + CMAP = getappdata(wgts.main,'CMAP'); + iZ = round(get(wgts.TransverseSldr,'Value')); + tmpimg = squeeze(ANA.ana256(:,:,iZ)); + set(GRAHANDLE.transverse,'cdata',ind2rgb(tmpimg',CMAP)); + set(GRAHANDLE.sagitalH, 'ydata',[iZ iZ]); + set(GRAHANDLE.coronalH, 'ydata',[iZ iZ]); + set(wgts.TransverseEdt,'String',sprintf('%d',iZ)); + zdata = get(GRAHANDLE.triTransverse,'zdata'); + zdata(:) = iZ; + set(GRAHANDLE.triTransverse,'zdata',zdata,'cdata',tmpimg); + end + + case {'edit-sagital'} + iX = str2num(get(wgts.SagitalEdt,'String')); + if isempty(iX), + iX = round(get(wgts.SagitalSldr,'Value')); + set(wgts.SagitalEdt,'String',sprintf('%d',iX)); + else + if iX < 0, + iX = 1; + set(wgts.SagitalEdt,'String',sprintf('%d',iX)); + elseif iX > size(ANA.dat,1), + iX = size(ANA.dat,1); + set(wgts.SagitalEdt,'String',sprintf('%d',iX)); + end + set(wgts.SagitalSldr,'Value',iX); + OrthoView_Callback(hObject,'slider-sagital',[]); + end + + case {'edit-coronal'} + iY = str2num(get(wgts.CoronalEdt,'String')); + if isempty(iY), + iY = round(get(wgts.CoronalSldr,'Value')); + set(wgts.CoronalEdt,'String',sprintf('%d',iY)); + else + if iY < 0, + iY = 1; + set(wgts.CoronalEdt,'String',sprintf('%d',iY)); + elseif iY > size(ANA.dat,2), + iY = size(ANA.dat,1); + set(wgts.CoronalEdt,'String',sprintf('%d',iY)); + end + set(wgts.CoronalSldr,'Value',iY); + OrthoView_Callback(hObject,'slider-coronal',[]); + end + + case {'edit-transverse'} + iZ = str2num(get(wgts.TransverseEdt,'String')); + if isempty(iZ), + iZ = round(get(wgts.TransverseSldr,'Value')); + set(wgts.TransverseEdt,'String',sprintf('%d',iZ)); + else + if iZ < 0, + iZ = 1; + set(wgts.TransverseEdt,'String',sprintf('%d',iZ)); + elseif iZ > size(ANA.dat,3), + iZ = size(ANA.dat,1); + set(wgts.TransverseEdt,'String',sprintf('%d',iZ)); + end + set(wgts.TransverseSldr,'Value',iZ); + OrthoView_Callback(hObject,'slider-transverse',[]); + end + + case {'dir-reverse'} + % note that image(),imagesc() reverse Y axies + Xrev = get(wgts.XReverseCheck,'Value'); + Yrev = get(wgts.YReverseCheck,'Value'); + Zrev = get(wgts.ZReverseCheck,'Value'); + if Xrev == 0, + corX = 'normal'; traX = 'normal'; + else + corX = 'reverse'; traX = 'reverse'; + end + if Yrev == 0, + sagX = 'normal'; traY = 'reverse'; + else + sagX = 'reverse'; traY = 'normal'; + end + if Zrev == 0, + sagY = 'reverse'; corY = 'reverse'; + else + sagY = 'normal'; corY = 'normal'; + end + set(wgts.SagitalAxs, 'xdir',sagX,'ydir',sagY); + set(wgts.CoronalAxs, 'xdir',corX,'ydir',corY); + set(wgts.TransverseAxs,'xdir',traX,'ydir',traY); + + case {'crosshair'} + GRAHANDLE = getappdata(wgts.main,'GRAHANDLE'); + if ~isempty(GRAHANDLE), + if get(wgts.CrosshairCheck,'value') == 0, + set(GRAHANDLE.sagitalV, 'visible','off'); + set(GRAHANDLE.sagitalH, 'visible','off'); + set(GRAHANDLE.coronalV, 'visible','off'); + set(GRAHANDLE.coronalH, 'visible','off'); + set(GRAHANDLE.transverseV,'visible','off'); + set(GRAHANDLE.transverseH,'visible','off'); + else + set(GRAHANDLE.sagitalV, 'visible','on'); + set(GRAHANDLE.sagitalH, 'visible','on'); + set(GRAHANDLE.coronalV, 'visible','on'); + set(GRAHANDLE.coronalH, 'visible','on'); + set(GRAHANDLE.transverseV,'visible','on'); + set(GRAHANDLE.transverseH,'visible','on'); + end + end + + case {'button-sagital'} + click = get(wgts.main,'SelectionType'); + if strcmpi(click,'alt') & get(wgts.CrosshairCheck,'Value') == 1, + pt = round(get(wgts.SagitalAxs,'CurrentPoint')); + iY = pt(1,1); iZ = pt(1,2); + if iY > 0 & iY <= size(ANA.dat,2), + set(wgts.CoronalEdt,'String',sprintf('%d',iY)); + set(wgts.CoronalSldr,'Value',iY); + OrthoView_Callback(hObject,'slider-coronal',[]); + end + if iZ > 0 & iZ <= size(ANA.dat,3), + set(wgts.TransverseEdt,'String',sprintf('%d',iZ)); + set(wgts.TransverseSldr,'Value',iZ); + OrthoView_Callback(hObject,'slider-transverse',[]); + end + elseif strcmpi(click,'open'), + % double click + subZoomIn('sagital',wgts,ANA); + end + + case {'button-coronal'} + click = get(wgts.main,'SelectionType'); + if strcmpi(click,'alt') & get(wgts.CrosshairCheck,'Value') == 1, + pt = round(get(wgts.CoronalAxs,'CurrentPoint')); + iX = pt(1,1); iZ = pt(1,2); + if iX > 0 & iX <= size(ANA.dat,1), + set(wgts.SagitalEdt,'String',sprintf('%d',iX)); + set(wgts.SagitalSldr,'Value',iX); + OrthoView_Callback(hObject,'slider-sagital',[]); + end + if iZ > 0 & iZ <= size(ANA.dat,3), + set(wgts.TransverseEdt,'String',sprintf('%d',iZ)); + set(wgts.TransverseSldr,'Value',iZ); + OrthoView_Callback(hObject,'slider-transverse',[]); + end + elseif strcmpi(click,'open'), + % double click + subZoomIn('coronal',wgts,ANA); + end + + case {'button-transverse'} + click = get(wgts.main,'SelectionType'); + if strcmpi(click,'alt') & get(wgts.CrosshairCheck,'Value') == 1, + pt = round(get(wgts.TransverseAxs,'CurrentPoint')); + iX = pt(1,1); iY = pt(1,2); + if iX > 0 & iX <= size(ANA.dat,1), + set(wgts.SagitalEdt,'String',sprintf('%d',iX)); + set(wgts.SagitalSldr,'Value',iX); + OrthoView_Callback(hObject,'slider-sagital',[]); + end + if iY > 0 & iY <= size(ANA.dat,2), + set(wgts.CoronalEdt,'String',sprintf('%d',iY)); + set(wgts.CoronalSldr,'Value',iY); + OrthoView_Callback(hObject,'slider-coronal',[]); + end + elseif strcmpi(click,'open'), + % double click + subZoomIn('transverse',wgts,ANA); + end + + otherwise +end + + +return; + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION to handle lightbox view +function LightboxView_Callback(hObject,eventdata,handles) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +wgts = guihandles(get(hObject,'Parent')); +ANA = getappdata(wgts.main,'ANA'); +ViewMode = get(wgts.ViewModeCmb,'String'); +ViewMode = ViewMode{get(wgts.ViewModeCmb,'Value')}; +switch lower(ViewMode), + case {'lightbox-cor'} + iDimension = 2; + case {'lightbox-sag'} + iDimension = 1; + case {'lightbox-trans'} + iDimension = 3; + otherwise + iDimension = 3; +end +nmaximages = size(ANA.dat,iDimension); + +NCol = 5; +NRow = 4; + +switch lower(eventdata), + case {'init'} + NPages = floor((nmaximages-1)/NCol/NRow)+1; + tmptxt = {}; + for iPage = 1:NPages, + tmptxt{iPage} = sprintf('Page%d: %d-%d',iPage,... + (iPage-1)*NCol*NRow+1,min([nmaximages,iPage*NCol*NRow])); + end + set(wgts.ViewPageList,'String',tmptxt,'Value',1); + ViewMode = get(wgts.ViewModeCmb,'String'); + ViewMode = ViewMode{get(wgts.ViewModeCmb,'Value')}; + if strcmpi(ViewMode,'lightbox'), + LightboxView_Callback(hObject,'redraw',handles); + end + + case {'redraw'} + axes(wgts.LightboxAxs); cla; + pagestr = get(wgts.ViewPageList,'String'); + pagestr = pagestr{get(wgts.ViewPageList,'Value')}; + ipage = sscanf(pagestr,'Page%d:'); + SLICES = (ipage-1)*NCol*NRow+1:min([nmaximages,ipage*NCol*NRow]); + if iDimension == 1, + nX = size(ANA.dat,2); nY = size(ANA.dat,3); + INFSTR = 'Sag'; + elseif iDimension == 2, + nX = size(ANA.dat,1); nY = size(ANA.dat,3); + INFSTR = 'Cor'; + else + nX = size(ANA.dat,1); nY = size(ANA.dat,2); + INFSTR = 'Trans'; + end + X = [0:nX-1]; Y = [nY-1:-1:0]; + CMAP = getappdata(wgts.main,'CMAP'); + + for N = 1:length(SLICES), + iSlice = SLICES(N); + if iDimension == 1, + tmpimg = squeeze(ANA.ana256(iSlice,:,:)); + elseif iDimension == 2, + tmpimg = squeeze(ANA.ana256(:,iSlice,:)); + else + tmpimg = squeeze(ANA.ana256(:,:,iSlice)); + end + iCol = floor((N-1)/NRow)+1; + iRow = mod((N-1),NRow)+1; + offsX = nX*(iRow-1); + offsY = nY*NCol - iCol*nY; + tmpx = X + offsX; tmpy = Y + offsY; + image(tmpx,tmpy,ind2rgb(tmpimg',CMAP)); hold on; + text(min(tmpx)+1,min(tmpy)+1,sprintf('%s=%d',INFSTR,iSlice),... + 'color',[0.9 0.9 0.5],'VerticalAlignment','bottom',... + 'FontName','Comic Sans MS','FontSize',8,'Fontweight','bold'); + end + axes(wgts.LightboxAxs); + set(gca,'Tag','LightboxAxs','color','black'); + set(gca,'XTickLabel',{},'YTickLabel',{},'XTick',[],'YTick',[]); + set(gca,'xlim',[0 nX*NRow],'ylim',[0 nY*NCol]); + set(gca,'YDir','normal'); + + otherwise +end + +return; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION to scale anatomy image +function ANASCALED = subScaleAnatomy(ANA,MINV,MAXV,GAMMA) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if isstruct(ANA), + tmpana = single(ANA.dat); +else + tmpana = single(ANA); +end +clear ANA; +tmpana = (tmpana - MINV) / (MAXV - MINV); +tmpana = round(tmpana*255) + 1; % +1 for matlab indexing +tmpana(find(tmpana(:) < 0)) = 1; +tmpana(find(tmpana(:) > 256)) = 256; + +ANASCALED = uint8(round(tmpana)); + + +return; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION to scale anatomy image +function ANARGB = subScaleAnatomy_OLD(ANA,MINV,MAXV,GAMMA) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if isstruct(ANA), + tmpana = single(ANA.dat); +else + tmpana = single(ANA); +end +clear ANA; +tmpana = (tmpana - MINV) / (MAXV - MINV); +tmpana = round(tmpana*255) + 1; % +1 for matlab indexing +tmpana(find(tmpana(:) < 0)) = 1; +tmpana(find(tmpana(:) > 256)) = 256; +anacmap = gray(256).^(1/GAMMA); +for N = size(tmpana,3):-1:1, + ANARGB(:,:,:,N) = ind2rgb(tmpana(:,:,N),anacmap); +end +clear tmpana; + +ANARGB = permute(ANARGB,[1 2 4 3]); % [x,y,rgb,z] --> [x,y,z,rgb] + + +return; + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION to get a color map +function cmap = subGetColormap(wgts) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +cmapstr = get(wgts.ColormapCmb,'String'); +cmapstr = cmapstr{get(wgts.ColormapCmb,'value')}; +switch lower(cmapstr), + case {'jet','hsv','hot','cool','spring','summer','autumn','winter','gray','bone','copper','pink'} + eval(sprintf('cmap = %s(256);',cmapstr)); + case {'red'} + %cmap = zeros(256,3); cmap(:,1) = 1; + cmap = gray(256); cmap(:,[2 3]) = 0; + case {'green'} + %cmap = zeros(256,3); cmap(:,2) = 1; + cmap = gray(256); cmap(:,[1 3]) = 0; + case {'blue'} + %cmap = zeros(256,3); cmap(:,3) = 1; + cmap = gray(256); cmap(:,[1 2]) = 0; + case {'yellow'} + %cmap = zeros(256,3); cmap(:,1) = 1; cmap(:,2) = 1; + cmap = gray(256); cmap(:,3) = 0; + otherwise + cmap = gray(256); +end + +ANA = getappdata(wgts.main,'ANA'); + +gammav = ANA.scale(3); +if ~isempty(gammav), + cmap = cmap.^(1/gammav); +end + +return + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION to fuse anatomy and functional images +function IMG = subFuseImage(ANARGB,STATV,MINV,MAXV,PVAL,ALPHA,CMAP) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +IMG = ANARGB; +if isempty(STATV) | isempty(PVAL) | isempty(ALPHA), return; end + +PVAL(find(isnan(PVAL(:)))) = 1; % to avoid error; + +tmpdat = repmat(PVAL,[1 1 3]); % for rgb +idx = find(tmpdat(:) < ALPHA); +if ~isempty(idx), + % scale STATV from MINV to MAXV as 0 to 1 + STATV = (STATV - MINV)/(MAXV - MINV); + STATV = round(STATV*255) + 1; % +1 for matlab indexing + STATV(find(STATV(:) < 0)) = 1; + STATV(find(STATV(:) > 256)) = 256; + % map 0-256 as RGB + STATV = ind2rgb(STATV,CMAP); + % replace pixels + IMG(idx) = STATV(idx); +end + + +return; + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCTION to zoom-in plot +function subZoomIn(planestr,wgts,ANA) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +switch lower(planestr) + case {'coronal'} + hfig = wgts.main + 1001; + hsrc = wgts.CoronalAxs; + DX = ANA.ds(1); DY = ANA.ds(3); + N = str2num(get(wgts.CoronalEdt,'String')); + tmpstr = sprintf('CORONAL %03d: %s',N, ANA.imgfile); + tmpxlabel = 'X (mm)'; tmpylabel = 'Z (mm)'; + case {'sagital'} + hfig = wgts.main + 1002; + hsrc = wgts.SagitalAxs; + DX = ANA.ds(2); DY = ANA.ds(3); + N = str2num(get(wgts.SagitalEdt,'String')); + tmpstr = sprintf('SAGITAL %03d: %s',N,ANA.imgfile); + tmpxlabel = 'Y (mm)'; tmpylabel = 'Z (mm)'; + case {'transverse'} + hfig = wgts.main + 1003; + hsrc = wgts.TransverseAxs; + DX = ANA.ds(1); DY = ANA.ds(2); + N = str2num(get(wgts.TransverseEdt,'String')); + tmpstr = sprintf('TRANSVERSE %03d: %s',N,ANA.imgfile); + tmpxlabel = 'X (mm)'; tmpylabel = 'Y (mm)'; +end + +tmpstr = strrep(tmpstr,'\','/'); + +figure(hfig); clf; +pos = get(hfig,'pos'); +set(hfig,'Name',tmpstr,'pos',[pos(1)-680+pos(3) pos(2)-500+pos(4) 680 500]); +haxs = copyobj(hsrc,hfig); +set(haxs,'ButtonDownFcn',''); % clear callback function +set(hfig,'Colormap',get(wgts.main,'Colormap')); +h = findobj(haxs,'type','image'); +set(h,'ButtonDownFcn',''); % clear callback function +set(h,'xdata',get(h,'xdata')*DX,'ydata',get(h,'ydata')*DY); +nx = length(get(h,'xdata')); ny = length(get(h,'ydata')); + +% to keep actual size correct, do like this... +anasz = size(ANA.dat).*ANA.ds; +maxsz = max(anasz); +%set(haxs,'Position',[0.01 0.1 nx*DX/100 ny*DY/100],'units','normalized'); +set(haxs,'Position',[0.01 0.1 nx*DX/maxsz*0.85 ny*DY/maxsz*0.85],'units','normalized'); +h = findobj(haxs,'type','line'); +for N =1:length(h), + set(h(N),'xdata',get(h(N),'xdata')*DX,'ydata',get(h(N),'ydata')*DY); +end +set(haxs,'xlim',get(haxs,'xlim')*DX,'ylim',get(haxs,'ylim')*DY); +set(haxs,'xtick',[0 10 20 30 40 50 60 70 80 90 100 110 120]); +set(haxs,'ytick',[0 10 20 30 40 50 60 70 80 90 100 110 120]); +xlabel(tmpxlabel); ylabel(tmpylabel); +title(haxs,strrep(tmpstr,'_','\_')); +%title(haxs,tmpstr); +daspect(haxs,[1 1 1]); +pos = get(haxs,'pos'); +hbar = copyobj(wgts.ColorbarAxs,hfig); +set(hbar,'pos',[0.85 pos(2) 0.045 pos(4)]); + +return; diff --git a/mpi_code/mex_anz/anz_write.m b/mpi_code/mex_anz/anz_write.m new file mode 100644 index 0000000..10559b7 --- /dev/null +++ b/mpi_code/mex_anz/anz_write.m @@ -0,0 +1,93 @@ +function varargout = anz_write(filename,HDR,IMGDAT) +%ANZ_WRITE - writes ANALYZE image/header +% ANZ_WRITE(HDRFILE,HDR,IMGDAT) writes ANALYZE(TM) image. +% +% VERSION : +% 0.90 27.02.07 YM pre-release +% +% See also ANZ_READ HDR_WRITE + +if nargin == 0, help anz_write; return; end + +if isempty(filename), + fprintf('\n ERROR %s: no filename specified.\n',mfilename); + return +end + +[fp,fr,fe] = fileparts(filename); + +imgfile = fullfile(fp,sprintf('%s.img',fr)); +hdrfile = fullfile(fp,sprintf('%s.hdr',fr)); + + +% /* Acceptable values for datatype */ +% #define DT_NONE 0 +% #define DT_UNKNOWN 0 +% #define DT_BINARY 1 +% #define DT_UNSIGNED_CHAR 2 +% #define DT_SIGNED_SHORT 4 +% #define DT_SIGNED_INT 8 +% #define DT_FLOAT 16 +% #define DT_COMPLEX 32 +% #define DT_DOUBLE 64 +% #define DT_RGB 128 +% #define DT_ALL 255 + +switch lower(HDR.dime.datatype) + %case {1,'binary'} + % ndatatype = 1; + % wdatatype = 'int8'; + case {2,'uchar', 'uint8'} + ndatatype = 2; + wdatatype = 'uint8'; + case {4,'short', 'int16'} + ndatatype = 4; + wdatatype = 'int16'; + case {8,'int', 'int32', 'long'} + ndatatype = 8; + wdatatype = 'int32'; + case {16,'float', 'single'} + ndatatype = 16; + wdatatype = 'single'; + %case {32,'complex'} + % ndatatype = 32; + % wdatatype = 'complex'; + case {64,'double'} + ndatatype = 64; + wdatatype = 'double'; + case {128,'rgb'} + ndatatype = 128; + wdatatype = 'uint8'; + otherwise + if ischar(HDR.dime.datatype), + fprintf('\n %s: unsupported datatype(=%s).\n',mfilename,HDR.dime.datatype); + else + fprintf('\n %s: unsupported datatype(=%d).\n',mfilename,HDR.dime.datatype); + end + return +end + +% check image size +imgdim = HDR.dime.dim([1:HDR.dime.dim(1)]+1); +nvox = prod(double(HDR.dime.dim([1:HDR.dime.dim(1)]+1))); +if ndatatype == 128, + nvox = nvox*3; +end +if numel(IMGDAT) ~= nvox, + fprintf('\n ERROR %s: dimensional mismatch, '); + fprintf(' HDR.dime.dim = ['); fprintf(' %d',HDR.dime.dim([1:HDR.dime.dim(1)]+1)); + fprintf(' ], size(IMGDAT)=['); fprintf(' %d',size(IMGDAT)); + fprintf(' ]\n'); + return +end + + + +hdr_write(hdrfile,HDR); + +fid = fopen(imgfile,'w'); +fwrite(fid,IMGDAT,wdatatype); +fclose(fid); + + +return diff --git a/mpi_code/mex_anz/anzview.m b/mpi_code/mex_anz/anzview.m new file mode 100644 index 0000000..de62ab1 --- /dev/null +++ b/mpi_code/mex_anz/anzview.m @@ -0,0 +1,6 @@ +function varargout = anzview(varargin) +if nargout, + varargout = anz_view(varargin{:}); +else + anz_view(varargin{:}); +end diff --git a/mpi_code/mex_anz/bru2analyze.m b/mpi_code/mex_anz/bru2analyze.m new file mode 100644 index 0000000..23427b1 --- /dev/null +++ b/mpi_code/mex_anz/bru2analyze.m @@ -0,0 +1,489 @@ +function varargout = bru2analyze(varargin) +%BRU2ANALYZE - dumps Brucker 2dseq as ANALIZE-7 format for SPM. +% BRU2ANALYZE(2DSEQFILE,...) +% BRU2ANALYZE(SESSION,EXPNO,...) dumps Brucker 2dseq as ANLYZE-7 format for SPM. +% Optional setting can be given as a pair of the name and value, like, +% BRU2ANALYZE(2dseqfile,'SaveDir','y:/temp/spm') % save to 'y:/temp/spm' +% BRU2ANALYZE(2dseqfile,'FlipDim',[2]) % flips Y +% Supported optional arguments are +% 'ImageCrop' : [x y width height] +% 'SliceCrop' : [slice-start num.slices] +% 'FlipDim' : [1,2...] dimension(s) to flip, 1/2/3 as X/Y/Z +% 'ExportAs2D' : 0/1 to export volumes 2D +% 'SplitInTime' : 0/1 to export time series to different files +% 'SaveDir' : directory to save +% 'FileRoot' : filename without extension +% 'Verbose' : 0/1 +% +% EXAMPLE: +% % exporting functional 2dseq for spm +% >> bru2analyze('m02lx1',1) +% % exporting 3D-MDEFT "WITH Y-AXIS FLIP" for BrainSight. +% >> bru2analyze('//wks8/guest/D02.G01/5/pdata/1/2dseq','FlipDim',[2]) +% % exporting 3D-MDEFT as 2D images for photoshop etc. +% >> bru2analyze('//wks8/guest/H03.BJ1/5/pdata/1/2dseq','SaveDir','../H03','ExportAs2D',1); +% +% IMAGE ORIENTATION : +% hdr.hist.orient:. +% 0 transverse unflipped (ANALYZE default) +% +X=left, +Y=anterior, +Z=superior +% 1 coronal unflipped +% 2 sagittal unflipped +% 3 transverse flipped +% 4 coronal flipped +% 5 sagittal flipped +% +% VERSION : +% 0.90 13.06.05 YM pre-release +% 0.91 14.06.05 YM bug fix, tested with 'm02lx1' +% 0.92 08.08.05 YM checks reco.RECO_byte_order for machine format. +% 0.93 12.02.07 YM bug fix on 3D-MDEFT +% 0.94 13.02.07 YM supports FLIPDIM +% 0.95 21.02.07 YM supports EXPORT_AS_2D +% 0.96 27.02.07 YM supports SAVEDIR, hdr.dim.dim(1) as 4 always. +% 0.97 20.03.08 YM supports 'FileRoot' as option. +% 0.98 08.04.08 YM supports 'Verbose' as option. +% 0.99 14.09.09 YM bug fix of RECO_transposition, help by MB. +% +% See also HDR_INIT HDR_WRITE TCIMG2SPM SPM2TCIMG PVREAD_RECO PVREAD_ACQP + +if nargin == 0, help bru2analyze; return; end + +SAVEDIR = 'spmanz'; + +% GET FILENAME, CROPPING INFO. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +IMGCROP = []; SLICROP = []; FLIPDIM = [2]; +EXPORT_AS_2D = []; SPLIT_IN_TIME = []; +FILE_ROOT = ''; +VERBOSE = 1; +if ischar(varargin{1}) & ~isempty(strfind(varargin{1},'2dseq')), + % called like BRU2ANALYZE(2DSEQFILE,varargin) + TDSEQFILE = varargin{1}; + % parse inputs + for N = 2:2:nargin, + switch lower(varargin{N}), + case {'imgcrop','imagecrop','image crop'} + IMGCROP = varargin{N+1}; + case {'slicop','slicecrop','slice crop'} + SLICROP = varargin{N+1}; + case {'flipdim','flip dim','flip dimension'} + FLIPDIM = varargin{N+1}; + case {'exportas2d','export as 2d','export2d','export 2d'} + EXPORT_AS_2D = varargin{N+1}; + case {'splitintime','splittime','split in time','splite time','tsplit'} + SPLIT_IN_TIME = varargin{N+1}; + case {'savedir','save dir','savedirectory','save directory'} + SAVEDIR = varargin{N+1}; + case {'fileroot','file root','froot','savename','filename','fname'} + FILE_ROOT = varargin{N+1}; + case {'verbose'} + VERBOSE = varargin{N+1}; + end + end +else + % called like BRU2ANALYZE(SESSION,EXPNO,varargin) + Ses = goto(varargin{1}); + ExpNo = varargin{2}; + if ~isnumeric(ExpNo) | length(ExpNo) ~= 1, + fprintf('%s ERROR: 2nd arg. must be a numeric ExpNo.\n',mfilename); + return; + end + if nargout, + varargout = bru2analyze(catfilename(Ses,ExpNo,'2dseq'),varargin{:}); + else + bru2analyze(catfilename(Ses,ExpNo,'2dseq'),varargin{:}); + end + return +end +if isempty(EXPORT_AS_2D), EXPORT_AS_2D = 0; end +if isempty(SPLIT_IN_TIME), SPLIT_IN_TIME = 1; end +if ~isempty(FLIPDIM) & ischar(FLIPDIM), + % 'FLIPDIM' is given as a string like, 'Y' or 'XZ' + tmpdim = []; + for N=1:length(FLIPDIM), + tmpidx = strfind('xyz',lower(FLIPDIM(N))); + if ~isempty(tmpidx), tmpdim(end+1) = tmpidx; end + end + FLIPDIM = tmpdim; + clear tmpdim tmpidx; +end + + +[fp,fr,fe] = fileparts(TDSEQFILE); +RECOFILE = fullfile(fp,'reco'); +[fp,fr,fe] = fileparts(fileparts(fp)); +ACQPFILE = fullfile(fp,'acqp'); + +if exist(TDSEQFILE,'file') == 0, + fprintf(' %s ERROR: ''%s'' not found.\n',mfilename,TDSEQFILE); + return; +end +if exist(RECOFILE,'file') == 0, + fprintf(' %s ERROR: ''%s'' not found.\n',mfilename,RECOFILE); + return; +end +if exist(ACQPFILE,'file') == 0, + fprintf(' %s ERROR: ''%s'' not found.\n',mfilename,ACQPFILE); + return; +end + + +% READ RECO/ACQP INFO %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if VERBOSE > 0, + fprintf(' %s: reading reco/acqp',mfilename); +end +reco = pvread_reco(RECOFILE); +acqp = pvread_acqp(ACQPFILE); + +if length(reco.RECO_size) == 3, + % likely mdeft + nx = reco.RECO_size(1); + ny = reco.RECO_size(2); + nz = reco.RECO_size(3); + xres = reco.RECO_fov(1) / reco.RECO_size(1) * 10; % 10 for cm -> mm + yres = reco.RECO_fov(2) / reco.RECO_size(2) * 10; % 10 for cm -> mm + zres = reco.RECO_fov(3) / reco.RECO_size(3) * 10; % 10 for cm -> mm +else + % likely epi + nx = reco.RECO_size(1); + ny = reco.RECO_size(2); + nz = acqp.NSLICES; + xres = reco.RECO_fov(1) / reco.RECO_size(1) * 10; % 10 for cm -> mm + yres = reco.RECO_fov(2) / reco.RECO_size(2) * 10; % 10 for cm -> mm + if nz > 1, + zres = acqp.ACQ_slice_sepn; + else + zres = acqp.ACQ_slice_thick; + end +end + +tmpfs = dir(TDSEQFILE); +switch reco.RECO_wordtype, + case {'_8BIT_UNSGN_INT'} + dtype = 'uint8'; + nt = floor(tmpfs.bytes/nx/ny/nz); + case {'_16BIT_SGN_INT'} + dtype = 'int16'; + nt = floor(tmpfs.bytes/nx/ny/nz/2); + case {'_32BIT_SGN_INT'} + dtype = 'int32'; + nt = floor(tmpfs.bytes/nx/ny/nz/4); +end +if nt == 1, SPLIT_IN_TIME = 0; end +if strcmpi(reco.RECO_byte_order,'bigEndian'), + machineformat = 'ieee-be'; +else + machineformat = 'ieee-le'; +end + + +% check trasposition on reco +transpos = 0; +if isfield(reco,'RECO_transposition'), + transpos = reco.RECO_transposition(1); +elseif isfield(reco,'RECO_transpose_dim'), + transpos = reco.RECO_transpose_dim(1); +end +if any(transpos), + if transpos == 1, + % (x,y,z) --> (y,x,z) + tmpx = nx; tmpy = ny; + nx = tmpy; ny = tmpx; + tmpx = xres; tmpy = yres; + xres = tmpy; yres = tmpx; + elseif transpos == 2, + % (x,y,z) --> (x,z,y) + tmpy = ny; tmpz = nz; + ny = tmpz; nz = tmpy; + tmpy = yres; tmpz = zres; + yres = tmpz; zres = tmpy; + elseif transpos == 3, + % (x,y,z) --> (z,y,x) + tmpx = nx; tmpz = nz; + nx = tmpz; nz = tmpx; + tmpx = xres; tmpz = zres; + xres = tmpz; zres = tmpx; + end + clear tmpx tmpy tmpz +end + + +% READ IMAGE DATA %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if VERBOSE > 0, + fprintf('/2dseq[%dx%dx%d %d %s]...',nx,ny,nz,nt,dtype); +end +fid = fopen(TDSEQFILE,'rb',machineformat); +IMG = fread(fid,inf,sprintf('%s=>%s',dtype,dtype)); +fclose(fid); +if nt > 1, + IMG = reshape(IMG,[nx,ny,nz,nt]); +else + IMG = reshape(IMG,[nx,ny,nz]); +end +RECOSZ = size(IMG); +if ~isempty(FLIPDIM), + if VERBOSE > 0, + tmpstr = 'XYZT'; + fprintf('flipping(%s)...',tmpstr(FLIPDIM)); + end + for N = 1:size(FLIPDIM), + IMG = flipdim(IMG,FLIPDIM(N)); + end +end +if ~isempty(IMGCROP), + if VERBOSE > 0, + fprintf('imgcrop[%d:%d %d:%d]...',... + IMGCROP(1),IMGCROP(3)+IMGCROP(1)-1,... + IMGCROP(2),IMGCROP(4)+IMGCROP(2)-1); + end + idx = [1:IMGCROP(3)] + IMGCROP(1) - 1; + IMG = IMG(idx,:,:,:); + idx = [1:IMGCROP(4)] + IMGCROP(2) - 1; + IMG = IMG(:,idx,:,:); +end +if ~isempty(SLICROP), + if VERBOSE > 0, + fprintf('slicrop[%d:%d]',SLICROP(1),SLICROP(2)+SLICROP(1)-1); + end + idx = [1:SLICROP(2)] + SLICROP(1) - 1; + IMG = IMG(:,:,idx,:); +end + + +% PREPARE HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% use size() instead of nx/ny/nz/nt because of cropping +if nt > 1, + % functional + if SPLIT_IN_TIME > 0, + if size(IMG,3) == 1 || EXPORT_AS_2D > 0, + %dim = [2 size(IMG,1) size(IMG,2)]; + %pixdim = [2 xres yres]; + dim = [4 size(IMG,1) size(IMG,2) 1 1]; + pixdim = [3 xres yres zres]; + else + dim = [4 size(IMG,1) size(IMG,2) size(IMG,3) 1]; + pixdim = [3 xres yres zres]; + end + else + if EXPORT_AS_2D & size(IMG,3) > 1, + %dim = [3 size(IMG,1) size(IMG,2) size(IMG,4)]; + %pixdim = [2 xres yres]; + dim = [4 size(IMG,1) size(IMG,2) 1 size(IMG,4)]; + pixdim = [3 xres yres zres]; + else + dim = [4 size(IMG,1) size(IMG,2) size(IMG,3) size(IMG,4)]; + pixdim = [3 xres yres zres]; + end + end +else + % anatomy + if size(IMG,3) == 1 || EXPORT_AS_2D > 0, + %dim = [2 size(IMG,1) size(IMG,2)]; + %pixdim = [2 xres yres]; + dim = [4 size(IMG,1) size(IMG,2) 1 1]; + pixdim = [3 xres yres zres]; + else + %dim = [3 size(IMG,1) size(IMG,2) size(IMG,3)]; + dim = [4 size(IMG,1) size(IMG,2) size(IMG,3) 1]; + pixdim = [3 xres yres zres]; + end +end + + +HDR = hdr_init('dim',dim,'datatype',dtype,'pixdim',pixdim,'glmax',intmax('int16')); + + + +% SET OUTPUTS, IF REQUIRED. OTHERWISE SAVE TO FILES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if nargout, + varargout{1} = HDR; + if nargout > 1, + varargout{2} = IMG; + end +else + if VERBOSE > 0, + fprintf(' saving to ''%s''(2D=%d,SplitInTime=%d)...',SAVEDIR,EXPORT_AS_2D,SPLIT_IN_TIME); + end + %if exist(fullfile(pwd,SAVEDIR),'dir') == 0, + % mkdir(pwd,SAVEDIR); + %end + if exist(SAVEDIR,'dir') == 0, + mkdir(SAVEDIR); + end + if isempty(FILE_ROOT), + if exist('Ses','var') & ~isempty(Ses), + froot = sprintf('%s_%03d',Ses.name,ExpNo); + else + froot = subGetFileRoot(TDSEQFILE); + if isempty(froot), + froot = sprintf('anz'); + end + end + else + froot = FILE_ROOT; + end + + if nt > 1, + subExportFunctional(SAVEDIR,froot,HDR,IMG,EXPORT_AS_2D,SPLIT_IN_TIME); + else + % anatomy + if EXPORT_AS_2D > 0 & size(IMG,3) > 1, + for S = 1:size(IMG,3), + IMGFILE = sprintf('%s/%s_sl%03d.img',SAVEDIR,froot,S); + HDRFILE = sprintf('%s/%s_sl%03d.hdr',SAVEDIR,froot,S); + hdr_write(HDRFILE,HDR); + fid = fopen(IMGFILE,'wb'); + fwrite(fid,IMG(:,:,S),class(IMG)); + fclose(fid); + end + else + IMGFILE = sprintf('%s/%s.img',SAVEDIR,froot); + HDRFILE = sprintf('%s/%s.hdr',SAVEDIR,froot); + hdr_write(HDRFILE,HDR); + fid = fopen(IMGFILE,'wb'); + fwrite(fid,IMG,class(IMG)); + fclose(fid); + end + end + % write information as a text file + subWriteInfo(SAVEDIR,froot,HDR,... + TDSEQFILE,RECOSZ,[xres,yres,zres],EXPORT_AS_2D,SPLIT_IN_TIME,IMGCROP,SLICROP,FLIPDIM); +end + + +if VERBOSE > 0, + fprintf(' done.\n'); +end + +return; + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function froot = subGetFileRoot(TDSEQFILE) + +try, + tmpf = TDSEQFILE; + for N=1:4, [tmpf scanno] = fileparts(tmpf); end + [tmpf,sesname,sesext] = fileparts(tmpf); + sesname = sprintf('%s%s',sesname,sesext); +catch + sesname = ''; scanno = ''; +end + +if ~isempty(scanno) & ~isempty(sesname), + froot = sprintf('%s_scan%s',strrep(sesname,'.',''),scanno); +else + froot = 'anz'; +end + +return + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function subExportFunctional(SAVEDIR,froot,HDR,IMG,EXPORT_AS_2D,SPLIT_IN_TIME) + +if SPLIT_IN_TIME > 0, + if EXPORT_AS_2D > 0 & size(IMG,3) > 1, + for N = 1:size(IMG,4), + for S = 1:size(IMG,3), + IMGFILE = sprintf('%s/%s_%05d_sl%03d.img',SAVEDIR,froot,N,S); + HDRFILE = sprintf('%s/%s_%05d_sl%03d.hdr',SAVEDIR,froot,N,S); + hdr_write(HDRFILE,HDR); + fid = fopen(IMGFILE,'wb'); + fwrite(fid,IMG(:,:,S,N),class(IMG)); + fclose(fid); + end + end + else + for N = 1:size(IMG,4), + IMGFILE = sprintf('%s/%s_%05d.img',SAVEDIR,froot,N); + HDRFILE = sprintf('%s/%s_%05d.hdr',SAVEDIR,froot,N); + hdr_write(HDRFILE,HDR); + fid = fopen(IMGFILE,'wb'); + fwrite(fid,IMG(:,:,:,N),class(IMG)); + fclose(fid); + end + end +else + if EXPORT_AS_2D > 0 & size(IMG,3) > 1, + for S = 1:size(IMG,3), + IMGFILE = sprintf('%s/%s_sl%05d.img',SAVEDIR,froot,S); + HDRFILE = sprintf('%s/%s_sl%05d.hdr',SAVEDIR,froot,S); + hdr_write(HDRFILE,HDR); + fid = fopen(IMGFILE,'wb'); + fwrite(fid,IMG(:,:,S,:),class(IMG)); + fclose(fid); + end + else + IMGFILE = sprintf('%s/%s.img',SAVEDIR,froot); + HDRFILE = sprintf('%s/%s.hdr',SAVEDIR,froot); + hdr_write(HDRFILE,HDR); + fid = fopen(IMGFILE,'wb'); + fwrite(fid,IMG(:,:,:,:),class(IMG)); + fclose(fid); + end +end + + +return + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function subWriteInfo(SAVEDIR,froot,HDR,TDSEQFILE,RECOSZ,XYZRES,EXPORT_AS_2D,SPLIT_IN_TIME,IMGCROP,SLICROP,FLIPDIM) + +TXTFILE = sprintf('%s/%s_info.txt',SAVEDIR,froot); +fid = fopen(TXTFILE,'wt'); +fprintf(fid,'date: %s\n',datestr(now)); +fprintf(fid,'program: %s\n',mfilename); + +fprintf(fid,'[input]\n'); +fprintf(fid,'2dseq: %s\n',TDSEQFILE); +fprintf(fid,'recosize: ['); fprintf(fid,' %d',RECOSZ); fprintf(fid,' ]\n'); +fprintf(fid,'xyzres: ['); fprintf(fid,' %g',XYZRES); fprintf(fid,' ] in mm\n'); +fprintf(fid,'imgcrop: ['); +if ~isempty(IMGCROP), + fprintf(fid,'%d %d %d %d',IMGCROP(1),IMGCROP(2),IMGCROP(3),IMGCROP(4)); +end +fprintf(fid,'] as [x y w h]\n'); +fprintf(fid,'slicrop: ['); +if ~isempty(SLICROP), + fprintf(fid,'%d %d',SLICROP(1),SLICROP(2)); +end +fprintf(fid,'] as [start n]\n'); +fprintf(fid,'flipdim: ['); +if ~isempty(FLIPDIM), fprintf(fid,' %d',FLIPDIM); end +fprintf(fid,' ]\n'); +fprintf(fid,'export_as_2d: %d\n',EXPORT_AS_2D); +fprintf(fid,'split_in_time: %d\n',SPLIT_IN_TIME); + +fprintf(fid,'[output]\n'); +fprintf(fid,'dim: ['); fprintf(fid,' %d',HDR.dime.dim(2:end)); fprintf(fid,' ]\n'); +fprintf(fid,'pixdim: ['); fprintf(fid,' %g',HDR.dime.pixdim(2:end)); fprintf(fid,' ] in mm\n'); +fprintf(fid,'datatype: %d',HDR.dime.datatype); +switch HDR.dime.datatype + case 1 + dtype = 'binary'; + case 2 + dtype = 'char'; + case 4 + dtype = 'int16'; + case 8 + dtype = 'int32'; + case 16 + dtype = 'float'; + case 32 + dtype = 'complex'; + case 64 + dtype = 'double'; + case 128 + dtype = 'rgb'; + otherwise + dtype = 'unknown'; +end +fprintf(fid,'(%s)\n',dtype); + +fclose(fid); + +return diff --git a/mpi_code/mex_anz/bru2spm.m b/mpi_code/mex_anz/bru2spm.m new file mode 100644 index 0000000..93faef4 --- /dev/null +++ b/mpi_code/mex_anz/bru2spm.m @@ -0,0 +1,19 @@ +function varargout = bru2spm(varargin) +%BRU2SPM - dumps Brucker 2dseq as ANALIZE-7 format for SPM. +% BRU2SPM() just calls BRU2ANALYZE function and remains to keep compatibility. +% See BRU2ANALYZE for detail. +% +% VERSION : +% 0.90 24.10.07 YM renamed to bru2analyze.m +% +% See also BRU2ANALYZE + +if nargin == 0, help bru2spm; return; end + +if nargout, + varargout = bru2analyze(varargin{:}); +else + bru2analyze(varargin{:}); +end + +return diff --git a/mpi_code/mex_anz/dbh.h b/mpi_code/mex_anz/dbh.h new file mode 100644 index 0000000..595ff7a --- /dev/null +++ b/mpi_code/mex_anz/dbh.h @@ -0,0 +1,140 @@ +/* ANALYZE(TM) Header File Format +* +* (c) Copyright, 1986-1995 +* Biomedical Imaging Resource +* Mayo Foundation +* +* dbh.h +* +* databse sub-definitions +* +* 2005.05.31 Yusuke MURAYAMA @MPI : +* changed "short int"-->"short". +* adds _DBH_H_INCLUDED, __cplusplus and #pragma pack. +* 2005.06.01 Yusuke MURAYAMA @MPI : +* modified "image_dimension" to make compatible to Bru2Anz.exe. +*/ + +#ifndef _DBH_H_INCLUDED +#define _DBH_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#define BRU2ANZ + + +#pragma pack(1) +struct header_key /* header key */ +{ /* off + size */ + int sizeof_hdr; /* 0 + 4 */ + char data_type[10]; /* 4 + 10 */ + char db_name[18]; /* 14 + 18 */ + int extents; /* 32 + 4 */ + short session_error; /* 36 + 2 */ + char regular; /* 38 + 1 */ + char hkey_un0; /* 39 + 1 */ +}; /* total=40 bytes */ + + +struct image_dimension +{ /* off + size */ + short dim[8]; /* 0 + 16 */ +#ifdef BRU2ANZ + char vox_units[4]; /* 16 + 4 */ + // up to 3 characters for the voxels units label; i.e. mm., um., cm. + char cal_units[8]; /* 20 + 8 */ + // up to 7 characters for the calibration units label; i.e. HU +#else + short unused8; /* 16 + 2 */ + short unused9; /* 18 + 2 */ + short unused10; /* 20 + 2 */ + short unused11; /* 22 + 2 */ + short unused12; /* 24 + 2 */ + short unused13; /* 26 + 2 */ +#endif + short unused14; /* 28 + 2 */ + short datatype; /* 30 + 2 */ + short bitpix; /* 32 + 2 */ + short dim_un0; /* 34 + 2 */ + float pixdim[8]; /* 36 + 32 */ + /* + pixdim[] specifies the voxel dimensitons: + pixdim[1] - voxel width + pixdim[2] - voxel height + pixdim[3] - interslice distance + ...etc + */ + float vox_offset; /* 68 + 4 */ +#ifdef BRU2ANZ + float roi_scale; /* 72 + 4 */ +#else + float funused1; /* 72 + 4 */ +#endif + float funused2; /* 76 + 4 */ + float funused3; /* 80 + 4 */ + float cal_max; /* 84 + 4 */ + float cal_min; /* 88 + 4 */ + float compressed; /* 92 + 4 */ + float verified; /* 96 + 4 */ + int glmax,glmin; /* 100 + 8 */ +}; /* total=108 bytes */ + + +struct data_history +{ /* off + size */ + char descrip[80]; /* 0 + 80 */ + char aux_file[24]; /* 80 + 24 */ + char orient; /* 104 + 1 */ + char originator[10]; /* 105 + 10 */ + char generated[10]; /* 115 + 10 */ + char scannum[10]; /* 125 + 10 */ + char patient_id[10]; /* 135 + 10 */ + char exp_date[10]; /* 145 + 10 */ + char exp_time[10]; /* 155 + 10 */ + char hist_un0[3]; /* 165 + 3 */ + int views; /* 168 + 4 */ + int vols_added; /* 172 + 4 */ + int start_field; /* 176 + 4 */ + int field_skip; /* 180 + 4 */ + int omax, omin; /* 184 + 8 */ + int smax, smin; /* 192 + 8 */ +}; /* total=200 bytes */ + +struct dsr +{ + struct header_key hk; /* 0 + 40 */ + struct image_dimension dime; /* 40 + 108 */ + struct data_history hist; /* 148 + 200 */ +}; /* total= 348 bytes */ + +typedef struct +{ + float real; + float imag; +} COMPLEX; + +#pragma pack() + + +/* Acceptable values for datatype */ +#define DT_NONE 0 +#define DT_UNKNOWN 0 +#define DT_BINARY 1 +#define DT_UNSIGNED_CHAR 2 +#define DT_SIGNED_SHORT 4 +#define DT_SIGNED_INT 8 +#define DT_FLOAT 16 +#define DT_COMPLEX 32 +#define DT_DOUBLE 64 +#define DT_RGB 128 +#define DT_ALL 255 + + + +#ifdef __cplusplus +} +#endif + +#endif // end of _DBH_H_INCLUDED diff --git a/mpi_code/mex_anz/dbh.orig.h b/mpi_code/mex_anz/dbh.orig.h new file mode 100644 index 0000000..93c232f --- /dev/null +++ b/mpi_code/mex_anz/dbh.orig.h @@ -0,0 +1,123 @@ +/* ANALYZE(TM) Header File Format +* +* (c) Copyright, 1986-1995 +* Biomedical Imaging Resource +* Mayo Foundation +* +* dbh.h +* +* databse sub-definitions +* +* 2005.05.31 Yusuke MURAYAMA @MPI : +* changed "short int"-->"short". +* adds _DBH_H_INCLUDED, __cplusplus and #pragma pack. +*/ + +#ifndef _DBH_H_INCLUDED +#define _DBH_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + + +#pragma pack(1) +struct header_key /* header key */ +{ /* off + size */ + int sizeof_hdr; /* 0 + 4 */ + char data_type[10]; /* 4 + 10 */ + char db_name[18]; /* 14 + 18 */ + int extents; /* 32 + 4 */ + short session_error; /* 36 + 2 */ + char regular; /* 38 + 1 */ + char hkey_un0; /* 39 + 1 */ +}; /* total=40 bytes */ + +struct image_dimension +{ /* off + size */ + short dim[8]; /* 0 + 16 */ + short unused8; /* 16 + 2 */ + short unused9; /* 18 + 2 */ + short unused10; /* 20 + 2 */ + short unused11; /* 22 + 2 */ + short unused12; /* 24 + 2 */ + short unused13; /* 26 + 2 */ + short unused14; /* 28 + 2 */ + short datatype; /* 30 + 2 */ + short bitpix; /* 32 + 2 */ + short dim_un0; /* 34 + 2 */ + float pixdim[8]; /* 36 + 32 */ + /* + pixdim[] specifies the voxel dimensitons: + pixdim[1] - voxel width + pixdim[2] - voxel height + pixdim[3] - interslice distance + ...etc + */ + float vox_offset; /* 68 + 4 */ + float funused1; /* 72 + 4 */ + float funused2; /* 76 + 4 */ + float funused3; /* 80 + 4 */ + float cal_max; /* 84 + 4 */ + float cal_min; /* 88 + 4 */ + float compressed; /* 92 + 4 */ + float verified; /* 96 + 4 */ + int glmax,glmin; /* 100 + 8 */ +}; /* total=108 bytes */ + +struct data_history +{ /* off + size */ + char descrip[80]; /* 0 + 80 */ + char aux_file[24]; /* 80 + 24 */ + char orient; /* 104 + 1 */ + char originator[10]; /* 105 + 10 */ + char generated[10]; /* 115 + 10 */ + char scannum[10]; /* 125 + 10 */ + char patient_id[10]; /* 135 + 10 */ + char exp_date[10]; /* 145 + 10 */ + char exp_time[10]; /* 155 + 10 */ + char hist_un0[3]; /* 165 + 3 */ + int views; /* 168 + 4 */ + int vols_added; /* 172 + 4 */ + int start_field; /* 176 + 4 */ + int field_skip; /* 180 + 4 */ + int omax, omin; /* 184 + 8 */ + int smax, smin; /* 192 + 8 */ +}; /* total=200 bytes */ + +struct dsr +{ + struct header_key hk; /* 0 + 40 */ + struct image_dimension dime; /* 40 + 108 */ + struct data_history hist; /* 148 + 200 */ +}; /* total= 348 bytes */ + +typedef struct +{ + float real; + float imag; +} COMPLEX; + +#pragma pack() + + +/* Acceptable values for datatype */ +#define DT_NONE 0 +#define DT_UNKNOWN 0 +#define DT_BINARY 1 +#define DT_UNSIGNED_CHAR 2 +#define DT_SIGNED_SHORT 4 +#define DT_SIGNED_INT 8 +#define DT_FLOAT 16 +#define DT_COMPLEX 32 +#define DT_DOUBLE 64 +#define DT_RGB 128 +#define DT_ALL 255 + + + +#ifdef __cplusplus +} +#endif + +#endif // end of _DBH_H_INCLUDED diff --git a/mpi_code/mex_anz/hdr_init.m b/mpi_code/mex_anz/hdr_init.m new file mode 100644 index 0000000..6f82c1d --- /dev/null +++ b/mpi_code/mex_anz/hdr_init.m @@ -0,0 +1,260 @@ +function HDR = hdr_init(varargin) +%HDR_INIT - initializes ANALIZE(TM) header structure. +% HDR = HDR_INIT() returns ANALIZE header structure. +% HDR = HDR_INIT(NAME1,VALUE1,NAME2,VALUE2,...) returns +% ANALYZE header initialized by given arguments. +% +% EXAMPLE : +% hdr = hdr_init; +% hdr = hdr_init('dim',[4 256 256 1 148 0 0 0],'datatype',8); +% hdr = hdr_init('dim',[4 256 256 1 148 0 0 0],'datatype','int32'); +% hdr = hdr_init('dim',[4 256 256 1 148 0 0 0],'datatype','_32BIT_SGN_INT'); +% +% VERSION : +% 0.90 01.06.05 YM first release. +% 0.91 01.06.05 YM modified for BRU2ANZ. +% 0.92 13.06.05 YM accepts '_16BIT_SGN_INT' and '_32BIT_SGN_INT' as 'datatype'. +% 0.93 12.09.05 YM set dime.roi_scale as 1 for safety. +% +% See also HDR_READ, HDR_WRITE, DBH.H +% +% ANALYZE HEADER =================================== +% #pragma pack(1) +% struct header_key /* header key */ +% { /* off + size */ +% long sizeof_hdr; /* 0 + 4 */ <---- must be 384 +% char data_type[10]; /* 4 + 10 */ +% char db_name[18]; /* 14 + 18 */ +% long extents; /* 32 + 4 */ +% short session_error; /* 36 + 2 */ +% char regular; /* 38 + 1 */ <---- should be 'r' ???? +% char hkey_un0; /* 39 + 1 */ +% }; /* total=40 bytes */ +% +% struct image_dimension +% { /* off + size */ +% short dim[8]; /* 0 + 16 */ +% #ifdef BRU2ANZ +% char vox_units[4]; /* 16 + 4 */ +% // up to 3 characters for the voxels units label; i.e. mm., um., cm. +% char cal_units[8]; /* 20 + 8 */ +% // up to 7 characters for the calibration units label; i.e. HU +% #else +% short unused8; /* 16 + 2 */ +% short unused9; /* 18 + 2 */ +% short unused10; /* 20 + 2 */ +% short unused11; /* 22 + 2 */ +% short unused12; /* 24 + 2 */ +% short unused13; /* 26 + 2 */ +% #endif +% short unused14; /* 28 + 2 */ +% short datatype; /* 30 + 2 */ +% short bitpix; /* 32 + 2 */ +% short dim_un0; /* 34 + 2 */ +% float pixdim[8]; /* 36 + 32 */ +% /* +% pixdim[] specifies the voxel dimensitons: +% pixdim[1] - voxel width +% pixdim[2] - voxel height +% pixdim[3] - interslice distance +% ...etc +% */ +% float vox_offset; /* 68 + 4 */ +% #ifdef BRU2ANZ +% float roi_scale; /* 72 + 4 */ +% #else +% float funused1; /* 72 + 4 */ +% #endif +% float funused2; /* 76 + 4 */ +% float funused3; /* 80 + 4 */ +% float cal_max; /* 84 + 4 */ +% float cal_min; /* 88 + 4 */ +% float compressed; /* 92 + 4 */ +% float verified; /* 96 + 4 */ +% long glmax,glmin; /* 100 + 8 */ +% }; /* total=108 bytes */ +% +% struct data_history +% { /* off + size */ +% char descrip[80]; /* 0 + 80 */ +% char aux_file[24]; /* 80 + 24 */ +% char orient; /* 104 + 1 */ +% char originator[10]; /* 105 + 10 */ +% char generated[10]; /* 115 + 10 */ +% char scannum[10]; /* 125 + 10 */ +% char patient_id[10]; /* 135 + 10 */ +% char exp_date[10]; /* 145 + 10 */ +% char exp_time[10]; /* 155 + 10 */ +% char hist_un0[3]; /* 165 + 3 */ +% long views; /* 168 + 4 */ +% long vols_added; /* 172 + 4 */ +% long start_field; /* 176 + 4 */ +% long field_skip; /* 180 + 4 */ +% long omax, omin; /* 184 + 8 */ +% long smax, smin; /* 192 + 8 */ +% }; /* total=200 bytes */ +% +% struct dsr +% { +% struct header_key hk; /* 0 + 40 */ +% struct image_dimension dime; /* 40 + 108 */ +% struct data_history hist; /* 148 + 200 */ +% }; /* total= 348 bytes */ +% +% typedef struct +% { +% float real; +% float imag; +% } COMPLEX; +% +% #pragma pack() +% +% /* Acceptable values for datatype */ +% #define DT_NONE 0 +% #define DT_UNKNOWN 0 +% #define DT_BINARY 1 +% #define DT_UNSIGNED_CHAR 2 +% #define DT_SIGNED_SHORT 4 +% #define DT_SIGNED_INT 8 +% #define DT_FLOAT 16 +% #define DT_COMPLEX 32 +% #define DT_DOUBLE 64 +% #define DT_RGB 128 +% #define DT_ALL 255 +% + +if nargin == 0 & nargout == 0, + help hdr_init; + return; +end + +BRU2ANZ = 1; + + +% read "header_key" +HK.sizeof_hdr = int32(348); +HK.data_type = ''; +HK.db_name = ''; +HK.extents = zeros(1,1, 'int32'); +HK.session_error = zeros(1,1, 'int16'); +HK.regular = 'r'; +HK.hkey_un0 = zeros(1,1, 'int8'); + +% read "image_dimension" +DIME.dim = zeros(1,8, 'int16'); +if BRU2ANZ, +DIME.vox_units = ''; +DIME.cal_units = ''; +else +DIME.unused8 = zeros(1,1, 'int16'); +DIME.unused9 = zeros(1,1, 'int16'); +DIME.unused10 = zeros(1,1, 'int16'); +DIME.unused11 = zeros(1,1, 'int16'); +DIME.unused12 = zeros(1,1, 'int16'); +DIME.unused13 = zeros(1,1, 'int16'); +end +DIME.unused14 = zeros(1,1, 'int16'); +DIME.datatype = zeros(1,1, 'int16'); +DIME.bitpix = zeros(1,1, 'int16'); +DIME.dim_un0 = zeros(1,1, 'int16'); +DIME.pixdim = zeros(1,8, 'single')'; +DIME.vox_offset = zeros(1,1, 'single'); +if BRU2ANZ, +% 2005.09.12 set as 1 to be safe, 0.00392157=1/255 +%DIME.roi_scale = zeros(1,1, 'single'); +%DIME.roi_scale = single(0.00392157); % why 0.00392157 ??? <--- 1/255 +DIME.roi_scale = single(1); +else +DIME.funused1 = zeros(1,1, 'single'); +end +DIME.funused2 = zeros(1,1, 'single'); +DIME.funused3 = zeros(1,1, 'single'); +DIME.cal_max = zeros(1,1, 'single'); +DIME.cal_min = zeros(1,1, 'single'); +DIME.compressed = zeros(1,1, 'single'); +DIME.verified = zeros(1,1, 'single'); +DIME.glmax = zeros(1,1, 'int32'); +DIME.glmin = zeros(1,1, 'int32'); + +% read "data_history" +HIST.descrip = ''; +HIST.aux_file = ''; +HIST.orient = zeros(1,1, 'int8'); +HIST.originator = ''; +HIST.generated = ''; +HIST.scannum = ''; +HIST.patient_id = ''; +HIST.exp_date = ''; +HIST.exp_time = ''; +HIST.hist_un0 = ''; +HIST.views = zeros(1,1, 'int32'); +HIST.vols_added = zeros(1,1, 'int32'); +HIST.start_field = zeros(1,1, 'int32'); +HIST.field_skip = zeros(1,1, 'int32'); +HIST.omax = zeros(1,1, 'int32'); +HIST.omin = zeros(1,1, 'int32'); +HIST.smax = zeros(1,1, 'int32'); +HIST.smin = zeros(1,1, 'int32'); + + +% set values if given. +for N = 1:2:nargin, + vname = varargin{N}; + vvalue = varargin{N+1}; + if strcmpi(vname,'datatype') & ischar(vvalue), + switch lower(vvalue), + case {'binary'} + vvalue = 1; + case {'uchar', 'uint8'} + vvalue = 2; + case {'short', 'int16', '_16bit_sgn_int'} + vvalue = 4; + case {'int', 'int32', 'long', '_32bit_sgn_int'} + vvalue = 8; + case {'float', 'single'} + vvalue = 16; + case {'complex'} + vvalue = 32; + case {'double'} + vvalue = 64; + case {'rgb'} + vvalue = 128; + otherwise + error('\n ERROR %s: datatype ''%s'' not supported.\n',mfilename,vvalue); + end + end + if isfield(HK,vname), HK.(vname) = vvalue; end + if isfield(DIME,vname), DIME.(vname) = vvalue; end + if isfield(HIST,vname), HIST.(vname) = vvalue; end +end + + +% update DIME.bitpix according to DIME.datatype +switch DIME.datatype + case 1 + DIME.bitpix = 1; + case 2 + DIME.bitpix = 8; + case 4 + DIME.bitpix = 16; + case 8 + DIME.bitpix = 32; + case 16 + DIME.bitpix = 32; + case 32 + DIME.bitpix = 64; + case 64 + DIME.bitpix = 64; + case 128 + DIME.bitpix = 24; +end + + + +% return the structure +HDR.hk = HK; % header_key +HDR.dime = DIME; % image_dimension +HDR.hist = HIST; % data_history + + +return; diff --git a/mpi_code/mex_anz/hdr_read.m b/mpi_code/mex_anz/hdr_read.m new file mode 100644 index 0000000..a4869e3 --- /dev/null +++ b/mpi_code/mex_anz/hdr_read.m @@ -0,0 +1,193 @@ +function HDR = hdr_read(filename) +%HDR_READ - reads ANALYZE header +% HDR = HDR_READ(FILENAME) reads a header file of ANALYZE(TM). +% +% For detail, see http://www.mayo.edu/bir/PDF/ANALYZE75.pdf +% +% REQUIREMENT : +% utlswapbytes.dll +% +% VERSION : +% 0.90 31.05.05 YM pre-release. +% 0.91 01.06.05 YM modified for BRU2ANZ. +% 0.92 06.08.07 YM bug fix, when big-endian. +% 0.93 29.04.08 YM filename can be as .img +% +% See also ANZ_READ, MAKE_HDR, UTLSWAPBYTES, DBH.H + +if nargin == 0, help hdr_read; return; end + +HDR = []; +if isempty(filename), return; end + + +[fp fn fe] = fileparts(filename); +if ~strcmpi(fe,'.hdr'), + filename = fullfile(fp,sprintf('%s.hdr',fn)); +end + + +if ~exist(filename,'file'), + error('%s: ''%s'' not found.',mfilename,filename); +end + +% check filesize +tmp = dir(filename); +if tmp.bytes < 4, + fclose(fid); + fprintf('\n %s ERROR: invalid file size[%d].',... + mfilename,tmp.bytes); + return; +end + + +BRU2ANZ = 1; + +% open the file +fid = fopen(filename,'r'); + +% read "header_key" +HK.sizeof_hdr = fread(fid, 1, 'int32=>int32'); +hsize = HK.sizeof_hdr; +if hsize > hex2dec('01000000'), hsize = utlswapbytes(hsize); end +if tmp.bytes < hsize, + fclose(fid); + fprintf('\n %s ERROR: file size[%d] is smaller than %dbytes.',... + mfilename,tmp.bytes,hsize); + return; +end +HK.data_type = subConvStr(fread(fid,10, 'char')); +HK.db_name = subConvStr(fread(fid,18, 'char')); +HK.extents = fread(fid, 1, 'int32=>int32'); +HK.session_error = fread(fid, 1, 'int16=>int16'); +HK.regular = subConvStr(fread(fid, 1, 'char')); +HK.hkey_un0 = fread(fid, 1, 'char'); + +% read "image_dimension" +DIME.dim = fread(fid, 8, 'int16=>int16')'; +if BRU2ANZ, +DIME.vox_units = subConvStr(fread(fid, 4, 'char')); +DIME.cal_units = subConvStr(fread(fid, 8, 'char')); +else +DIME.unused8 = fread(fid, 1, 'int16=>int16'); +DIME.unused9 = fread(fid, 1, 'int16=>int16'); +DIME.unused10 = fread(fid, 1, 'int16=>int16'); +DIME.unused11 = fread(fid, 1, 'int16=>int16'); +DIME.unused12 = fread(fid, 1, 'int16=>int16'); +DIME.unused13 = fread(fid, 1, 'int16=>int16'); +end +DIME.unused14 = fread(fid, 1, 'int16=>int16'); +DIME.datatype = fread(fid, 1, 'int16=>int16'); +DIME.bitpix = fread(fid, 1, 'int16=>int16'); +DIME.dim_un0 = fread(fid, 1, 'int16=>int16'); +DIME.pixdim = fread(fid, 8, 'single=>single')'; +DIME.vox_offset = fread(fid, 1, 'single=>single'); +if BRU2ANZ, +DIME.roi_scale = fread(fid, 1, 'single=>single'); +else +DIME.funused1 = fread(fid, 1, 'single=>single'); +end +DIME.funused2 = fread(fid, 1, 'single=>single'); +DIME.funused3 = fread(fid, 1, 'single=>single'); +DIME.cal_max = fread(fid, 1, 'single=>single'); +DIME.cal_min = fread(fid, 1, 'single=>single'); +DIME.compressed = fread(fid, 1, 'single=>single'); +DIME.verified = fread(fid, 1, 'single=>single'); +DIME.glmax = fread(fid, 1, 'int32=>int32'); +DIME.glmin = fread(fid, 1, 'int32=>int32'); + +% read "data_history" +HIST.descrip = subConvStr(fread(fid,80, 'char')); +HIST.aux_file = subConvStr(fread(fid,24, 'char')); +HIST.orient = fread(fid, 1, 'char'); +HIST.originator = subConvStr(fread(fid,10, 'char')); +HIST.generated = subConvStr(fread(fid,10, 'char')); +HIST.scannum = subConvStr(fread(fid,10, 'char')); +HIST.patient_id = subConvStr(fread(fid,10, 'char')); +HIST.exp_date = subConvStr(fread(fid,10, 'char')); +HIST.exp_time = subConvStr(fread(fid,10, 'char')); +HIST.hist_un0 = subConvStr(fread(fid, 3, 'char')); +HIST.views = fread(fid, 1, 'int32=>int32'); +HIST.vols_added = fread(fid, 1, 'int32=>int32'); +HIST.start_field = fread(fid, 1, 'int32=>int32'); +HIST.field_skip = fread(fid, 1, 'int32=>int32'); +HIST.omax = fread(fid, 1, 'int32=>int32'); +HIST.omin = fread(fid, 1, 'int32=>int32'); +HIST.smax = fread(fid, 1, 'int32=>int32'); +HIST.smin = fread(fid, 1, 'int32=>int32'); + + +% for debug, ftell(fid) should return 348 +%ftell(fid) + +% close the file +fclose(fid); + +% return the structure +HDR.hk = HK; % header_key +HDR.dime = DIME; % image_dimension +HDR.hist = HIST; % data_history + +% swap header's bytes, if needed. +if HDR.dime.dim(1) < 0 | HDR.dime.dim(1) > 15, + HDR = subSwapHdr(HDR,BRU2ANZ); +end + + +return; + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function str = subConvStr(dat) +dat = dat(:)'; +if any(dat) + str = deblank(char(dat)); +else + str = ''; +end + +return; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function HDR = subSwapHdr(HDR,BRU2ANZ) +HDR.hk.sizeof_hdr = utlswapbytes(HDR.hk.sizeof_hdr); +HDR.hk.extents = utlswapbytes(HDR.hk.extents); +HDR.hk.session_error = utlswapbytes(HDR.hk.session_error); +HDR.dime.dim(1) = utlswapbytes(HDR.dime.dim(1)); +HDR.dime.dim(2) = utlswapbytes(HDR.dime.dim(2)); +HDR.dime.dim(3) = utlswapbytes(HDR.dime.dim(3)); +HDR.dime.dim(4) = utlswapbytes(HDR.dime.dim(4)); +HDR.dime.dim(5) = utlswapbytes(HDR.dime.dim(5)); +HDR.dime.dim(6) = utlswapbytes(HDR.dime.dim(6)); +HDR.dime.dim(7) = utlswapbytes(HDR.dime.dim(7)); +HDR.dime.dim(8) = utlswapbytes(HDR.dime.dim(8)); +HDR.dime.unused14 = utlswapbytes(HDR.dime.unused14); +HDR.dime.datatype = utlswapbytes(HDR.dime.datatype); +HDR.dime.bitpix = utlswapbytes(HDR.dime.bitpix); +HDR.dime.pixdim(1) = utlswapbytes(HDR.dime.pixdim(1)); +HDR.dime.pixdim(2) = utlswapbytes(HDR.dime.pixdim(2)); +HDR.dime.pixdim(3) = utlswapbytes(HDR.dime.pixdim(3)); +HDR.dime.pixdim(4) = utlswapbytes(HDR.dime.pixdim(4)); +HDR.dime.pixdim(5) = utlswapbytes(HDR.dime.pixdim(5)); +HDR.dime.pixdim(6) = utlswapbytes(HDR.dime.pixdim(6)); +HDR.dime.pixdim(7) = utlswapbytes(HDR.dime.pixdim(7)); +HDR.dime.pixdim(8) = utlswapbytes(HDR.dime.pixdim(8)); +HDR.dime.vox_offset = utlswapbytes(HDR.dime.vox_offset); +if BRU2ANZ, + HDR.dime.roi_scale = utlswapbytes(HDR.dime.roi_scale); +else + HDR.dime.funused1 = utlswapbytes(HDR.dime.funused1); +end +HDR.dime.funused2 = utlswapbytes(HDR.dime.funused2); +HDR.dime.cal_max = utlswapbytes(HDR.dime.cal_max); +HDR.dime.cal_min = utlswapbytes(HDR.dime.cal_min); +HDR.dime.compressed = utlswapbytes(HDR.dime.compressed); +HDR.dime.verified = utlswapbytes(HDR.dime.verified); +HDR.dime.dim_un0 = utlswapbytes(HDR.dime.dim_un0); +HDR.dime.glmax = utlswapbytes(HDR.dime.glmax); +HDR.dime.glmin = utlswapbytes(HDR.dime.glmin); + +return; + diff --git a/mpi_code/mex_anz/hdr_write.m b/mpi_code/mex_anz/hdr_write.m new file mode 100644 index 0000000..74e3e47 --- /dev/null +++ b/mpi_code/mex_anz/hdr_write.m @@ -0,0 +1,169 @@ +function hdr_write(filename, HDR) +%HDR_WRITE - create a ANALYZE header file. +% HDR_WRITE(FILENAME,HDR) writes a header file of ANALYZE(TM). +% Input HDR can be given by HDR_INIT. +% +% For detail, see http://www.mayo.edu/bir/PDF/ANALYZE75.pdf +% +% VERSION : +% 0.90 01.06.05 YM pre-release. +% 0.91 01.06.05 YM mofified for BRU2ANZ. +% +% See also HDR_READ, HDR_INIT + +if nargin ~= 2, help hdr_write; return; end + +if ~ischar(filename) | isempty(filename), + fprintf('\n %s ERROR: first arg must be a filename string.',mfilename); + return; +end +if ~isstruct(HDR) | ~isfield(HDR,'hk') | ~isfield(HDR,'dime') | ~isfield(HDR,'hist'), + fprintf('\n %s ERROR: second arg must be a strucure by hdr_init().',mfilename); + return; +end + +BRU2ANZ = 1; + +% update HDR.dime.datatype if it is a string +if ischar(HDR.dime.datatype), + switch lower(HDR.dime.datatype) + case {'binary'} + HDR.dime.datatype = 1; + case {'uchar','uint8'} + HDR.dime.datatype = 2; + case {'short', 'int16'} + HDR.dime.datatype = 4; + case {'int', 'int32', 'long'} + HDR.dime.datatype = 8; + case {'float', 'single'} + HDR.dime.datatype = 16; + case {'complex'} + HDR.dime.datatype = 32; + case {'double'} + HDR.dime.datatype = 64; + case {'rgb'} + HDR.dime.datatype = 128; + end +end + +% update HDR.dime.bitpix according to HDR.dime.datatype +switch HDR.dime.datatype + case 1 + HDR.dime.bitpix = 1; + case 2 + HDR.dime.bitpix = 8; + case 4 + HDR.dime.bitpix = 16; + case 8 + HDR.dime.bitpix = 32; + case 16 + HDR.dime.bitpix = 32; + case 32 + HDR.dime.bitpix = 64; + case 64 + HDR.dime.bitpix = 64; + case 128 + HDR.dime.bitpix = 24; +end + +% open the file +fid = fopen(filename,'wb'); + +% write "header_key" +HK = HDR.hk; +fwrite(fid, HK.sizeof_hdr(1), 'int32'); +fwrite(fid, subGetChar(HK.data_type,10), 'int8'); +fwrite(fid, subGetChar(HK.db_name,18), 'int8'); +fwrite(fid, HK.extents(1), 'int32'); +fwrite(fid, HK.session_error(1), 'int16'); +fwrite(fid, subGetChar(HK.regular,1), 'int8'); +fwrite(fid, HK.hkey_un0(1), 'int8'); + +% write "image_dimension" +DIME = HDR.dime; +fwrite(fid, subGetValue(DIME.dim,8), 'int16'); +if BRU2ANZ, +fwrite(fid, subGetChar(DIME.vox_units,4), 'int8'); +fwrite(fid, subGetChar(DIME.cal_units,8), 'int8'); +else +fwrite(fid, DIME.unused8(1), 'int16'); +fwrite(fid, DIME.unused9(1), 'int16'); +fwrite(fid, DIME.unused10(1), 'int16'); +fwrite(fid, DIME.unused11(1), 'int16'); +fwrite(fid, DIME.unused12(1), 'int16'); +fwrite(fid, DIME.unused13(1), 'int16'); +end +fwrite(fid, DIME.unused14(1), 'int16'); +fwrite(fid, DIME.datatype(1), 'int16'); +fwrite(fid, DIME.bitpix(1), 'int16'); +fwrite(fid, DIME.dim_un0(1), 'int16'); +fwrite(fid, subGetValue(DIME.pixdim,8), 'single'); +fwrite(fid, DIME.vox_offset(1), 'single'); +if BRU2ANZ, +fwrite(fid, DIME.roi_scale(1), 'single'); +else +fwrite(fid, DIME.funused1(1), 'single'); +end +fwrite(fid, DIME.funused2(1), 'single'); +fwrite(fid, DIME.funused3(1), 'single'); +fwrite(fid, DIME.cal_max(1), 'single'); +fwrite(fid, DIME.cal_min(1), 'single'); +fwrite(fid, DIME.compressed(1), 'single'); +fwrite(fid, DIME.verified(1), 'single'); +fwrite(fid, DIME.glmax(1), 'int32'); +fwrite(fid, DIME.glmin(1), 'int32'); + +% write "data_history" +HIST = HDR.hist; +fwrite(fid, subGetChar(HIST.descrip,80), 'int8'); +fwrite(fid, subGetChar(HIST.aux_file,24), 'int8'); +fwrite(fid, HIST.orient(1), 'int8'); +fwrite(fid, subGetChar(HIST.originator,10), 'int8'); +fwrite(fid, subGetChar(HIST.generated,10), 'int8'); +fwrite(fid, subGetChar(HIST.scannum,10), 'int8'); +fwrite(fid, subGetChar(HIST.patient_id,10), 'int8'); +fwrite(fid, subGetChar(HIST.exp_date,10), 'int8'); +fwrite(fid, subGetChar(HIST.exp_time,10), 'int8'); +fwrite(fid, subGetChar(HIST.hist_un0,3), 'int8'); +fwrite(fid, HIST.views(1), 'int32'); +fwrite(fid, HIST.vols_added(1), 'int32'); +fwrite(fid, HIST.start_field(1), 'int32'); +fwrite(fid, HIST.field_skip(1), 'int32'); +fwrite(fid, HIST.omax(1), 'int32'); +fwrite(fid, HIST.omin(1), 'int32'); +fwrite(fid, HIST.smax(1), 'int32'); +fwrite(fid, HIST.smin(1), 'int32'); + +% close the file +fclose(fid); + + +return; + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function v = subGetChar(x,n) +v = x; +if ischar(v), v = int8(v); end +if length(v) > n, + v = v(1:n); +elseif length(v) < n, + v(end+1:n) = 0; +end + +return; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function v = subGetValue(x,n) +v = x; +if length(v) > n, + v = v(1:n); +elseif length(v) < n, + v(end+1:n) = 0; +end + +return; + diff --git a/mpi_code/mex_anz/html_files/Contents.html b/mpi_code/mex_anz/html_files/Contents.html new file mode 100644 index 0000000..c9466d6 --- /dev/null +++ b/mpi_code/mex_anz/html_files/Contents.html @@ -0,0 +1,256 @@ + + + + + Contents + + +  ANA
+
+  Files
+      @SessionTemplate - - description of your poject/session
+      K02jP1                    - - Block Design (Fahad)
+      a003c1                    - - Phys+MRI
+      a003x1                    - - Phys+MRI
+      a019p1                    - - Block Design (Zoe)
+      a01lG1                    - - Scotoma
+      a98nm1                    - - Movie Phys
+      a98nm2                    - - Physiology w/ Brief Stimuli and the HR-Flash Suppression
+      b003d1                    - - Phys+MRI
+      b00401                    - - Phys + MRI, Phys+MRI
+      b004h1                    - - Phys+MRI
+      b004o1                    - - Block Design (Margaret)
+      b00581                    - - Scotoma
+      b005j1                    - - Phys+MRI
+      b005y1                    - - Phys+MRI
+      b006d1                    - - Phys+MRI
+      b006r1                    - - Block Design (Margaret)
+      b007t1                    - - Block Design (Zoe)
+      b00851                    - - Block Design (Zoe)
+      b009s1                    - - Microstimulation
+      b00ae1                    - - Microstimulation
+      b00au1                    - - Microstimulation
+      b00bi1                    - - Neuromod Phys+MRI
+      b00cg1                    - - Neuromod Phys+MRI
+      b00cs1                    - - Phys+MRI
+      b00nm1                    - - Neuromod Phys
+      b019i1                    - - Microstimulation
+      b01a21                    - - Block Design (Margaret)
+      b01ae1                    - - Glass Patterns
+      b01ak1                    - - Block Design (Zoe)
+      b01bs1                    - - Block Design (Margaret)
+      b01di1                    - - Glass Patterns
+      b01du1                    - - Block Design (Margaret)
+      b01lm1                    - - Microstimulation
+      b01mz1                    - - Movie Phys+MRI
+      b01nm3                    - - Flash Suppression Phys
+      b01nm4                    - - Flash Suppression Phys
+      b01nm5                    - - Flash Suppression Phys
+      b02nm1                    - - Attention, Flash Suppression Phys
+      b02nm2                    - - Movie Phys
+      b02nm3                    - - Physiology w/ Brief Stimuli and the HR-Flash Suppression
+      b03pD1                    - - Psychophys w/ Brief Stimuli
+      b03pG1                    - - Psychophys w/ Brief Stimuli
+      b03pN1                    - B03PG1 - Psychophys w/ Brief Stimuli
+      b970q1                    - - Block Design (Gregor)
+      b971q1                    - - Block Design (Margaret)
+      b972y1                    - - Phys+MRI
+      b973k1                    - - Phys+MRI
+      b983m1                    - - Block Design (Margaret)
+      b987c1                    - - Glass Patterns
+      b99wr1                    - - Block Design (Margaret)
+      c019q1                    - - Microstimulation
+      c019t1                    - - Block Design (Margaret)
+      c01aa1                    - - Block Design (Zoe)
+      c01af1                    - - Block Design (Zoe)
+      c01br1                    - - Block Design (Zoe)
+      c01dl1                    - - Block Design (Margaret)
+      c01ek1                    - - Block Design (Margaret)
+      c01ep1                    - - Block Design (Margaret)
+      c01hl1                    - - Glass Patterns
+      c01i21                    - - Block Design (Zoe)
+      c01ie1                    - - Block Design (Faces)
+      c01jn1                    - - Anesthesia Phys+MRI
+      c01jw1                    - - Microstimulation, Flash Suppression Phys+MRI, Anesthesia Phys+MRI
+      c01kx1                    - - Attention, Flash Suppression Phys+MRI, Anesthesia Phys+MRI
+      c01nm1                    - - Movie Phys
+      c01nm2                    - - Movie Phys
+      c01nm3                    - - Physiology w/ Brief Stimuli and the HR-Flash Suppression
+      c01nn1                    - - Movie MRI
+      c01ph1                    - - Short stimuli -> Non-linearity of BOLD onset
+      c970z1                    - - Block Design (Gregor)
+      c97241                    - - Block Design (Margaret)
+      c97311                    - - Block Design (Margaret)
+      c973p1                    - - Block Design (Margaret)
+      c974l1                    - - Phys+MRI
+      c98nm1                    - - Movie Phys, Anesthesia Phys
+      c98nm2                    - - Movie Phys
+      c98nm3                    - - Movie Phys
+      c990q1                    - - Block Design (Margaret)
+      c993a1                    - - Block Design (Margaret)
+      c993t1                    - - Block Design (Margaret)
+      c995s1                    - - Block Design (Gregor)
+      d01hq1                    - - Glass Patterns
+      d01lr1                    - - Microstimulation
+      d01ml1                    - - Movie Phys+MRI
+      d01nm1                    - - Neuromod Phys
+      d01nm2                    - - Neuromod Phys
+      d01nm4                    - - Flash Suppression Phys
+      d01nm5                    - - Flash Suppression Phys
+      d03pf1                    - - Short stimuli
+      d04pk1                    - - Short stimuli
+      d04qd1                    - - Movie MRI
+      d970j1                    - - Block Design (Margaret)
+      d970x1                    - - Block Design (Margaret)
+      d972i1                    - - Block Design (Margaret)
+      d972j1                    - - Block Design (Ocular Dominance)
+      d973f1                    - - Phys+MRI
+      d974b1                    - - Block Design (Gregor)
+      d974f1                    - - Block Design (Margaret)
+      d974m1                    - - Block Design (Gregor)
+      d97571                    - - Scotoma
+      d975n1                    - - Block Design (Margaret)
+      d97621                    - - Microstimulation
+      d976b1                    - - Block Design (High Resolution)
+      d991i1                    - - Phys+MRI
+      d992z1                    - - Phys+MRI
+      e004u1                    - - Block Design (Margaret)
+      e00nm1                    - - Physiology w/ Brief Stimuli and the HR-Flash Suppression
+      e01fe1                    - - Scotoma
+      e01js1                    - - Scotoma
+      e02hQ1                    - - Scotoma
+      e02iK1                    - - Scotoma
+      e02jc1                    - - Scotoma
+      e02jq1                    - - Scotoma
+      e02kF1                    - - Scotoma
+      e02kd1                    - - Scotoma
+      e02mm1                    - - Scotoma
+      e02nm1                    - - Movie Phys
+      e04pl1                    - - Short stimuli
+      e99wq1                    - - Block Design (Margaret)
+      f003w1                    - - Block Design (Margaret)
+      f01kj1                    - - Attention, Flash Suppression Phys+MRI
+      f01kz1                    - - Microstimulation
+      f01m91                    - - Movie Phys+MRI
+      f01pr1                    - - Short stimuli -> Non-linearity of BOLD onset
+      f970s1                    - - Block Design (Margaret)
+      f971k1                    - - Block Design (Gregor)
+      f972w1                    - - Block Design (Ocular Dominance)
+      f973j1                    - - Block Design (Gregor)
+      f975l1                    - - Block Design (High Resolution)
+      f97641                    - - Block Design (High Resolution)
+      g02j21                    - - Phys+MRI, Anesthesia Phys+MRI
+      g02lv1                    - - Movie Phys+MRI
+      g02mn1                    - - Movie Phys+MRI
+      g02nm1                    - - Movie Phys, Anesthesia Phys
+      g02nm2                    - - Physiology w/ Brief Stimuli and the HR-Flash Suppression
+      g02pv1                    - - Short stimuli -> Non-linearity of BOLD onset
+      g04pr1                    - - NEWSOME PROJECT
+      g974c1                    - - Block Design (Gregor)
+      g977d1                    - - Glass Patterns
+      g97nm1                    - - Movie Phys, Anesthesia Phys
+      g981v1                    - - Block Design (Margaret)
+      g98nm1                    - - Flash Suppression Phys, Anesthesia Phys
+      g98nm2                    - - Flash Suppression Phys, Anesthesia Phys
+      h005v1                    - - Phys+MRI
+      h005w1                    - - Microstimulation
+      h006l1                    - - Phys+MRI
+      h007l1                    - - Glass Patterns
+      h00871                    - - Glass Patterns
+      h008d1                    - - Glass Patterns
+      h009d1                    - - Phys+MRI
+      h00ag1                    - - Microstimulation
+      h970w1                    - - Block Design (Margaret)
+      h97361                    - - Phys+MRI
+      h973l1                    - - Phys+MRI
+      h974i1                    - - Block Design (Gregor)
+      i006p1                    - - Block Design (Gregor)
+      i007c1                    - - Block Design (Margaret)
+      i007v1                    - - Block Design (Zoe)
+      i00951                    - - Phys+MRI
+      i009h1                    - - Microstimulation
+      i00an1                    - - Microstimulation
+      i00f41                    - - Block Design (Margaret)
+      j00731                    - - Block Design (Margaret)
+      j007f1                    - - Microstimulation
+      j008e1                    - - Glass Patterns
+      j00aq1                    - - Block Design (Margaret)
+      j00b21                    - - Microstimulation
+      j00bt1                    - - Block Design (Margaret)
+      j00dh1                    - - Phys+MRI
+      j00dj1                    - - Phys+MRI
+      j00el1                    - - Block Design (Zoe)
+      j00f11                    - - Neuromod Phys+MRI
+      j00jx1                    - - Block Design (High Resolution)
+      j00lq1                    - - Movie Phys+MRI, Anesthesia Phys+MRI
+      j00me1                    - - Movie Phys+MRI
+      j00nm1                    - - Physiology w/ Brief Stimuli and the HR-Flash Suppression
+      j02hn1                    - - Glass Patterns
+      j02l61                    - - Glass Patterns
+      j02lw1                    - - Block Design (High Resolution)
+      j02np1                    - - Movie MRI
+      j02ol1                    - - Spontaneous activity for dependence analysis,
+      j02pb1                    - - Short stimuli
+      j02pp1                    - - Short stimuli
+      j02q71                    - - Short stimuli
+      j02qf1                    - - Movie MRI
+      j02qp1                    - - Traveling WAVE
+      j03ls1                    - - Movie MRI
+      j97nm1                    - - Physiology w/ Brief Stimuli and the HR-Flash Suppression
+      k005x1                    - - Phys+MRI
+      k005z1                    - - Microstimulation
+      k006i1                    - - Phys+MRI
+      k00761                    - - Block Design (Margaret)
+      k007w1                    - - Block Design (Zoe)
+      k007z1                    - - Glass Patterns
+      k008f1                    - - Glass Patterns
+      k00911                    - - Glass Patterns
+      k009u1                    - - Phys+MRI
+      k00bk1                    - - Neuromod Phys+MRI
+      k00dd1                    - - Neuromod Phys+MRI
+      l00651                    - - Block Design (Gregor)
+      m00631                    - - Block Design (Margaret)
+      m02gs1                    - - Phys+MRI
+      m02jC1                    - - Anesthesia Phys+MRI
+      m02lx1                    - - Two-electrode, Movie Phys+MRI, Injection(Propofol) [FORMAT]
+      m02pd1                    - - Short stimuli
+      m03lu1                    - - Movie MRI
+      m03pI1                    - - Psychophys - Brief Stimuli
+      m03pO1                    - - Psychophys - Brief Stimuli
+      n00a01                    - - Block Design (Zoe)
+      n00ab1                    - - Glass Patterns
+      n00eb1                    - - Neuromod Phys+MRI
+      n02l71                    - - Glass Patterns
+      n02lp1                    - - Movie Phys+MRI, Anesthesia Phys+MRI
+      n02m21                    - - Movie Phys+MRI
+      n02mv1                    - - Movie MRI
+      n03mt1                    - - Movie MRI
+      n03ow1                    - - Short stimuli -> Non-linearity of BOLD onset
+      n03py1                    - - Short stimuli, On/Off speparation(Wehrhahn)
+      n03qr1                    - - TRAVELING WAVE
+      n03qv1                    - - Traveling wave & Brief Pulses 28.06.04
+      o979x1                    - - Scotoma
+      o979z1                    - - Block Design (Zoe)
+      prz001                    - - Short stimuli -> Non-linearity of BOLD onset
+      q02mA1                    - - Scotoma
+      r97nm1                    - - Movie Phys
+      s02jT1                    - - Flash Suppression Phys+MRI, Anesthesia Phys+MRI
+      s02kr1                    - - Flash Suppression Phys+MRI
+      s02kv1                    - - Flash Suppression Phys+MRI
+      s02l81                    - - Glass Patterns
+      s02nm1                    - - Movie Phys
+      s02nm2                    - - Physiology w/ Brief Stimuli and the HR-Flash Suppression
+      @SessionTemplate - @SESSIONTEMPLATE - description of your poject/session
+
+      Overloaded functions or methods (ones with the same name in other directories)
+            help icinterface/Contents.m
+            help instrument/Contents.m
+            help serial/Contents.m
+            help timer/Contents.m
+            help audioplayer/Contents.m
+            help audiorecorder/Contents.m
+            help strel/Contents.m
+
+ + diff --git a/mpi_code/mex_anz/html_files/hdr_init.html b/mpi_code/mex_anz/html_files/hdr_init.html new file mode 100644 index 0000000..79ceac2 --- /dev/null +++ b/mpi_code/mex_anz/html_files/hdr_init.html @@ -0,0 +1,134 @@ + + + + + hdr_init + + + HDR_INIT - initializes ANALIZE(TM) header structure.
+    HDR = HDR_INIT() returns ANALIZE header structure.
+    HDR = HDR_INIT(NAME1,VALUE1,NAME2,VALUE2,...) returns
+    ANALYZE header initialized by given arguments.
+
+    EXAMPLE :
+        hdr = hdr_init;
+        hdr = hdr_init('dim',[4 256 256 1 148 0 0 0],'datatype',8);
+        hdr = hdr_init('dim',[4 256 256 1 148 0 0 0],'datatype','int32');
+        hdr = hdr_init('dim',[4 256 256 1 148 0 0 0],'datatype','_32BIT_SGN_INT');
+
+    VERSION :
+        0.90 01.06.05 YM  first release.
+        0.91 01.06.05 YM  modified for BRU2ANZ.
+        0.92 13.06.05 YM  accepts '_16BIT_SGN_INT' and '_32BIT_SGN_INT' as 'datatype'.
+        0.93 12.09.05 YM  set dime.roi_scale as 1 for safety.
+
+    See also HDR_READ, HDR_WRITE, DBH.H
+
+  ANALYZE HEADER ===================================
+  #pragma pack(1)
+  struct header_key /* header key */
+  {                                          /* off + size */
+      long sizeof_hdr;        /*    0 +  4 */ <---- must be 384
+      char data_type[10];  /*    4 + 10 */
+      char db_name[18];      /*  14 + 18 */
+      long extents;              /*  32 +  4 */
+      short session_error; /*  36 +  2 */
+      char regular;              /*  38 +  1 */ <---- should be 'r' ????
+      char hkey_un0;            /*  39 +  1 */
+  };                                        /* total=40 bytes */
+
+  struct image_dimension
+  {                                          /* off + size */
+      short dim[8];              /*    0 + 16 */
+  #ifdef BRU2ANZ
+      char  vox_units[4];  /*  16 +  4 */
+      // up to 3 characters for the voxels units label; i.e. mm., um., cm.
+      char  cal_units[8];  /*  20 +  8 */
+      // up to 7 characters for the calibration units label; i.e. HU
+  #else
+      short unused8;            /*  16 +  2 */
+      short unused9;            /*  18 +  2 */
+      short unused10;          /*  20 +  2 */
+      short unused11;          /*  22 +  2 */
+      short unused12;          /*  24 +  2 */
+      short unused13;          /*  26 +  2 */
+  #endif
+      short unused14;          /*  28 +  2 */
+      short datatype;          /*  30 +  2 */
+      short bitpix;              /*  32 +  2 */
+      short dim_un0;            /*  34 +  2 */
+      float pixdim[8];        /*  36 + 32 */
+      /*
+          pixdim[] specifies the voxel dimensitons:
+          pixdim[1] - voxel width
+          pixdim[2] - voxel height
+          pixdim[3] - interslice distance
+          ...etc
+      */
+      float vox_offset;      /*  68 +  4 */
+  #ifdef BRU2ANZ
+      float roi_scale;        /*  72 +  4 */
+  #else
+      float funused1;          /*  72 +  4 */
+  #endif
+      float funused2;          /*  76 +  4 */
+      float funused3;          /*  80 +  4 */
+      float cal_max;            /*  84 +  4 */
+      float cal_min;            /*  88 +  4 */
+      float compressed;      /*  92 +  4 */
+      float verified;          /*  96 +  4 */
+      long  glmax,glmin;    /* 100 +  8 */
+  };                                        /* total=108 bytes */
+
+  struct data_history
+  {                                          /* off + size */
+      char descrip[80];      /*    0 + 80 */
+      char aux_file[24];    /*  80 + 24 */
+      char orient;                /* 104 +  1 */
+      char originator[10]; /* 105 + 10 */
+      char generated[10];  /* 115 + 10 */
+      char scannum[10];      /* 125 + 10 */
+      char patient_id[10]; /* 135 + 10 */
+      char exp_date[10];    /* 145 + 10 */
+      char exp_time[10];    /* 155 + 10 */
+      char hist_un0[3];      /* 165 +  3 */
+      long views;                  /* 168 +  4 */
+      long vols_added;        /* 172 +  4 */
+      long start_field;      /* 176 +  4 */
+      long field_skip;        /* 180 +  4 */
+      long omax, omin;        /* 184 +  8 */
+      long smax, smin;        /* 192 +  8 */
+  };                                        /* total=200 bytes */
+
+  struct dsr
+  {
+      struct header_key hk;              /*    0 +  40 */
+      struct image_dimension dime; /*  40 + 108 */
+      struct data_history hist;      /* 148 + 200 */
+  };                                                        /* total= 348 bytes */
+
+  typedef struct
+  {
+      float real;
+      float imag;
+  } COMPLEX;
+
+  #pragma pack()
+
+  /* Acceptable values for datatype */
+  #define DT_NONE 0
+  #define DT_UNKNOWN 0
+  #define DT_BINARY 1
+  #define DT_UNSIGNED_CHAR 2
+  #define DT_SIGNED_SHORT 4
+  #define DT_SIGNED_INT 8
+  #define DT_FLOAT 16
+  #define DT_COMPLEX 32
+  #define DT_DOUBLE 64
+  #define DT_RGB 128
+  #define DT_ALL 255
+
+
+ + diff --git a/mpi_code/mex_anz/html_files/hdr_read.html b/mpi_code/mex_anz/html_files/hdr_read.html new file mode 100644 index 0000000..d145d84 --- /dev/null +++ b/mpi_code/mex_anz/html_files/hdr_read.html @@ -0,0 +1,24 @@ + + + + + hdr_read + + + HDR_READ - reads ANALYZE header
+    HDR = HDR_READ(FILENAME) reads a header file of ANALYZE(TM).
+
+    For detail, see http://www.mayo.edu/bir/PDF/ANALYZE75.pdf
+
+    REQUIREMENT :
+        swapbytes.dll
+
+    VERSION :
+        0.90 31.05.05 YM  pre-release.
+        0.91 01.06.05 YM  modified for BRU2ANZ.
+
+    See also MAKE_HDR, SWAPBYTES, DBH.H
+
+ + diff --git a/mpi_code/mex_anz/html_files/hdr_write.html b/mpi_code/mex_anz/html_files/hdr_write.html new file mode 100644 index 0000000..f87cc71 --- /dev/null +++ b/mpi_code/mex_anz/html_files/hdr_write.html @@ -0,0 +1,22 @@ + + + + + hdr_write + + + HDR_WRITE - create a ANALYZE header file.
+    HDR_WRITE(FILENAME,HDR) writes a header file of ANALYZE(TM).
+    Input HDR can be given by HDR_INIT.
+
+    For detail, see http://www.mayo.edu/bir/PDF/ANALYZE75.pdf
+
+    VERSION :
+        0.90 01.06.05 YM  pre-release.
+        0.91 01.06.05 YM  mofified for BRU2ANZ.
+
+    See also HDR_READ, HDR_INIT
+
+ + diff --git a/mpi_code/mex_anz/html_files/mexanz.html b/mpi_code/mex_anz/html_files/mexanz.html new file mode 100644 index 0000000..1c09a4a --- /dev/null +++ b/mpi_code/mex_anz/html_files/mexanz.html @@ -0,0 +1,15 @@ + + + + + mexanz + + +
+  mexanz.m : batch file to make all mex DLLs.
+
+  VERSION : 1.00  31-May-2005  YM
+
+ + diff --git a/mpi_code/mex_anz/html_files/swapbytes.html b/mpi_code/mex_anz/html_files/swapbytes.html new file mode 100644 index 0000000..f3a7155 --- /dev/null +++ b/mpi_code/mex_anz/html_files/swapbytes.html @@ -0,0 +1,30 @@ + + + + + swapbytes + + + SWAPBYTES - swaps bytes of given data.
+  SV = SWAPBYTES(V) swaps bytes of V and returns the result.
+  SWAPBYTES(V) does the same thing but it will modify directly the original
+  data V without allocating additional memory for the result.
+  Input data V can be multi-dimesional, but its data class
+  must be 2bytes or 4bytes type, ie. int16/uint16/int32/uint32/single.
+
+  Usage: sv = swapbytes(v,[verbose=0|1])
+  Notes: class of 'v' must be int16,uint16,int32,uint32,single.
+            : if nargout==0, then swaps 'v' directly.
+  
+  To compile,
+      mex swapbytes.c
+
+  VERSION :
+      0.90 2005.05.31 Yusuke MURAYAMA @MPI  first release.
+      0.91 2005.06.01 Yusuke MURAYAMA @MPI  if nargout==0, swap the original.
+
+  See also CLASS, INT16, UINT16, INT32, UINT32, SINGLE
+
+ + diff --git a/mpi_code/mex_anz/make_hdr.c b/mpi_code/mex_anz/make_hdr.c new file mode 100644 index 0000000..6f8d7f7 --- /dev/null +++ b/mpi_code/mex_anz/make_hdr.c @@ -0,0 +1,241 @@ +/* This program creates an ANALYZE(TM) database header */ +/* +* (c) Copyright, 1986-1995 +* Biomedical Imaging Resource +* Mayo Foundation +* +* to compile: +* cc -o make_hdr make_hdr.c +* +* to compile in Matlab: +* mex make_hdr.c -D_USE_IN_MATLAB +* +* 2005.05.31 Yusuke MURAYAMA @MPI supports Matlab. +* 2005.06.01 Yusuke MURAYAMA @MPI supports BRU2ANZ. +* +* for detail, see http://www.mayo.edu/bir/PDF/ANALYZE75.pdf +*/ + + +#include +#include +#include "dbh.h" + +#ifdef _USE_IN_MATLAB +# include "matrix.h" +# include "mex.h" +/* Input Arguments */ +# define FILE_IN prhs[0] +# define WIDTH_IN prhs[1] +# define HEIGHT_IN prhs[2] +# define DEPTH_IN prhs[3] +# define VOLUME_IN prhs[4] +# define DATATYPE_IN prhs[5] +# define GLMAX_IN prhs[6] +# define GLMIN_IN prhs[7] +/* Output Arguments */ +# define STATUS_OUT plhs[0] +#endif + + +// PROTOTYPES ////////////////////////////////////////////////////// +int setup_header(struct dsr *, short, short, short, short, char *, int, int); + + +// FUNCTIONS ////////////////////////////////////////////////////// +// setups the header with given parameters. +int setup_header(struct dsr *phdr, + short width, short height, short depth, short volume, + char *typestr, int glmax, int glmin) +{ + static char DataTypes[9][12] = {"UNKNOWN", "BINARY", + "CHAR", "SHORT", "INT","FLOAT", "COMPLEX", + "DOUBLE", "RGB"}; + static int DataTypeSizes[9] = {0,1,8,16,32,32,64,64,24}; + int i; + + memset(phdr,0, sizeof(struct dsr)); + + for(i = 0;i < 8; i++) phdr->dime.pixdim[i] = 0.0; + phdr->dime.vox_offset = 0.0; +#ifdef BRU2ANZ + phdr->dime.roi_scale = 0.00392157f; // why 0.00392157f; ????? +#else + phdr->dime.funused1 = 0.0; +#endif + phdr->dime.funused2 = 0.0; + phdr->dime.funused3 = 0.0; + phdr->dime.cal_max = 0.0; + phdr->dime.cal_min = 0.0; + phdr->dime.datatype = -1; + for(i = 1; i <= 8; i++) { + if(stricmp(typestr,DataTypes[i]) == 0) { + phdr->dime.datatype = (1<<(i-1)); + phdr->dime.bitpix = DataTypeSizes[i]; + break; + } + } + + phdr->dime.dim[0] = 4; // all Analyze images are taken as 4 dimensional + phdr->hk.regular = 'r'; + phdr->hk.sizeof_hdr = sizeof(struct dsr); + phdr->dime.dim[1] = width; // slice width in pixels + phdr->dime.dim[2] = height; // slice height in pixels + phdr->dime.dim[3] = depth; // volume depth in slices + phdr->dime.dim[4] = volume; // number of volumes per file + phdr->dime.glmax = glmax; // maximum voxel value + phdr->dime.glmin = glmin; // minimum voxel value + // Set the voxel dimension fields: + // A value of 0.0 for these fields implies that the value is unknown. + // Change these values to what is appropriate for your data + // or pass additional command line arguments + phdr->dime.pixdim[1] = 0.0; /* voxel x dimension */ + phdr->dime.pixdim[2] = 0.0; /* voxel y dimension */ + phdr->dime.pixdim[3] = 0.0; /* pixel z dimension, slice thickness */ + // Assume zero offset in .img file, byte at which pixel + // data starts in the image file + phdr->dime.vox_offset = 0.0; + // Planar Orientation; + // Movie flag OFF: 0 = transverse, 1 = coronal, 2 = sagittal + // Movie flag ON: 3 = transverse, 4 = coronal, 5 = sagittal + phdr->hist.orient = 0; + +#ifdef BRU2ANZ + // up to 3 characters for the voxels units label; i.e. mm., um., cm. + strcpy(phdr->dime.vox_units," "); + // up to 7 characters for the calibration units label; i.e. HU + strcpy(phdr->dime.cal_units," "); +#endif + + // Calibration maximum and minimum values; + // values of 0.0 for both fields imply that no + // calibration max and min values are used + phdr->dime.cal_max = 0.0; + phdr->dime.cal_min = 0.0; + + return 0; +} + + + + +// MAIN FUNCTION ///////////////////////////////////////////////////// +#ifdef _USE_IN_MATLAB +void mexFunction( int nlhs, mxArray *plhs[], + int nrhs, const mxArray*prhs[] ) +{ + struct dsr hdr; + FILE *fp; + int status, i; + short x,y,z,t; + int glmax, glmin; + char *filename, *datatype; + + if (nrhs == 0 || nrhs != 8) { + mexPrintf("Usage: status = make_hdr(filename,width,height,depth,volume,datatype,max,min)\n"); + mexPrintf("Notes: datatype: BINARY,CHAR,SHORT,INT,FLOAT,COMPLEX,DOUBLE or RGB\n"); + mexPrintf(" ver 0.91 Jun-2005 YM@MPI\n"); + return; + } + + filename = NULL; datatype = NULL; + + if (mxIsChar(FILE_IN) != 1 || mxGetM(FILE_IN) != 1) { + mexErrMsgTxt("make_hdr: first arg must be a filename string."); + } + i = (mxGetM(FILE_IN) * mxGetN(FILE_IN)) + 1; + filename = mxCalloc(i,sizeof(char)); + status = mxGetString(FILE_IN, filename, i); + if (status != 0) + mexWarnMsgTxt("make_hdr: not enough space, filename is truncated."); + + x = (short) mxGetScalar(WIDTH_IN); + y = (short) mxGetScalar(HEIGHT_IN); + z = (short) mxGetScalar(DEPTH_IN); + t = (short) mxGetScalar(VOLUME_IN); + glmax = (int) mxGetScalar(GLMAX_IN); + glmin = (int) mxGetScalar(GLMIN_IN); + + if (mxIsChar(DATATYPE_IN) != 1 || mxGetM(DATATYPE_IN) != 1) { + mexErrMsgTxt("make_hdr: 6th arg must be a datatype string."); + } + i = (mxGetM(DATATYPE_IN) * mxGetN(DATATYPE_IN)) + 1; + datatype = mxCalloc(i,sizeof(char)); + status = mxGetString(DATATYPE_IN, datatype, i); + if (status != 0) + mexWarnMsgTxt("make_hdr: not enough space, datatype is truncated."); + + + status = setup_header(&hdr,x,y,z,t,datatype,glmax,glmin); + if(hdr.dime.datatype <= 0) { + mexPrintf("make_hdr: '%s' is an unacceptable datatype.\n", datatype); + mexErrMsgTxt("make_hdr: datatype should be BINARY,CHAR,SHORT,INT,FLOAT,COMPLEX,DOUBLE or RGB."); + } + + if((fp = fopen(filename,"wb")) == NULL) { + mexPrintf("make_hdr: filename='%s'\n",filename); + mexErrMsgTxt("make_hdr: unable to create the file."); + } + i = fwrite(&hdr, sizeof(struct dsr),1,fp); + fclose(fp); +#if 0 + if (i != 1) { + mexPrintf("make_hdr: filename='%s'\n",filename); + mexErrMsgTxt("make_hdr: failed to write the header."); + } +#endif + + return; +} + +#else +void usage(void) +{ + printf("usage: make_hdr name.hdr x y z t datatype max min \n\n"); + printf(" name.hdr = the name of the header file\n"); + printf(" x = width, y = height, z = depth, t = number of volumes\n"); + printf(" acceptable datatype values are: BINARY, CHAR, SHORT,\n"); + printf(" INT, FLOAT, COMPLEX, DOUBLE, and RGB\n"); + printf(" max = maximum voxel value, min = minimum voxel value\n"); + + return; +} + +int main(int argc,char **argv) /* file x y z t datatype max min */ +{ + struct dsr hdr; + FILE *fp; + int status; + short x,y,z,t; + int glmax, glmin; + + if(argc != 9) { + usage(); + exit(0); + } + + x = (short)atoi(argv[2]); // slice width in pixels + y = (short)atoi(argv[3]); // slice height in pixels + z = (short)atoi(argv[4]); // volume depth in slices + t = (short)atoi(argv[5]); // number of volumes per file + glmax = atoi(argv[7]); // maximum voxel value + glmin = atoi(argv[8]); // minimum voxel value + + status = setup_header(&hdr,x,y,z,t,argv[6],glmax,glmin); + if(hdr.dime.datatype <= 0) { + printf("<%s> is an unacceptable datatype \n\n", argv[6]); + usage(); + exit(0); + } + + if((fp = fopen(argv[1],"wb")) == 0) { + printf("unable to create: %s\n",argv[1]); + exit(0); + } + fwrite(&hdr,sizeof(struct dsr),1,fp); + fclose(fp); + + return 1; +} + +#endif diff --git a/mpi_code/mex_anz/make_hdr.dll.old b/mpi_code/mex_anz/make_hdr.dll.old new file mode 100644 index 0000000..489b0c2 Binary files /dev/null and b/mpi_code/mex_anz/make_hdr.dll.old differ diff --git a/mpi_code/mex_anz/make_hdr.mexw32 b/mpi_code/mex_anz/make_hdr.mexw32 new file mode 100644 index 0000000..d2b0b82 Binary files /dev/null and b/mpi_code/mex_anz/make_hdr.mexw32 differ diff --git a/mpi_code/mex_anz/make_hdr.mexw64 b/mpi_code/mex_anz/make_hdr.mexw64 new file mode 100644 index 0000000..0f668b3 Binary files /dev/null and b/mpi_code/mex_anz/make_hdr.mexw64 differ diff --git a/mpi_code/mex_anz/mexanz.m b/mpi_code/mex_anz/mexanz.m new file mode 100644 index 0000000..07d7b93 --- /dev/null +++ b/mpi_code/mex_anz/mexanz.m @@ -0,0 +1,14 @@ +% +% mexanz.m : batch file to make all mex DLLs. +% +% VERSION : 1.00 31-May-2005 YM +% : 1.01 10-Jan-2006 YM Matlab7.1 supports swapbytes() + +% make_hdr +clear make_hdr; +mex make_hdr.c -D_USE_IN_MATLAB + +% swap_endian +clear utlswapbytes; +mex utlswapbytes.c + diff --git a/mpi_code/mex_anz/nifti1.h b/mpi_code/mex_anz/nifti1.h new file mode 100644 index 0000000..06d3665 --- /dev/null +++ b/mpi_code/mex_anz/nifti1.h @@ -0,0 +1,1490 @@ +/** \file nifti1.h + \brief Official definition of the nifti1 header. Written by Bob Cox, SSCC, NIMH. + + HISTORY: + + 29 Nov 2007 [rickr] + - added DT_RGBA32 and NIFTI_TYPE_RGBA32 + - added NIFTI_INTENT codes: + TIME_SERIES, NODE_INDEX, RGB_VECTOR, RGBA_VECTOR, SHAPE + */ + +#ifndef _NIFTI_HEADER_ +#define _NIFTI_HEADER_ + +/***************************************************************************** + ** This file defines the "NIFTI-1" header format. ** + ** It is derived from 2 meetings at the NIH (31 Mar 2003 and ** + ** 02 Sep 2003) of the Data Format Working Group (DFWG), ** + ** chartered by the NIfTI (Neuroimaging Informatics Technology ** + ** Initiative) at the National Institutes of Health (NIH). ** + **--------------------------------------------------------------** + ** Neither the National Institutes of Health (NIH), the DFWG, ** + ** nor any of the members or employees of these institutions ** + ** imply any warranty of usefulness of this material for any ** + ** purpose, and do not assume any liability for damages, ** + ** incidental or otherwise, caused by any use of this document. ** + ** If these conditions are not acceptable, do not use this! ** + **--------------------------------------------------------------** + ** Author: Robert W Cox (NIMH, Bethesda) ** + ** Advisors: John Ashburner (FIL, London), ** + ** Stephen Smith (FMRIB, Oxford), ** + ** Mark Jenkinson (FMRIB, Oxford) ** +******************************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Note that the ANALYZE 7.5 file header (dbh.h) is + (c) Copyright 1986-1995 + Biomedical Imaging Resource + Mayo Foundation + Incorporation of components of dbh.h are by permission of the + Mayo Foundation. + + Changes from the ANALYZE 7.5 file header in this file are released to the + public domain, including the functional comments and any amusing asides. +-----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/*! INTRODUCTION TO NIFTI-1: + ------------------------ + The twin (and somewhat conflicting) goals of this modified ANALYZE 7.5 + format are: + (a) To add information to the header that will be useful for functional + neuroimaging data analysis and display. These additions include: + - More basic data types. + - Two affine transformations to specify voxel coordinates. + - "Intent" codes and parameters to describe the meaning of the data. + - Affine scaling of the stored data values to their "true" values. + - Optional storage of the header and image data in one file (.nii). + (b) To maintain compatibility with non-NIFTI-aware ANALYZE 7.5 compatible + software (i.e., such a program should be able to do something useful + with a NIFTI-1 dataset -- at least, with one stored in a traditional + .img/.hdr file pair). + + Most of the unused fields in the ANALYZE 7.5 header have been taken, + and some of the lesser-used fields have been co-opted for other purposes. + Notably, most of the data_history substructure has been co-opted for + other purposes, since the ANALYZE 7.5 format describes this substructure + as "not required". + + NIFTI-1 FLAG (MAGIC STRINGS): + ---------------------------- + To flag such a struct as being conformant to the NIFTI-1 spec, the last 4 + bytes of the header must be either the C String "ni1" or "n+1"; + in hexadecimal, the 4 bytes + 6E 69 31 00 or 6E 2B 31 00 + (in any future version of this format, the '1' will be upgraded to '2', + etc.). Normally, such a "magic number" or flag goes at the start of the + file, but trying to avoid clobbering widely-used ANALYZE 7.5 fields led to + putting this marker last. However, recall that "the last shall be first" + (Matthew 20:16). + + If a NIFTI-aware program reads a header file that is NOT marked with a + NIFTI magic string, then it should treat the header as an ANALYZE 7.5 + structure. + + NIFTI-1 FILE STORAGE: + -------------------- + "ni1" means that the image data is stored in the ".img" file corresponding + to the header file (starting at file offset 0). + + "n+1" means that the image data is stored in the same file as the header + information. We recommend that the combined header+data filename suffix + be ".nii". When the dataset is stored in one file, the first byte of image + data is stored at byte location (int)vox_offset in this combined file. + The minimum allowed value of vox_offset is 352; for compatibility with + some software, vox_offset should be an integral multiple of 16. + + GRACE UNDER FIRE: + ---------------- + Most NIFTI-aware programs will only be able to handle a subset of the full + range of datasets possible with this format. All NIFTI-aware programs + should take care to check if an input dataset conforms to the program's + needs and expectations (e.g., check datatype, intent_code, etc.). If the + input dataset can't be handled by the program, the program should fail + gracefully (e.g., print a useful warning; not crash). + + SAMPLE CODES: + ------------ + The associated files nifti1_io.h and nifti1_io.c provide a sample + implementation in C of a set of functions to read, write, and manipulate + NIFTI-1 files. The file nifti1_test.c is a sample program that uses + the nifti1_io.c functions. +-----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* HEADER STRUCT DECLARATION: + ------------------------- + In the comments below for each field, only NIFTI-1 specific requirements + or changes from the ANALYZE 7.5 format are described. For convenience, + the 348 byte header is described as a single struct, rather than as the + ANALYZE 7.5 group of 3 substructs. + + Further comments about the interpretation of various elements of this + header are after the data type definition itself. Fields that are + marked as ++UNUSED++ have no particular interpretation in this standard. + (Also see the UNUSED FIELDS comment section, far below.) + + The presumption below is that the various C types have particular sizes: + sizeof(int) = sizeof(float) = 4 ; sizeof(short) = 2 +-----------------------------------------------------------------------------*/ + +/*=================*/ +#ifdef __cplusplus +extern "C" { +#endif +/*=================*/ + +/*! \struct nifti_1_header + \brief Data structure defining the fields in the nifti1 header. + This binary header should be found at the beginning of a valid + NIFTI-1 header file. + */ + /*************************/ /************************/ +struct nifti_1_header { /* NIFTI-1 usage */ /* ANALYZE 7.5 field(s) */ + /*************************/ /************************/ + + /*--- was header_key substruct ---*/ + int sizeof_hdr; /*!< MUST be 348 */ /* int sizeof_hdr; */ + char data_type[10]; /*!< ++UNUSED++ */ /* char data_type[10]; */ + char db_name[18]; /*!< ++UNUSED++ */ /* char db_name[18]; */ + int extents; /*!< ++UNUSED++ */ /* int extents; */ + short session_error; /*!< ++UNUSED++ */ /* short session_error; */ + char regular; /*!< ++UNUSED++ */ /* char regular; */ + char dim_info; /*!< MRI slice ordering. */ /* char hkey_un0; */ + + /*--- was image_dimension substruct ---*/ + short dim[8]; /*!< Data array dimensions.*/ /* short dim[8]; */ + float intent_p1 ; /*!< 1st intent parameter. */ /* short unused8; */ + /* short unused9; */ + float intent_p2 ; /*!< 2nd intent parameter. */ /* short unused10; */ + /* short unused11; */ + float intent_p3 ; /*!< 3rd intent parameter. */ /* short unused12; */ + /* short unused13; */ + short intent_code ; /*!< NIFTI_INTENT_* code. */ /* short unused14; */ + short datatype; /*!< Defines data type! */ /* short datatype; */ + short bitpix; /*!< Number bits/voxel. */ /* short bitpix; */ + short slice_start; /*!< First slice index. */ /* short dim_un0; */ + float pixdim[8]; /*!< Grid spacings. */ /* float pixdim[8]; */ + float vox_offset; /*!< Offset into .nii file */ /* float vox_offset; */ + float scl_slope ; /*!< Data scaling: slope. */ /* float funused1; */ + float scl_inter ; /*!< Data scaling: offset. */ /* float funused2; */ + short slice_end; /*!< Last slice index. */ /* float funused3; */ + char slice_code ; /*!< Slice timing order. */ + char xyzt_units ; /*!< Units of pixdim[1..4] */ + float cal_max; /*!< Max display intensity */ /* float cal_max; */ + float cal_min; /*!< Min display intensity */ /* float cal_min; */ + float slice_duration;/*!< Time for 1 slice. */ /* float compressed; */ + float toffset; /*!< Time axis shift. */ /* float verified; */ + int glmax; /*!< ++UNUSED++ */ /* int glmax; */ + int glmin; /*!< ++UNUSED++ */ /* int glmin; */ + + /*--- was data_history substruct ---*/ + char descrip[80]; /*!< any text you like. */ /* char descrip[80]; */ + char aux_file[24]; /*!< auxiliary filename. */ /* char aux_file[24]; */ + + short qform_code ; /*!< NIFTI_XFORM_* code. */ /*-- all ANALYZE 7.5 ---*/ + short sform_code ; /*!< NIFTI_XFORM_* code. */ /* fields below here */ + /* are replaced */ + float quatern_b ; /*!< Quaternion b param. */ + float quatern_c ; /*!< Quaternion c param. */ + float quatern_d ; /*!< Quaternion d param. */ + float qoffset_x ; /*!< Quaternion x shift. */ + float qoffset_y ; /*!< Quaternion y shift. */ + float qoffset_z ; /*!< Quaternion z shift. */ + + float srow_x[4] ; /*!< 1st row affine transform. */ + float srow_y[4] ; /*!< 2nd row affine transform. */ + float srow_z[4] ; /*!< 3rd row affine transform. */ + + char intent_name[16];/*!< 'name' or meaning of data. */ + + char magic[4] ; /*!< MUST be "ni1\0" or "n+1\0". */ + +} ; /**** 348 bytes total ****/ + +typedef struct nifti_1_header nifti_1_header ; + +/*---------------------------------------------------------------------------*/ +/* HEADER EXTENSIONS: + ----------------- + After the end of the 348 byte header (e.g., after the magic field), + the next 4 bytes are a char array field named "extension". By default, + all 4 bytes of this array should be set to zero. In a .nii file, these + 4 bytes will always be present, since the earliest start point for + the image data is byte #352. In a separate .hdr file, these bytes may + or may not be present. If not present (i.e., if the length of the .hdr + file is 348 bytes), then a NIfTI-1 compliant program should use the + default value of extension={0,0,0,0}. The first byte (extension[0]) + is the only value of this array that is specified at present. The other + 3 bytes are reserved for future use. + + If extension[0] is nonzero, it indicates that extended header information + is present in the bytes following the extension array. In a .nii file, + this extended header data is before the image data (and vox_offset + must be set correctly to allow for this). In a .hdr file, this extended + data follows extension and proceeds (potentially) to the end of the file. + + The format of extended header data is weakly specified. Each extension + must be an integer multiple of 16 bytes long. The first 8 bytes of each + extension comprise 2 integers: + int esize , ecode ; + These values may need to be byte-swapped, as indicated by dim[0] for + the rest of the header. + * esize is the number of bytes that form the extended header data + + esize must be a positive integral multiple of 16 + + this length includes the 8 bytes of esize and ecode themselves + * ecode is a non-negative integer that indicates the format of the + extended header data that follows + + different ecode values are assigned to different developer groups + + at present, the "registered" values for code are + = 0 = unknown private format (not recommended!) + = 2 = DICOM format (i.e., attribute tags and values) + = 4 = AFNI group (i.e., ASCII XML-ish elements) + In the interests of interoperability (a primary rationale for NIfTI), + groups developing software that uses this extension mechanism are + encouraged to document and publicize the format of their extensions. + To this end, the NIfTI DFWG will assign even numbered codes upon request + to groups submitting at least rudimentary documentation for the format + of their extension; at present, the contact is mailto:rwcox@nih.gov. + The assigned codes and documentation will be posted on the NIfTI + website. All odd values of ecode (and 0) will remain unassigned; + at least, until the even ones are used up, when we get to 2,147,483,646. + + Note that the other contents of the extended header data section are + totally unspecified by the NIfTI-1 standard. In particular, if binary + data is stored in such a section, its byte order is not necessarily + the same as that given by examining dim[0]; it is incumbent on the + programs dealing with such data to determine the byte order of binary + extended header data. + + Multiple extended header sections are allowed, each starting with an + esize,ecode value pair. The first esize value, as described above, + is at bytes #352-355 in the .hdr or .nii file (files start at byte #0). + If this value is positive, then the second (esize2) will be found + starting at byte #352+esize1 , the third (esize3) at byte #352+esize1+esize2, + et cetera. Of course, in a .nii file, the value of vox_offset must + be compatible with these extensions. If a malformed file indicates + that an extended header data section would run past vox_offset, then + the entire extended header section should be ignored. In a .hdr file, + if an extended header data section would run past the end-of-file, + that extended header data should also be ignored. + + With the above scheme, a program can successively examine the esize + and ecode values, and skip over each extended header section if the + program doesn't know how to interpret the data within. Of course, any + program can simply ignore all extended header sections simply by jumping + straight to the image data using vox_offset. +-----------------------------------------------------------------------------*/ + +/*! \struct nifti1_extender + \brief This structure represents a 4-byte string that should follow the + binary nifti_1_header data in a NIFTI-1 header file. If the char + values are {1,0,0,0}, the file is expected to contain extensions, + values of {0,0,0,0} imply the file does not contain extensions. + Other sequences of values are not currently defined. + */ +struct nifti1_extender { char extension[4] ; } ; +typedef struct nifti1_extender nifti1_extender ; + +/*! \struct nifti1_extension + \brief Data structure defining the fields of a header extension. + */ +struct nifti1_extension { + int esize ; /*!< size of extension, in bytes (must be multiple of 16) */ + int ecode ; /*!< extension code, one of the NIFTI_ECODE_ values */ + char * edata ; /*!< raw data, with no byte swapping (length is esize-8) */ +} ; +typedef struct nifti1_extension nifti1_extension ; + +/*---------------------------------------------------------------------------*/ +/* DATA DIMENSIONALITY (as in ANALYZE 7.5): + --------------------------------------- + dim[0] = number of dimensions; + - if dim[0] is outside range 1..7, then the header information + needs to be byte swapped appropriately + - ANALYZE supports dim[0] up to 7, but NIFTI-1 reserves + dimensions 1,2,3 for space (x,y,z), 4 for time (t), and + 5,6,7 for anything else needed. + + dim[i] = length of dimension #i, for i=1..dim[0] (must be positive) + - also see the discussion of intent_code, far below + + pixdim[i] = voxel width along dimension #i, i=1..dim[0] (positive) + - cf. ORIENTATION section below for use of pixdim[0] + - the units of pixdim can be specified with the xyzt_units + field (also described far below). + + Number of bits per voxel value is in bitpix, which MUST correspond with + the datatype field. The total number of bytes in the image data is + dim[1] * ... * dim[dim[0]] * bitpix / 8 + + In NIFTI-1 files, dimensions 1,2,3 are for space, dimension 4 is for time, + and dimension 5 is for storing multiple values at each spatiotemporal + voxel. Some examples: + - A typical whole-brain FMRI experiment's time series: + - dim[0] = 4 + - dim[1] = 64 pixdim[1] = 3.75 xyzt_units = NIFTI_UNITS_MM + - dim[2] = 64 pixdim[2] = 3.75 | NIFTI_UNITS_SEC + - dim[3] = 20 pixdim[3] = 5.0 + - dim[4] = 120 pixdim[4] = 2.0 + - A typical T1-weighted anatomical volume: + - dim[0] = 3 + - dim[1] = 256 pixdim[1] = 1.0 xyzt_units = NIFTI_UNITS_MM + - dim[2] = 256 pixdim[2] = 1.0 + - dim[3] = 128 pixdim[3] = 1.1 + - A single slice EPI time series: + - dim[0] = 4 + - dim[1] = 64 pixdim[1] = 3.75 xyzt_units = NIFTI_UNITS_MM + - dim[2] = 64 pixdim[2] = 3.75 | NIFTI_UNITS_SEC + - dim[3] = 1 pixdim[3] = 5.0 + - dim[4] = 1200 pixdim[4] = 0.2 + - A 3-vector stored at each point in a 3D volume: + - dim[0] = 5 + - dim[1] = 256 pixdim[1] = 1.0 xyzt_units = NIFTI_UNITS_MM + - dim[2] = 256 pixdim[2] = 1.0 + - dim[3] = 128 pixdim[3] = 1.1 + - dim[4] = 1 pixdim[4] = 0.0 + - dim[5] = 3 intent_code = NIFTI_INTENT_VECTOR + - A single time series with a 3x3 matrix at each point: + - dim[0] = 5 + - dim[1] = 1 xyzt_units = NIFTI_UNITS_SEC + - dim[2] = 1 + - dim[3] = 1 + - dim[4] = 1200 pixdim[4] = 0.2 + - dim[5] = 9 intent_code = NIFTI_INTENT_GENMATRIX + - intent_p1 = intent_p2 = 3.0 (indicates matrix dimensions) +-----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* DATA STORAGE: + ------------ + If the magic field is "n+1", then the voxel data is stored in the + same file as the header. In this case, the voxel data starts at offset + (int)vox_offset into the header file. Thus, vox_offset=352.0 means that + the data starts immediately after the NIFTI-1 header. If vox_offset is + greater than 352, the NIFTI-1 format does not say much about the + contents of the dataset file between the end of the header and the + start of the data. + + FILES: + ----- + If the magic field is "ni1", then the voxel data is stored in the + associated ".img" file, starting at offset 0 (i.e., vox_offset is not + used in this case, and should be set to 0.0). + + When storing NIFTI-1 datasets in pairs of files, it is customary to name + the files in the pattern "name.hdr" and "name.img", as in ANALYZE 7.5. + When storing in a single file ("n+1"), the file name should be in + the form "name.nii" (the ".nft" and ".nif" suffixes are already taken; + cf. http://www.icdatamaster.com/n.html ). + + BYTE ORDERING: + ------------- + The byte order of the data arrays is presumed to be the same as the byte + order of the header (which is determined by examining dim[0]). + + Floating point types are presumed to be stored in IEEE-754 format. +-----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* DETAILS ABOUT vox_offset: + ------------------------ + In a .nii file, the vox_offset field value is interpreted as the start + location of the image data bytes in that file. In a .hdr/.img file pair, + the vox_offset field value is the start location of the image data + bytes in the .img file. + * If vox_offset is less than 352 in a .nii file, it is equivalent + to 352 (i.e., image data never starts before byte #352 in a .nii file). + * The default value for vox_offset in a .nii file is 352. + * In a .hdr file, the default value for vox_offset is 0. + * vox_offset should be an integer multiple of 16; otherwise, some + programs may not work properly (e.g., SPM). This is to allow + memory-mapped input to be properly byte-aligned. + Note that since vox_offset is an IEEE-754 32 bit float (for compatibility + with the ANALYZE-7.5 format), it effectively has a 24 bit mantissa. All + integers from 0 to 2^24 can be represented exactly in this format, but not + all larger integers are exactly storable as IEEE-754 32 bit floats. However, + unless you plan to have vox_offset be potentially larger than 16 MB, this + should not be an issue. (Actually, any integral multiple of 16 up to 2^27 + can be represented exactly in this format, which allows for up to 128 MB + of random information before the image data. If that isn't enough, then + perhaps this format isn't right for you.) + + In a .img file (i.e., image data stored separately from the NIfTI-1 + header), data bytes between #0 and #vox_offset-1 (inclusive) are completely + undefined and unregulated by the NIfTI-1 standard. One potential use of + having vox_offset > 0 in the .hdr/.img file pair storage method is to make + the .img file be a copy of (or link to) a pre-existing image file in some + other format, such as DICOM; then vox_offset would be set to the offset of + the image data in this file. (It may not be possible to follow the + "multiple-of-16 rule" with an arbitrary external file; using the NIfTI-1 + format in such a case may lead to a file that is incompatible with software + that relies on vox_offset being a multiple of 16.) + + In a .nii file, data bytes between #348 and #vox_offset-1 (inclusive) may + be used to store user-defined extra information; similarly, in a .hdr file, + any data bytes after byte #347 are available for user-defined extra + information. The (very weak) regulation of this extra header data is + described elsewhere. +-----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* DATA SCALING: + ------------ + If the scl_slope field is nonzero, then each voxel value in the dataset + should be scaled as + y = scl_slope * x + scl_inter + where x = voxel value stored + y = "true" voxel value + Normally, we would expect this scaling to be used to store "true" floating + values in a smaller integer datatype, but that is not required. That is, + it is legal to use scaling even if the datatype is a float type (crazy, + perhaps, but legal). + - However, the scaling is to be ignored if datatype is DT_RGB24. + - If datatype is a complex type, then the scaling is to be + applied to both the real and imaginary parts. + + The cal_min and cal_max fields (if nonzero) are used for mapping (possibly + scaled) dataset values to display colors: + - Minimum display intensity (black) corresponds to dataset value cal_min. + - Maximum display intensity (white) corresponds to dataset value cal_max. + - Dataset values below cal_min should display as black also, and values + above cal_max as white. + - Colors "black" and "white", of course, may refer to any scalar display + scheme (e.g., a color lookup table specified via aux_file). + - cal_min and cal_max only make sense when applied to scalar-valued + datasets (i.e., dim[0] < 5 or dim[5] = 1). +-----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* TYPE OF DATA (acceptable values for datatype field): + --------------------------------------------------- + Values of datatype smaller than 256 are ANALYZE 7.5 compatible. + Larger values are NIFTI-1 additions. These are all multiples of 256, so + that no bits below position 8 are set in datatype. But there is no need + to use only powers-of-2, as the original ANALYZE 7.5 datatype codes do. + + The additional codes are intended to include a complete list of basic + scalar types, including signed and unsigned integers from 8 to 64 bits, + floats from 32 to 128 bits, and complex (float pairs) from 64 to 256 bits. + + Note that most programs will support only a few of these datatypes! + A NIFTI-1 program should fail gracefully (e.g., print a warning message) + when it encounters a dataset with a type it doesn't like. +-----------------------------------------------------------------------------*/ + +#undef DT_UNKNOWN /* defined in dirent.h on some Unix systems */ + +/*! \defgroup NIFTI1_DATATYPES + \brief nifti1 datatype codes + @{ + */ + /*--- the original ANALYZE 7.5 type codes ---*/ +#define DT_NONE 0 +#define DT_UNKNOWN 0 /* what it says, dude */ +#define DT_BINARY 1 /* binary (1 bit/voxel) */ +#define DT_UNSIGNED_CHAR 2 /* unsigned char (8 bits/voxel) */ +#define DT_SIGNED_SHORT 4 /* signed short (16 bits/voxel) */ +#define DT_SIGNED_INT 8 /* signed int (32 bits/voxel) */ +#define DT_FLOAT 16 /* float (32 bits/voxel) */ +#define DT_COMPLEX 32 /* complex (64 bits/voxel) */ +#define DT_DOUBLE 64 /* double (64 bits/voxel) */ +#define DT_RGB 128 /* RGB triple (24 bits/voxel) */ +#define DT_ALL 255 /* not very useful (?) */ + + /*----- another set of names for the same ---*/ +#define DT_UINT8 2 +#define DT_INT16 4 +#define DT_INT32 8 +#define DT_FLOAT32 16 +#define DT_COMPLEX64 32 +#define DT_FLOAT64 64 +#define DT_RGB24 128 + + /*------------------- new codes for NIFTI ---*/ +#define DT_INT8 256 /* signed char (8 bits) */ +#define DT_UINT16 512 /* unsigned short (16 bits) */ +#define DT_UINT32 768 /* unsigned int (32 bits) */ +#define DT_INT64 1024 /* long long (64 bits) */ +#define DT_UINT64 1280 /* unsigned long long (64 bits) */ +#define DT_FLOAT128 1536 /* long double (128 bits) */ +#define DT_COMPLEX128 1792 /* double pair (128 bits) */ +#define DT_COMPLEX256 2048 /* long double pair (256 bits) */ +#define DT_RGBA32 2304 /* 4 byte RGBA (32 bits/voxel) */ +/* @} */ + + + /*------- aliases for all the above codes ---*/ + +/*! \defgroup NIFTI1_DATATYPE_ALIASES + \brief aliases for the nifti1 datatype codes + @{ + */ + /*! unsigned char. */ +#define NIFTI_TYPE_UINT8 2 + /*! signed short. */ +#define NIFTI_TYPE_INT16 4 + /*! signed int. */ +#define NIFTI_TYPE_INT32 8 + /*! 32 bit float. */ +#define NIFTI_TYPE_FLOAT32 16 + /*! 64 bit complex = 2 32 bit floats. */ +#define NIFTI_TYPE_COMPLEX64 32 + /*! 64 bit float = double. */ +#define NIFTI_TYPE_FLOAT64 64 + /*! 3 8 bit bytes. */ +#define NIFTI_TYPE_RGB24 128 + /*! signed char. */ +#define NIFTI_TYPE_INT8 256 + /*! unsigned short. */ +#define NIFTI_TYPE_UINT16 512 + /*! unsigned int. */ +#define NIFTI_TYPE_UINT32 768 + /*! signed long long. */ +#define NIFTI_TYPE_INT64 1024 + /*! unsigned long long. */ +#define NIFTI_TYPE_UINT64 1280 + /*! 128 bit float = long double. */ +#define NIFTI_TYPE_FLOAT128 1536 + /*! 128 bit complex = 2 64 bit floats. */ +#define NIFTI_TYPE_COMPLEX128 1792 + /*! 256 bit complex = 2 128 bit floats */ +#define NIFTI_TYPE_COMPLEX256 2048 + /*! 4 8 bit bytes. */ +#define NIFTI_TYPE_RGBA32 2304 +/* @} */ + + /*-------- sample typedefs for complicated types ---*/ +#if 0 +typedef struct { float r,i; } complex_float ; +typedef struct { double r,i; } complex_double ; +typedef struct { long double r,i; } complex_longdouble ; +typedef struct { unsigned char r,g,b; } rgb_byte ; +#endif + +/*---------------------------------------------------------------------------*/ +/* INTERPRETATION OF VOXEL DATA: + ---------------------------- + The intent_code field can be used to indicate that the voxel data has + some particular meaning. In particular, a large number of codes is + given to indicate that the the voxel data should be interpreted as + being drawn from a given probability distribution. + + VECTOR-VALUED DATASETS: + ---------------------- + The 5th dimension of the dataset, if present (i.e., dim[0]=5 and + dim[5] > 1), contains multiple values (e.g., a vector) to be stored + at each spatiotemporal location. For example, the header values + - dim[0] = 5 + - dim[1] = 64 + - dim[2] = 64 + - dim[3] = 20 + - dim[4] = 1 (indicates no time axis) + - dim[5] = 3 + - datatype = DT_FLOAT + - intent_code = NIFTI_INTENT_VECTOR + mean that this dataset should be interpreted as a 3D volume (64x64x20), + with a 3-vector of floats defined at each point in the 3D grid. + + A program reading a dataset with a 5th dimension may want to reformat + the image data to store each voxels' set of values together in a struct + or array. This programming detail, however, is beyond the scope of the + NIFTI-1 file specification! Uses of dimensions 6 and 7 are also not + specified here. + + STATISTICAL PARAMETRIC DATASETS (i.e., SPMs): + -------------------------------------------- + Values of intent_code from NIFTI_FIRST_STATCODE to NIFTI_LAST_STATCODE + (inclusive) indicate that the numbers in the dataset should be interpreted + as being drawn from a given distribution. Most such distributions have + auxiliary parameters (e.g., NIFTI_INTENT_TTEST has 1 DOF parameter). + + If the dataset DOES NOT have a 5th dimension, then the auxiliary parameters + are the same for each voxel, and are given in header fields intent_p1, + intent_p2, and intent_p3. + + If the dataset DOES have a 5th dimension, then the auxiliary parameters + are different for each voxel. For example, the header values + - dim[0] = 5 + - dim[1] = 128 + - dim[2] = 128 + - dim[3] = 1 (indicates a single slice) + - dim[4] = 1 (indicates no time axis) + - dim[5] = 2 + - datatype = DT_FLOAT + - intent_code = NIFTI_INTENT_TTEST + mean that this is a 2D dataset (128x128) of t-statistics, with the + t-statistic being in the first "plane" of data and the degrees-of-freedom + parameter being in the second "plane" of data. + + If the dataset 5th dimension is used to store the voxel-wise statistical + parameters, then dim[5] must be 1 plus the number of parameters required + by that distribution (e.g., intent_code=NIFTI_INTENT_TTEST implies dim[5] + must be 2, as in the example just above). + + Note: intent_code values 2..10 are compatible with AFNI 1.5x (which is + why there is no code with value=1, which is obsolescent in AFNI). + + OTHER INTENTIONS: + ---------------- + The purpose of the intent_* fields is to help interpret the values + stored in the dataset. Some non-statistical values for intent_code + and conventions are provided for storing other complex data types. + + The intent_name field provides space for a 15 character (plus 0 byte) + 'name' string for the type of data stored. Examples: + - intent_code = NIFTI_INTENT_ESTIMATE; intent_name = "T1"; + could be used to signify that the voxel values are estimates of the + NMR parameter T1. + - intent_code = NIFTI_INTENT_TTEST; intent_name = "House"; + could be used to signify that the voxel values are t-statistics + for the significance of 'activation' response to a House stimulus. + - intent_code = NIFTI_INTENT_DISPVECT; intent_name = "ToMNI152"; + could be used to signify that the voxel values are a displacement + vector that transforms each voxel (x,y,z) location to the + corresponding location in the MNI152 standard brain. + - intent_code = NIFTI_INTENT_SYMMATRIX; intent_name = "DTI"; + could be used to signify that the voxel values comprise a diffusion + tensor image. + + If no data name is implied or needed, intent_name[0] should be set to 0. +-----------------------------------------------------------------------------*/ + + /*! default: no intention is indicated in the header. */ + +#define NIFTI_INTENT_NONE 0 + + /*-------- These codes are for probability distributions ---------------*/ + /* Most distributions have a number of parameters, + below denoted by p1, p2, and p3, and stored in + - intent_p1, intent_p2, intent_p3 if dataset doesn't have 5th dimension + - image data array if dataset does have 5th dimension + + Functions to compute with many of the distributions below can be found + in the CDF library from U Texas. + + Formulas for and discussions of these distributions can be found in the + following books: + + [U] Univariate Discrete Distributions, + NL Johnson, S Kotz, AW Kemp. + + [C1] Continuous Univariate Distributions, vol. 1, + NL Johnson, S Kotz, N Balakrishnan. + + [C2] Continuous Univariate Distributions, vol. 2, + NL Johnson, S Kotz, N Balakrishnan. */ + /*----------------------------------------------------------------------*/ + + /*! [C2, chap 32] Correlation coefficient R (1 param): + p1 = degrees of freedom + R/sqrt(1-R*R) is t-distributed with p1 DOF. */ + +/*! \defgroup NIFTI1_INTENT_CODES + \brief nifti1 intent codes, to describe intended meaning of dataset contents + @{ + */ +#define NIFTI_INTENT_CORREL 2 + + /*! [C2, chap 28] Student t statistic (1 param): p1 = DOF. */ + +#define NIFTI_INTENT_TTEST 3 + + /*! [C2, chap 27] Fisher F statistic (2 params): + p1 = numerator DOF, p2 = denominator DOF. */ + +#define NIFTI_INTENT_FTEST 4 + + /*! [C1, chap 13] Standard normal (0 params): Density = N(0,1). */ + +#define NIFTI_INTENT_ZSCORE 5 + + /*! [C1, chap 18] Chi-squared (1 param): p1 = DOF. + Density(x) proportional to exp(-x/2) * x^(p1/2-1). */ + +#define NIFTI_INTENT_CHISQ 6 + + /*! [C2, chap 25] Beta distribution (2 params): p1=a, p2=b. + Density(x) proportional to x^(a-1) * (1-x)^(b-1). */ + +#define NIFTI_INTENT_BETA 7 + + /*! [U, chap 3] Binomial distribution (2 params): + p1 = number of trials, p2 = probability per trial. + Prob(x) = (p1 choose x) * p2^x * (1-p2)^(p1-x), for x=0,1,...,p1. */ + +#define NIFTI_INTENT_BINOM 8 + + /*! [C1, chap 17] Gamma distribution (2 params): + p1 = shape, p2 = scale. + Density(x) proportional to x^(p1-1) * exp(-p2*x). */ + +#define NIFTI_INTENT_GAMMA 9 + + /*! [U, chap 4] Poisson distribution (1 param): p1 = mean. + Prob(x) = exp(-p1) * p1^x / x! , for x=0,1,2,.... */ + +#define NIFTI_INTENT_POISSON 10 + + /*! [C1, chap 13] Normal distribution (2 params): + p1 = mean, p2 = standard deviation. */ + +#define NIFTI_INTENT_NORMAL 11 + + /*! [C2, chap 30] Noncentral F statistic (3 params): + p1 = numerator DOF, p2 = denominator DOF, + p3 = numerator noncentrality parameter. */ + +#define NIFTI_INTENT_FTEST_NONC 12 + + /*! [C2, chap 29] Noncentral chi-squared statistic (2 params): + p1 = DOF, p2 = noncentrality parameter. */ + +#define NIFTI_INTENT_CHISQ_NONC 13 + + /*! [C2, chap 23] Logistic distribution (2 params): + p1 = location, p2 = scale. + Density(x) proportional to sech^2((x-p1)/(2*p2)). */ + +#define NIFTI_INTENT_LOGISTIC 14 + + /*! [C2, chap 24] Laplace distribution (2 params): + p1 = location, p2 = scale. + Density(x) proportional to exp(-abs(x-p1)/p2). */ + +#define NIFTI_INTENT_LAPLACE 15 + + /*! [C2, chap 26] Uniform distribution: p1 = lower end, p2 = upper end. */ + +#define NIFTI_INTENT_UNIFORM 16 + + /*! [C2, chap 31] Noncentral t statistic (2 params): + p1 = DOF, p2 = noncentrality parameter. */ + +#define NIFTI_INTENT_TTEST_NONC 17 + + /*! [C1, chap 21] Weibull distribution (3 params): + p1 = location, p2 = scale, p3 = power. + Density(x) proportional to + ((x-p1)/p2)^(p3-1) * exp(-((x-p1)/p2)^p3) for x > p1. */ + +#define NIFTI_INTENT_WEIBULL 18 + + /*! [C1, chap 18] Chi distribution (1 param): p1 = DOF. + Density(x) proportional to x^(p1-1) * exp(-x^2/2) for x > 0. + p1 = 1 = 'half normal' distribution + p1 = 2 = Rayleigh distribution + p1 = 3 = Maxwell-Boltzmann distribution. */ + +#define NIFTI_INTENT_CHI 19 + + /*! [C1, chap 15] Inverse Gaussian (2 params): + p1 = mu, p2 = lambda + Density(x) proportional to + exp(-p2*(x-p1)^2/(2*p1^2*x)) / x^3 for x > 0. */ + +#define NIFTI_INTENT_INVGAUSS 20 + + /*! [C2, chap 22] Extreme value type I (2 params): + p1 = location, p2 = scale + cdf(x) = exp(-exp(-(x-p1)/p2)). */ + +#define NIFTI_INTENT_EXTVAL 21 + + /*! Data is a 'p-value' (no params). */ + +#define NIFTI_INTENT_PVAL 22 + + /*! Data is ln(p-value) (no params). + To be safe, a program should compute p = exp(-abs(this_value)). + The nifti_stats.c library returns this_value + as positive, so that this_value = -log(p). */ + + +#define NIFTI_INTENT_LOGPVAL 23 + + /*! Data is log10(p-value) (no params). + To be safe, a program should compute p = pow(10.,-abs(this_value)). + The nifti_stats.c library returns this_value + as positive, so that this_value = -log10(p). */ + +#define NIFTI_INTENT_LOG10PVAL 24 + + /*! Smallest intent_code that indicates a statistic. */ + +#define NIFTI_FIRST_STATCODE 2 + + /*! Largest intent_code that indicates a statistic. */ + +#define NIFTI_LAST_STATCODE 24 + + /*---------- these values for intent_code aren't for statistics ----------*/ + + /*! To signify that the value at each voxel is an estimate + of some parameter, set intent_code = NIFTI_INTENT_ESTIMATE. + The name of the parameter may be stored in intent_name. */ + +#define NIFTI_INTENT_ESTIMATE 1001 + + /*! To signify that the value at each voxel is an index into + some set of labels, set intent_code = NIFTI_INTENT_LABEL. + The filename with the labels may stored in aux_file. */ + +#define NIFTI_INTENT_LABEL 1002 + + /*! To signify that the value at each voxel is an index into the + NeuroNames labels set, set intent_code = NIFTI_INTENT_NEURONAME. */ + +#define NIFTI_INTENT_NEURONAME 1003 + + /*! To store an M x N matrix at each voxel: + - dataset must have a 5th dimension (dim[0]=5 and dim[5]>1) + - intent_code must be NIFTI_INTENT_GENMATRIX + - dim[5] must be M*N + - intent_p1 must be M (in float format) + - intent_p2 must be N (ditto) + - the matrix values A[i][[j] are stored in row-order: + - A[0][0] A[0][1] ... A[0][N-1] + - A[1][0] A[1][1] ... A[1][N-1] + - etc., until + - A[M-1][0] A[M-1][1] ... A[M-1][N-1] */ + +#define NIFTI_INTENT_GENMATRIX 1004 + + /*! To store an NxN symmetric matrix at each voxel: + - dataset must have a 5th dimension + - intent_code must be NIFTI_INTENT_SYMMATRIX + - dim[5] must be N*(N+1)/2 + - intent_p1 must be N (in float format) + - the matrix values A[i][[j] are stored in row-order: + - A[0][0] + - A[1][0] A[1][1] + - A[2][0] A[2][1] A[2][2] + - etc.: row-by-row */ + +#define NIFTI_INTENT_SYMMATRIX 1005 + + /*! To signify that the vector value at each voxel is to be taken + as a displacement field or vector: + - dataset must have a 5th dimension + - intent_code must be NIFTI_INTENT_DISPVECT + - dim[5] must be the dimensionality of the displacment + vector (e.g., 3 for spatial displacement, 2 for in-plane) */ + +#define NIFTI_INTENT_DISPVECT 1006 /* specifically for displacements */ +#define NIFTI_INTENT_VECTOR 1007 /* for any other type of vector */ + + /*! To signify that the vector value at each voxel is really a + spatial coordinate (e.g., the vertices or nodes of a surface mesh): + - dataset must have a 5th dimension + - intent_code must be NIFTI_INTENT_POINTSET + - dim[0] = 5 + - dim[1] = number of points + - dim[2] = dim[3] = dim[4] = 1 + - dim[5] must be the dimensionality of space (e.g., 3 => 3D space). + - intent_name may describe the object these points come from + (e.g., "pial", "gray/white" , "EEG", "MEG"). */ + +#define NIFTI_INTENT_POINTSET 1008 + + /*! To signify that the vector value at each voxel is really a triple + of indexes (e.g., forming a triangle) from a pointset dataset: + - dataset must have a 5th dimension + - intent_code must be NIFTI_INTENT_TRIANGLE + - dim[0] = 5 + - dim[1] = number of triangles + - dim[2] = dim[3] = dim[4] = 1 + - dim[5] = 3 + - datatype should be an integer type (preferably DT_INT32) + - the data values are indexes (0,1,...) into a pointset dataset. */ + +#define NIFTI_INTENT_TRIANGLE 1009 + + /*! To signify that the vector value at each voxel is a quaternion: + - dataset must have a 5th dimension + - intent_code must be NIFTI_INTENT_QUATERNION + - dim[0] = 5 + - dim[5] = 4 + - datatype should be a floating point type */ + +#define NIFTI_INTENT_QUATERNION 1010 + + /*! Dimensionless value - no params - although, as in _ESTIMATE + the name of the parameter may be stored in intent_name. */ + +#define NIFTI_INTENT_DIMLESS 1011 + + /*---------- these values apply to GIFTI datasets ----------*/ + + /*! To signify that the value at each location is from a time series. */ + +#define NIFTI_INTENT_TIME_SERIES 2001 + + /*! To signify that the value at each location is a node index, from + a complete surface dataset. */ + +#define NIFTI_INTENT_NODE_INDEX 2002 + + /*! To signify that the vector value at each location is an RGB triplet, + of whatever type. + - dataset must have a 5th dimension + - dim[0] = 5 + - dim[1] = number of nodes + - dim[2] = dim[3] = dim[4] = 1 + - dim[5] = 3 + */ + +#define NIFTI_INTENT_RGB_VECTOR 2003 + + /*! To signify that the vector value at each location is a 4 valued RGBA + vector, of whatever type. + - dataset must have a 5th dimension + - dim[0] = 5 + - dim[1] = number of nodes + - dim[2] = dim[3] = dim[4] = 1 + - dim[5] = 4 + */ + +#define NIFTI_INTENT_RGBA_VECTOR 2004 + + /*! To signify that the value at each location is a shape value, such + as the curvature. */ + +#define NIFTI_INTENT_SHAPE 2005 + +/* @} */ + +/*---------------------------------------------------------------------------*/ +/* 3D IMAGE (VOLUME) ORIENTATION AND LOCATION IN SPACE: + --------------------------------------------------- + There are 3 different methods by which continuous coordinates can + attached to voxels. The discussion below emphasizes 3D volumes, and + the continuous coordinates are referred to as (x,y,z). The voxel + index coordinates (i.e., the array indexes) are referred to as (i,j,k), + with valid ranges: + i = 0 .. dim[1]-1 + j = 0 .. dim[2]-1 (if dim[0] >= 2) + k = 0 .. dim[3]-1 (if dim[0] >= 3) + The (x,y,z) coordinates refer to the CENTER of a voxel. In methods + 2 and 3, the (x,y,z) axes refer to a subject-based coordinate system, + with + +x = Right +y = Anterior +z = Superior. + This is a right-handed coordinate system. However, the exact direction + these axes point with respect to the subject depends on qform_code + (Method 2) and sform_code (Method 3). + + N.B.: The i index varies most rapidly, j index next, k index slowest. + Thus, voxel (i,j,k) is stored starting at location + (i + j*dim[1] + k*dim[1]*dim[2]) * (bitpix/8) + into the dataset array. + + N.B.: The ANALYZE 7.5 coordinate system is + +x = Left +y = Anterior +z = Superior + which is a left-handed coordinate system. This backwardness is + too difficult to tolerate, so this NIFTI-1 standard specifies the + coordinate order which is most common in functional neuroimaging. + + N.B.: The 3 methods below all give the locations of the voxel centers + in the (x,y,z) coordinate system. In many cases, programs will wish + to display image data on some other grid. In such a case, the program + will need to convert its desired (x,y,z) values into (i,j,k) values + in order to extract (or interpolate) the image data. This operation + would be done with the inverse transformation to those described below. + + N.B.: Method 2 uses a factor 'qfac' which is either -1 or 1; qfac is + stored in the otherwise unused pixdim[0]. If pixdim[0]=0.0 (which + should not occur), we take qfac=1. Of course, pixdim[0] is only used + when reading a NIFTI-1 header, not when reading an ANALYZE 7.5 header. + + N.B.: The units of (x,y,z) can be specified using the xyzt_units field. + + METHOD 1 (the "old" way, used only when qform_code = 0): + ------------------------------------------------------- + The coordinate mapping from (i,j,k) to (x,y,z) is the ANALYZE + 7.5 way. This is a simple scaling relationship: + + x = pixdim[1] * i + y = pixdim[2] * j + z = pixdim[3] * k + + No particular spatial orientation is attached to these (x,y,z) + coordinates. (NIFTI-1 does not have the ANALYZE 7.5 orient field, + which is not general and is often not set properly.) This method + is not recommended, and is present mainly for compatibility with + ANALYZE 7.5 files. + + METHOD 2 (used when qform_code > 0, which should be the "normal" case): + --------------------------------------------------------------------- + The (x,y,z) coordinates are given by the pixdim[] scales, a rotation + matrix, and a shift. This method is intended to represent + "scanner-anatomical" coordinates, which are often embedded in the + image header (e.g., DICOM fields (0020,0032), (0020,0037), (0028,0030), + and (0018,0050)), and represent the nominal orientation and location of + the data. This method can also be used to represent "aligned" + coordinates, which would typically result from some post-acquisition + alignment of the volume to a standard orientation (e.g., the same + subject on another day, or a rigid rotation to true anatomical + orientation from the tilted position of the subject in the scanner). + The formula for (x,y,z) in terms of header parameters and (i,j,k) is: + + [ x ] [ R11 R12 R13 ] [ pixdim[1] * i ] [ qoffset_x ] + [ y ] = [ R21 R22 R23 ] [ pixdim[2] * j ] + [ qoffset_y ] + [ z ] [ R31 R32 R33 ] [ qfac * pixdim[3] * k ] [ qoffset_z ] + + The qoffset_* shifts are in the NIFTI-1 header. Note that the center + of the (i,j,k)=(0,0,0) voxel (first value in the dataset array) is + just (x,y,z)=(qoffset_x,qoffset_y,qoffset_z). + + The rotation matrix R is calculated from the quatern_* parameters. + This calculation is described below. + + The scaling factor qfac is either 1 or -1. The rotation matrix R + defined by the quaternion parameters is "proper" (has determinant 1). + This may not fit the needs of the data; for example, if the image + grid is + i increases from Left-to-Right + j increases from Anterior-to-Posterior + k increases from Inferior-to-Superior + Then (i,j,k) is a left-handed triple. In this example, if qfac=1, + the R matrix would have to be + + [ 1 0 0 ] + [ 0 -1 0 ] which is "improper" (determinant = -1). + [ 0 0 1 ] + + If we set qfac=-1, then the R matrix would be + + [ 1 0 0 ] + [ 0 -1 0 ] which is proper. + [ 0 0 -1 ] + + This R matrix is represented by quaternion [a,b,c,d] = [0,1,0,0] + (which encodes a 180 degree rotation about the x-axis). + + METHOD 3 (used when sform_code > 0): + ----------------------------------- + The (x,y,z) coordinates are given by a general affine transformation + of the (i,j,k) indexes: + + x = srow_x[0] * i + srow_x[1] * j + srow_x[2] * k + srow_x[3] + y = srow_y[0] * i + srow_y[1] * j + srow_y[2] * k + srow_y[3] + z = srow_z[0] * i + srow_z[1] * j + srow_z[2] * k + srow_z[3] + + The srow_* vectors are in the NIFTI_1 header. Note that no use is + made of pixdim[] in this method. + + WHY 3 METHODS? + -------------- + Method 1 is provided only for backwards compatibility. The intention + is that Method 2 (qform_code > 0) represents the nominal voxel locations + as reported by the scanner, or as rotated to some fiducial orientation and + location. Method 3, if present (sform_code > 0), is to be used to give + the location of the voxels in some standard space. The sform_code + indicates which standard space is present. Both methods 2 and 3 can be + present, and be useful in different contexts (method 2 for displaying the + data on its original grid; method 3 for displaying it on a standard grid). + + In this scheme, a dataset would originally be set up so that the + Method 2 coordinates represent what the scanner reported. Later, + a registration to some standard space can be computed and inserted + in the header. Image display software can use either transform, + depending on its purposes and needs. + + In Method 2, the origin of coordinates would generally be whatever + the scanner origin is; for example, in MRI, (0,0,0) is the center + of the gradient coil. + + In Method 3, the origin of coordinates would depend on the value + of sform_code; for example, for the Talairach coordinate system, + (0,0,0) corresponds to the Anterior Commissure. + + QUATERNION REPRESENTATION OF ROTATION MATRIX (METHOD 2) + ------------------------------------------------------- + The orientation of the (x,y,z) axes relative to the (i,j,k) axes + in 3D space is specified using a unit quaternion [a,b,c,d], where + a*a+b*b+c*c+d*d=1. The (b,c,d) values are all that is needed, since + we require that a = sqrt(1.0-(b*b+c*c+d*d)) be nonnegative. The (b,c,d) + values are stored in the (quatern_b,quatern_c,quatern_d) fields. + + The quaternion representation is chosen for its compactness in + representing rotations. The (proper) 3x3 rotation matrix that + corresponds to [a,b,c,d] is + + [ a*a+b*b-c*c-d*d 2*b*c-2*a*d 2*b*d+2*a*c ] + R = [ 2*b*c+2*a*d a*a+c*c-b*b-d*d 2*c*d-2*a*b ] + [ 2*b*d-2*a*c 2*c*d+2*a*b a*a+d*d-c*c-b*b ] + + [ R11 R12 R13 ] + = [ R21 R22 R23 ] + [ R31 R32 R33 ] + + If (p,q,r) is a unit 3-vector, then rotation of angle h about that + direction is represented by the quaternion + + [a,b,c,d] = [cos(h/2), p*sin(h/2), q*sin(h/2), r*sin(h/2)]. + + Requiring a >= 0 is equivalent to requiring -Pi <= h <= Pi. (Note that + [-a,-b,-c,-d] represents the same rotation as [a,b,c,d]; there are 2 + quaternions that can be used to represent a given rotation matrix R.) + To rotate a 3-vector (x,y,z) using quaternions, we compute the + quaternion product + + [0,x',y',z'] = [a,b,c,d] * [0,x,y,z] * [a,-b,-c,-d] + + which is equivalent to the matrix-vector multiply + + [ x' ] [ x ] + [ y' ] = R [ y ] (equivalence depends on a*a+b*b+c*c+d*d=1) + [ z' ] [ z ] + + Multiplication of 2 quaternions is defined by the following: + + [a,b,c,d] = a*1 + b*I + c*J + d*K + where + I*I = J*J = K*K = -1 (I,J,K are square roots of -1) + I*J = K J*K = I K*I = J + J*I = -K K*J = -I I*K = -J (not commutative!) + For example + [a,b,0,0] * [0,0,0,1] = [0,0,-b,a] + since this expands to + (a+b*I)*(K) = (a*K+b*I*K) = (a*K-b*J). + + The above formula shows how to go from quaternion (b,c,d) to + rotation matrix and direction cosines. Conversely, given R, + we can compute the fields for the NIFTI-1 header by + + a = 0.5 * sqrt(1+R11+R22+R33) (not stored) + b = 0.25 * (R32-R23) / a => quatern_b + c = 0.25 * (R13-R31) / a => quatern_c + d = 0.25 * (R21-R12) / a => quatern_d + + If a=0 (a 180 degree rotation), alternative formulas are needed. + See the nifti1_io.c function mat44_to_quatern() for an implementation + of the various cases in converting R to [a,b,c,d]. + + Note that R-transpose (= R-inverse) would lead to the quaternion + [a,-b,-c,-d]. + + The choice to specify the qoffset_x (etc.) values in the final + coordinate system is partly to make it easy to convert DICOM images to + this format. The DICOM attribute "Image Position (Patient)" (0020,0032) + stores the (Xd,Yd,Zd) coordinates of the center of the first voxel. + Here, (Xd,Yd,Zd) refer to DICOM coordinates, and Xd=-x, Yd=-y, Zd=z, + where (x,y,z) refers to the NIFTI coordinate system discussed above. + (i.e., DICOM +Xd is Left, +Yd is Posterior, +Zd is Superior, + whereas +x is Right, +y is Anterior , +z is Superior. ) + Thus, if the (0020,0032) DICOM attribute is extracted into (px,py,pz), then + qoffset_x = -px qoffset_y = -py qoffset_z = pz + is a reasonable setting when qform_code=NIFTI_XFORM_SCANNER_ANAT. + + That is, DICOM's coordinate system is 180 degrees rotated about the z-axis + from the neuroscience/NIFTI coordinate system. To transform between DICOM + and NIFTI, you just have to negate the x- and y-coordinates. + + The DICOM attribute (0020,0037) "Image Orientation (Patient)" gives the + orientation of the x- and y-axes of the image data in terms of 2 3-vectors. + The first vector is a unit vector along the x-axis, and the second is + along the y-axis. If the (0020,0037) attribute is extracted into the + value (xa,xb,xc,ya,yb,yc), then the first two columns of the R matrix + would be + [ -xa -ya ] + [ -xb -yb ] + [ xc yc ] + The negations are because DICOM's x- and y-axes are reversed relative + to NIFTI's. The third column of the R matrix gives the direction of + displacement (relative to the subject) along the slice-wise direction. + This orientation is not encoded in the DICOM standard in a simple way; + DICOM is mostly concerned with 2D images. The third column of R will be + either the cross-product of the first 2 columns or its negative. It is + possible to infer the sign of the 3rd column by examining the coordinates + in DICOM attribute (0020,0032) "Image Position (Patient)" for successive + slices. However, this method occasionally fails for reasons that I + (RW Cox) do not understand. +-----------------------------------------------------------------------------*/ + + /* [qs]form_code value: */ /* x,y,z coordinate system refers to: */ + /*-----------------------*/ /*---------------------------------------*/ + +/*! \defgroup NIFTI1_XFORM_CODES + \brief nifti1 xform codes to describe the "standard" coordinate system + @{ + */ + /*! Arbitrary coordinates (Method 1). */ + +#define NIFTI_XFORM_UNKNOWN 0 + + /*! Scanner-based anatomical coordinates */ + +#define NIFTI_XFORM_SCANNER_ANAT 1 + + /*! Coordinates aligned to another file's, + or to anatomical "truth". */ + +#define NIFTI_XFORM_ALIGNED_ANAT 2 + + /*! Coordinates aligned to Talairach- + Tournoux Atlas; (0,0,0)=AC, etc. */ + +#define NIFTI_XFORM_TALAIRACH 3 + + /*! MNI 152 normalized coordinates. */ + +#define NIFTI_XFORM_MNI_152 4 +/* @} */ + +/*---------------------------------------------------------------------------*/ +/* UNITS OF SPATIAL AND TEMPORAL DIMENSIONS: + ---------------------------------------- + The codes below can be used in xyzt_units to indicate the units of pixdim. + As noted earlier, dimensions 1,2,3 are for x,y,z; dimension 4 is for + time (t). + - If dim[4]=1 or dim[0] < 4, there is no time axis. + - A single time series (no space) would be specified with + - dim[0] = 4 (for scalar data) or dim[0] = 5 (for vector data) + - dim[1] = dim[2] = dim[3] = 1 + - dim[4] = number of time points + - pixdim[4] = time step + - xyzt_units indicates units of pixdim[4] + - dim[5] = number of values stored at each time point + + Bits 0..2 of xyzt_units specify the units of pixdim[1..3] + (e.g., spatial units are values 1..7). + Bits 3..5 of xyzt_units specify the units of pixdim[4] + (e.g., temporal units are multiples of 8). + + This compression of 2 distinct concepts into 1 byte is due to the + limited space available in the 348 byte ANALYZE 7.5 header. The + macros XYZT_TO_SPACE and XYZT_TO_TIME can be used to mask off the + undesired bits from the xyzt_units fields, leaving "pure" space + and time codes. Inversely, the macro SPACE_TIME_TO_XYZT can be + used to assemble a space code (0,1,2,...,7) with a time code + (0,8,16,32,...,56) into the combined value for xyzt_units. + + Note that codes are provided to indicate the "time" axis units are + actually frequency in Hertz (_HZ), in part-per-million (_PPM) + or in radians-per-second (_RADS). + + The toffset field can be used to indicate a nonzero start point for + the time axis. That is, time point #m is at t=toffset+m*pixdim[4] + for m=0..dim[4]-1. +-----------------------------------------------------------------------------*/ + +/*! \defgroup NIFTI1_UNITS + \brief nifti1 units codes to describe the unit of measurement for + each dimension of the dataset + @{ + */ + /*! NIFTI code for unspecified units. */ +#define NIFTI_UNITS_UNKNOWN 0 + + /** Space codes are multiples of 1. **/ + /*! NIFTI code for meters. */ +#define NIFTI_UNITS_METER 1 + /*! NIFTI code for millimeters. */ +#define NIFTI_UNITS_MM 2 + /*! NIFTI code for micrometers. */ +#define NIFTI_UNITS_MICRON 3 + + /** Time codes are multiples of 8. **/ + /*! NIFTI code for seconds. */ +#define NIFTI_UNITS_SEC 8 + /*! NIFTI code for milliseconds. */ +#define NIFTI_UNITS_MSEC 16 + /*! NIFTI code for microseconds. */ +#define NIFTI_UNITS_USEC 24 + + /*** These units are for spectral data: ***/ + /*! NIFTI code for Hertz. */ +#define NIFTI_UNITS_HZ 32 + /*! NIFTI code for ppm. */ +#define NIFTI_UNITS_PPM 40 + /*! NIFTI code for radians per second. */ +#define NIFTI_UNITS_RADS 48 +/* @} */ + +#undef XYZT_TO_SPACE +#undef XYZT_TO_TIME +#define XYZT_TO_SPACE(xyzt) ( (xyzt) & 0x07 ) +#define XYZT_TO_TIME(xyzt) ( (xyzt) & 0x38 ) + +#undef SPACE_TIME_TO_XYZT +#define SPACE_TIME_TO_XYZT(ss,tt) ( (((char)(ss)) & 0x07) \ + | (((char)(tt)) & 0x38) ) + +/*---------------------------------------------------------------------------*/ +/* MRI-SPECIFIC SPATIAL AND TEMPORAL INFORMATION: + --------------------------------------------- + A few fields are provided to store some extra information + that is sometimes important when storing the image data + from an FMRI time series experiment. (After processing such + data into statistical images, these fields are not likely + to be useful.) + + { freq_dim } = These fields encode which spatial dimension (1,2, or 3) + { phase_dim } = corresponds to which acquisition dimension for MRI data. + { slice_dim } = + Examples: + Rectangular scan multi-slice EPI: + freq_dim = 1 phase_dim = 2 slice_dim = 3 (or some permutation) + Spiral scan multi-slice EPI: + freq_dim = phase_dim = 0 slice_dim = 3 + since the concepts of frequency- and phase-encoding directions + don't apply to spiral scan + + slice_duration = If this is positive, AND if slice_dim is nonzero, + indicates the amount of time used to acquire 1 slice. + slice_duration*dim[slice_dim] can be less than pixdim[4] + with a clustered acquisition method, for example. + + slice_code = If this is nonzero, AND if slice_dim is nonzero, AND + if slice_duration is positive, indicates the timing + pattern of the slice acquisition. The following codes + are defined: + NIFTI_SLICE_SEQ_INC == sequential increasing + NIFTI_SLICE_SEQ_DEC == sequential decreasing + NIFTI_SLICE_ALT_INC == alternating increasing + NIFTI_SLICE_ALT_DEC == alternating decreasing + NIFTI_SLICE_ALT_INC2 == alternating increasing #2 + NIFTI_SLICE_ALT_DEC2 == alternating decreasing #2 + { slice_start } = Indicates the start and end of the slice acquisition + { slice_end } = pattern, when slice_code is nonzero. These values + are present to allow for the possible addition of + "padded" slices at either end of the volume, which + don't fit into the slice timing pattern. If there + are no padding slices, then slice_start=0 and + slice_end=dim[slice_dim]-1 are the correct values. + For these values to be meaningful, slice_start must + be non-negative and slice_end must be greater than + slice_start. Otherwise, they should be ignored. + + The following table indicates the slice timing pattern, relative to + time=0 for the first slice acquired, for some sample cases. Here, + dim[slice_dim]=7 (there are 7 slices, labeled 0..6), slice_duration=0.1, + and slice_start=1, slice_end=5 (1 padded slice on each end). + + slice + index SEQ_INC SEQ_DEC ALT_INC ALT_DEC ALT_INC2 ALT_DEC2 + 6 : n/a n/a n/a n/a n/a n/a n/a = not applicable + 5 : 0.4 0.0 0.2 0.0 0.4 0.2 (slice time offset + 4 : 0.3 0.1 0.4 0.3 0.1 0.0 doesn't apply to + 3 : 0.2 0.2 0.1 0.1 0.3 0.3 slices outside + 2 : 0.1 0.3 0.3 0.4 0.0 0.1 the range + 1 : 0.0 0.4 0.0 0.2 0.2 0.4 slice_start .. + 0 : n/a n/a n/a n/a n/a n/a slice_end) + + The SEQ slice_codes are sequential ordering (uncommon but not unknown), + either increasing in slice number or decreasing (INC or DEC), as + illustrated above. + + The ALT slice codes are alternating ordering. The 'standard' way for + these to operate (without the '2' on the end) is for the slice timing + to start at the edge of the slice_start .. slice_end group (at slice_start + for INC and at slice_end for DEC). For the 'ALT_*2' slice_codes, the + slice timing instead starts at the first slice in from the edge (at + slice_start+1 for INC2 and at slice_end-1 for DEC2). This latter + acquisition scheme is found on some Siemens scanners. + + The fields freq_dim, phase_dim, slice_dim are all squished into the single + byte field dim_info (2 bits each, since the values for each field are + limited to the range 0..3). This unpleasantness is due to lack of space + in the 348 byte allowance. + + The macros DIM_INFO_TO_FREQ_DIM, DIM_INFO_TO_PHASE_DIM, and + DIM_INFO_TO_SLICE_DIM can be used to extract these values from the + dim_info byte. + + The macro FPS_INTO_DIM_INFO can be used to put these 3 values + into the dim_info byte. +-----------------------------------------------------------------------------*/ + +#undef DIM_INFO_TO_FREQ_DIM +#undef DIM_INFO_TO_PHASE_DIM +#undef DIM_INFO_TO_SLICE_DIM + +#define DIM_INFO_TO_FREQ_DIM(di) ( ((di) ) & 0x03 ) +#define DIM_INFO_TO_PHASE_DIM(di) ( ((di) >> 2) & 0x03 ) +#define DIM_INFO_TO_SLICE_DIM(di) ( ((di) >> 4) & 0x03 ) + +#undef FPS_INTO_DIM_INFO +#define FPS_INTO_DIM_INFO(fd,pd,sd) ( ( ( ((char)(fd)) & 0x03) ) | \ + ( ( ((char)(pd)) & 0x03) << 2 ) | \ + ( ( ((char)(sd)) & 0x03) << 4 ) ) + +/*! \defgroup NIFTI1_SLICE_ORDER + \brief nifti1 slice order codes, describing the acquisition order + of the slices + @{ + */ +#define NIFTI_SLICE_UNKNOWN 0 +#define NIFTI_SLICE_SEQ_INC 1 +#define NIFTI_SLICE_SEQ_DEC 2 +#define NIFTI_SLICE_ALT_INC 3 +#define NIFTI_SLICE_ALT_DEC 4 +#define NIFTI_SLICE_ALT_INC2 5 /* 05 May 2005: RWCox */ +#define NIFTI_SLICE_ALT_DEC2 6 /* 05 May 2005: RWCox */ +/* @} */ + +/*---------------------------------------------------------------------------*/ +/* UNUSED FIELDS: + ------------- + Some of the ANALYZE 7.5 fields marked as ++UNUSED++ may need to be set + to particular values for compatibility with other programs. The issue + of interoperability of ANALYZE 7.5 files is a murky one -- not all + programs require exactly the same set of fields. (Unobscuring this + murkiness is a principal motivation behind NIFTI-1.) + + Some of the fields that may need to be set for other (non-NIFTI aware) + software to be happy are: + + extents dbh.h says this should be 16384 + regular dbh.h says this should be the character 'r' + glmin, } dbh.h says these values should be the min and max voxel + glmax } values for the entire dataset + + It is best to initialize ALL fields in the NIFTI-1 header to 0 + (e.g., with calloc()), then fill in what is needed. +-----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* MISCELLANEOUS C MACROS +-----------------------------------------------------------------------------*/ + +/*.................*/ +/*! Given a nifti_1_header struct, check if it has a good magic number. + Returns NIFTI version number (1..9) if magic is good, 0 if it is not. */ + +#define NIFTI_VERSION(h) \ + ( ( (h).magic[0]=='n' && (h).magic[3]=='\0' && \ + ( (h).magic[1]=='i' || (h).magic[1]=='+' ) && \ + ( (h).magic[2]>='1' && (h).magic[2]<='9' ) ) \ + ? (h).magic[2]-'0' : 0 ) + +/*.................*/ +/*! Check if a nifti_1_header struct says if the data is stored in the + same file or in a separate file. Returns 1 if the data is in the same + file as the header, 0 if it is not. */ + +#define NIFTI_ONEFILE(h) ( (h).magic[1] == '+' ) + +/*.................*/ +/*! Check if a nifti_1_header struct needs to be byte swapped. + Returns 1 if it needs to be swapped, 0 if it does not. */ + +#define NIFTI_NEEDS_SWAP(h) ( (h).dim[0] < 0 || (h).dim[0] > 7 ) + +/*.................*/ +/*! Check if a nifti_1_header struct contains a 5th (vector) dimension. + Returns size of 5th dimension if > 1, returns 0 otherwise. */ + +#define NIFTI_5TH_DIM(h) ( ((h).dim[0]>4 && (h).dim[5]>1) ? (h).dim[5] : 0 ) + +/*****************************************************************************/ + +/*=================*/ +#ifdef __cplusplus +} +#endif +/*=================*/ + +#endif /* _NIFTI_HEADER_ */ diff --git a/mpi_code/mex_anz/nifti1diagrams_v2.pdf b/mpi_code/mex_anz/nifti1diagrams_v2.pdf new file mode 100644 index 0000000..c83cee4 Binary files /dev/null and b/mpi_code/mex_anz/nifti1diagrams_v2.pdf differ diff --git a/mpi_code/mex_anz/test.hdr b/mpi_code/mex_anz/test.hdr new file mode 100644 index 0000000..f67bb12 Binary files /dev/null and b/mpi_code/mex_anz/test.hdr differ diff --git a/mpi_code/mex_anz/test2.hdr b/mpi_code/mex_anz/test2.hdr new file mode 100644 index 0000000..f67bb12 Binary files /dev/null and b/mpi_code/mex_anz/test2.hdr differ diff --git a/mpi_code/mex_anz/utlswapbytes.c b/mpi_code/mex_anz/utlswapbytes.c new file mode 100644 index 0000000..85d4c18 --- /dev/null +++ b/mpi_code/mex_anz/utlswapbytes.c @@ -0,0 +1,139 @@ +/* utlswapbytes.c : utility to swap bytes for Matlab. + * + * + * UTLSWAPBYTES - swaps bytes of given data. + * + * SV = UTLSWAPBYTES(V) swaps bytes of V and returns the result. + * UTLSWAPBYTES(V) does the same thing but it will modify directly the original + * data V without allocating additional memory for the result. + * Input data V can be multi-dimesional, but its data class + * must be 2bytes or 4bytes type, ie. int16/uint16/int32/uint32/single. + * + * Usage: sv = utlswapbytes(v,[verbose=0|1]) + * Notes: class of 'v' must be int16,uint16,int32,uint32,single. + * : if nargout==0, then swaps 'v' directly. + * + * To compile, + * mex utlswapbytes.c + * + * VERSION : + * 0.90 2005.05.31 Yusuke MURAYAMA @MPI first release. + * 0.91 2005.06.01 Yusuke MURAYAMA @MPI if nargout==0, swaps the original. + */ + +#include +#include "matrix.h" +#include "mex.h" + +// input arguments +#define DATA_IN prhs[0] +#define VERBOSE_IN prhs[1] + +// output arguments +#define DATA_OUT plhs[0] + + +// PROTOTYPES ///////////////////////////////////////////////////////// +void swap_short(short *, int, int); +void swap_long(long *, int, int); + + + +// FUNCTIONS ///////////////////////////////////////////////////////// +void swap_short(unsigned char *ptr, int n, int verbose) +{ + unsigned char b0,b1; + int i; + + for (i = 0; i < n; i++) { + // b0-b1 --> b1-b0 + b0 = *ptr; + b1 = *(ptr+1); + *ptr = b1; + *(ptr+1) = b0; + + ptr = ptr + 2; + } + + if (verbose) + mexPrintf("[%d]: %02x %02x --> %02x %02x\n", n,b0,b1,b1,b0); + + return; +} + +void swap_long(unsigned char *ptr, int n, int verbose) +{ + unsigned char b0,b1,b2,b3; + int i; + + for (i = 0; i < n; i++) { + // b0-b1-b2-b3 --> b3-b2-b1-b0 + b0 = *ptr; b1 = *(ptr+1); + b2 = *(ptr+2); b3 = *(ptr+3); + + *ptr = b3; *(ptr+1) = b2; + *(ptr+2) = b1; *(ptr+3) = b0; + + ptr = ptr + 4; + } + + if (verbose) + mexPrintf("[%d]: %02x %02x %02x %02x --> %x %x %x %x\n", n,b0,b1,b2,b3,b3,b2,b1,b0); + + return; +} + + +// MAIN FUNCTION ///////////////////////////////////////////////////// +void mexFunction(int nlhs, mxArray *plhs[], + int nrhs, const mxArray *prhs[]) +{ + char *datastr; + int n, dataclass, verbose; + + if (nrhs == 0) { + mexPrintf("Usage: sv = utlswapbytes(v,[verbose=0|1])\n"); + mexPrintf("Notes: class of 'v' must be int16,uint16,int32,uint32,single.\n"); + mexPrintf(" : if nargout==0, then swaps 'v' directly.\n"); + mexPrintf(" ver 0.91 Jun-2005 YM@MPI\n"); + return; + } + + verbose = 0; + if (nrhs > 1) { + verbose = (int)mxGetScalar(VERBOSE_IN); + } + + dataclass = mxGetClassID(DATA_IN); + n = mxGetNumberOfElements(DATA_IN); + + if (nlhs > 0) { + DATA_OUT = mxDuplicateArray(DATA_IN); + } + + switch (dataclass) { + case mxINT16_CLASS: + case mxUINT16_CLASS: + if (nlhs > 0) { + swap_short((unsigned char *)mxGetData(DATA_OUT), n, verbose); + } else { + swap_short((unsigned char *)mxGetData(DATA_IN), n, verbose); + } + break; + case mxINT32_CLASS: + case mxUINT32_CLASS: + case mxSINGLE_CLASS: + if (nlhs > 0) { + swap_long((unsigned char *)mxGetData(DATA_OUT), n, verbose); + } else { + swap_long((unsigned char *)mxGetData(DATA_IN), n, verbose); + } + break; + default: + mexPrintf("utlswapbytes: '%s' is an unacceptable data class, 'help class' for detail.\n", + mxGetClassName(DATA_IN)); + mexErrMsgTxt("utlswapbytes: dataclass must be int16,uint16,int32,uint32,single."); + } + + return; +} diff --git a/mpi_code/mex_anz/utlswapbytes.dll.old b/mpi_code/mex_anz/utlswapbytes.dll.old new file mode 100644 index 0000000..c08d7fb Binary files /dev/null and b/mpi_code/mex_anz/utlswapbytes.dll.old differ diff --git a/mpi_code/mex_anz/utlswapbytes.m b/mpi_code/mex_anz/utlswapbytes.m new file mode 100644 index 0000000..bcf5df3 --- /dev/null +++ b/mpi_code/mex_anz/utlswapbytes.m @@ -0,0 +1,19 @@ +%UTLSWAPBYTES - swaps bytes of given data. +% SV = UTLSWAPBYTES(V) swaps bytes of V and returns the result. +% UTLSWAPBYTES(V) does the same thing but it will modify directly the original +% data V without allocating additional memory for the result. +% Input data V can be multi-dimesional, but its data class +% must be 2bytes or 4bytes type, ie. int16/uint16/int32/uint32/single. +% +% Usage: sv = utlswapbytes(v,[verbose=0|1]) +% Notes: class of 'v' must be int16,uint16,int32,uint32,single. +% : if nargout==0, then swaps 'v' directly. +% +% To compile, +% mex utlswapbytes.c +% +% VERSION : +% 0.90 2005.05.31 Yusuke MURAYAMA @MPI first release. +% 0.91 2005.06.01 Yusuke MURAYAMA @MPI if nargout==0, swap the original. +% +% See also CLASS, INT16, UINT16, INT32, UINT32, SINGLE diff --git a/mpi_code/mex_anz/utlswapbytes.mexw32 b/mpi_code/mex_anz/utlswapbytes.mexw32 new file mode 100644 index 0000000..6f62652 Binary files /dev/null and b/mpi_code/mex_anz/utlswapbytes.mexw32 differ diff --git a/mpi_code/mex_anz/utlswapbytes.mexw64 b/mpi_code/mex_anz/utlswapbytes.mexw64 new file mode 100644 index 0000000..fcfa496 Binary files /dev/null and b/mpi_code/mex_anz/utlswapbytes.mexw64 differ diff --git a/mpi_code/pvread/pv_imgpar.m b/mpi_code/pvread/pv_imgpar.m new file mode 100644 index 0000000..d17c972 --- /dev/null +++ b/mpi_code/pvread/pv_imgpar.m @@ -0,0 +1,269 @@ +function IMGP = pv_imgpar(varargin) +%PV_IMGPAR - Get ParaVision imaging parameters. +% IMGP = PV_IMGPAR(IMGFILE,...) +% IMGP = PV_IMGPAR(SESSION,EXPNO,...) gets ParaVision's imaging parameters. +% +% Supported options are +% 'acqp' : set acqp parameters, see pvread_acqp +% 'imnd' : set imnd parameters, see pvread_imnd +% 'method' : set method parameters, see pvread_method +% 'reco' : set reco parameters, see pvread_reco +% +% VERSION : +% 0.90 29.08.08 YM pre-release +% 0.91 18.09.08 YM supports both new csession and old getses. +% 0.92 23.09.08 YM bug fix on IMND_num_segments/_numsegmetns, RECO_transposition. +% +% See also getpvpars pvread_2dseq pvread_acqp pvread_method pvread_reco + +if nargin < 1, eval(sprintf('help %s;',mfilename)); return; end + + +if ischar(varargin{1}) & ~isempty(strfind(varargin{1},'2dseq')), + % Called like pv_imgpar(2DSEQFILE) + imgfile = varargin{1}; + ivar = 2; +else + % Called like pv_imgpar(SESSION,ExpNo) + if nargin < 2, + error(' ERROR %s: missing 2nd arg. as ExpNo.\n',mfilename); + return; + end + if exist('csession','class'), + ses = csession(varargin{1}); + imgfile = ses.filename(varargin{2},'2dseq'); + else + ses = goto(varargin{1}); + imgfile = catfilename(ses,varargin{2},'2dseq'); + end + ivar = 3; +end + + +% check the file. +if ~exist(imgfile,'file'), + error(' ERROR %s: ''%s'' not found.',mfilename,imgfile); +end + +% SET OPTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +reco = []; +acqp = []; +imnd = []; +method = []; +for N = ivar:2:length(varargin), + switch lower(varargin{N}), + case {'reco'} + reco = varargin{N+1}; + case {'acqp'} + acqp = varargin{N+1}; + case {'imnd'} + imnd = varargin{N+1}; + case {'method'} + method = varargin{N+1}; + end +end + +if isempty(reco), reco = pvread_reco(imgfile); end +if isempty(acqp), acqp = pvread_acqp(imgfile); end +if isempty(method), method = pvread_method(imgfile,'verbose',0); end + + +%if isfield(acqp,'ACQ_method') && ~isempty(acqp.ACQ_method), +if isfield(method,'Method') && ~isempty(method.Method), + f_PVM = 1; +else + f_PVM = 0; + if isempty(imnd), + imnd = pvread_imnd(fullfile(fileparts(acqp.filename),'imnd')); + end +end + + +nx = reco.RECO_size(1); +if length(reco.RECO_size) < 2, + ny = 1; +else + ny = reco.RECO_size(2); +end +ns = acqp.NSLICES; +nt = acqp.NR; +if strncmpi(acqp.PULPROG,' 2, + ns = reco.RECO_size(3); + end + nt = acqp.NI; +end + +dx = reco.RECO_fov(1)*10/nx; % [mm] +dy = reco.RECO_fov(2)*10/ny; % [mm] + +if length(reco.RECO_fov) >= 3, + ds = reco.RECO_fov(3)*10/ns; +else + ds = mean(acqp.ACQ_slice_sepn); + if ~any(ds), + ds = acqp.ACQ_slice_thick; + end +end + + +if strncmp(acqp.PULPROG, ' 0 + nechoes = acqp.NECHOES/acqp.ACQ_rare_factor; % don't count echoes used for RARE phase encode + else + nechoes = acqp.NECHOES; + end +end +nechoes = max([1 nechoes]); + + +if f_PVM == 1 + if isfield(method,'PVM_EpiNShots'), + nseg = method.PVM_EpiNShots; + else + nseg = 1; + end + slitr = acqp.ACQ_repetition_time/1000/acqp.NSLICES; % [s] + segtr = acqp.ACQ_repetition_time/1000; + imgtr = acqp.ACQ_repetition_time/1000*nseg; + if isfield(method,'PVM_EchoTime'), + effte = method.PVM_EchoTime/1000; % [s] + elseif isfield(method,'EchoTime'), + effte = method.EchoTime/1000; % [s] + else + effte = 0; + end + recovtr = acqp.ACQ_recov_time(:)'/1000; % [s] for T1 series +else + if isfield(imnd,'IMND_numsegments') && any(imnd.IMND_numsegments), + nseg = imnd.IMND_numsegments; + elseif isfield(imnd,'IMND_num_segments') && any(imnd.IMND_num_segments), + nseg = imnd.IMND_num_segments; + else + nseg = 0; + end + + % glitch for EPI + if isfield(imnd,'EPI_segmentation_mode') && strcmpi(imnd.EPI_segmentation_mode,'No_Segments'), + nseg = 1; + end + + if strncmp(acqp.PULPROG, ' (y,x,z) + tmpvec = [2 1 3]; + elseif transpos == 2, + % (x,y,z) --> (x,z,y) + tmpvec = [1 3 2]; + elseif transpos == 3, + % (x,y,z) --> (z,y,x) + tmpvec = [3 2 1]; + end + IMGP.imgsize(1:3) = IMGP.imgsize(tmpvec); + IMGP.dimsize(1:3) = IMGP.dimsize(tmpvec); + IMGP.dimname(1:3) = IMGP.dimname(tmpvec); + %IMGP.res = IMGP.dimsize([1 2]); +end + + +if nt == 1, + IMGP.imgsize = IMGP.imgsize(1:3); + IMGP.dimsize = IMGP.dimsize(1:3); + IMGP.dimunit = IMGP.dimunit(1:3); + IMGP.dimname = IMGP.dimname(1:3); +end + + +return diff --git a/mpi_code/pvread/pvread_2dseq.m b/mpi_code/pvread/pvread_2dseq.m new file mode 100644 index 0000000..24c54f7 --- /dev/null +++ b/mpi_code/pvread/pvread_2dseq.m @@ -0,0 +1,248 @@ +function varargout = pvread_2dseq(varargin) +%PVREAD_2DSEQ - Read ParaVision 2dseq data. +% [IDATA,IMGP] = PVREAD_2DSEQ(FILENAME,...) +% IDATA = PVREAD_2DSEQ(FILENAME,...) +% IDATA = PVREAD_2DSEQ(SESSION,EXPNO,...) read ParaVision 2dseq data. +% +% Supported options are... +% 'ImgCrop' : cropping as [x,y,width,height], can be empty. x,y>=1. +% 'ImgSize' : image size as [nx, ny, nslices, ntime], must not be empty. +% 'TimeCrop' : cropping as [t,nt], can be empty. t>=1. +% 'ByteOrder' : 'littleEndian' or 'bigEndian' +% 'WordType' : '_16BIT_SGN_INT' or '_32BIT_SGN_INT' +% 'reco' : reco sturcture returned by pvread_reco(). +% 'acqp' : acqp structure returned by pvread_acqp(). +% 'imgp' : image parameters returned by pv_imgpar(). +% +% Returned IDATA is NOT 'double', but 'WordType'. +% +% VERSION : +% 0.90 07.03.07 YM pre-release +% 0.91 16.04.07 YM supports pvread_2dseq(Ses,ExpNo) +% 0.92 29.08.08 YM supports both new csession and old getses. +% 0.93 18.09.08 YM returns imgp instread of acqp/reco +% 0.94 23.09.08 YM bug fix on RECO_transposition. +% +% See also pv_imgpar pvread_acqp pvread_reco pvread_imnd pvread_method pvread_visu_pars + +if nargin < 1, eval(sprintf('help %s;',mfilename)); return; end + + +if ischar(varargin{1}) & ~isempty(strfind(varargin{1},'2dseq')), + % Called like pvread_2dseq(2DSEQFILE) + imgfile = varargin{1}; + ivar = 2; +else + % Called like pvread_2dseq(SESSION,ExpNo) + if nargin < 2, + error(' ERROR %s: missing 2nd arg. as ExpNo.\n',mfilename); + return; + end + if exist('csession','class'), + ses = csession(varargin{1}); + imgfile = ses.filename(varargin{2},'2dseq'); + else + ses = goto(varargin{1}); + imgfile = catfilename(ses,varargin{2},'2dseq'); + end + ivar = 3; +end + + +% check the file. +if ~exist(imgfile,'file'), + error(' ERROR %s: ''%s'' not found.',mfilename,imgfile); +end + +% SET OPTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +ImgSize = []; +ImgCrop = []; +SliceCrop = []; +TimeCrop = []; +ByteOrder = ''; +WordType = '_16BIT_SGN_INT'; +reco = []; +acqp = []; +imgp = []; +for N = ivar:2:length(varargin), + switch lower(varargin{N}), + case {'imgsize','imagesize'} + ImgSize = varargin{N+1}; + case {'imgcrop','imagecrop'} + ImgCrop = varargin{N+1}; + case {'slicrop','slicecrop'} + SliceCrop = varargin{N+1}; + case {'timecrop','tcrop'} + TimeCrop = varargin{N+1}; + case {'byteorder','endian','reco_byte_order'} + ByteOrder = varargin{N+1}; + case {'wordtype','datatype','data type','reco_wordtype'} + WordType = varargin{N+1}; + case {'reco'} + reco = varargin{N+1}; + case {'acqp'} + acqp = varargin{N+1}; + case {'imgpar','imgp','pvpar'} + imgp = varargin{N+1}; + end +end + +if nargout > 1 && isempty(imgp), + imgp = pv_imgpar(imgfile,'acqp',acqp,'reco',reco); +end + +% set image parameters from 'pv_imgpar'. +if ~isempty(imgp), + if isempty(ImgSize) ImgSize = imgp.imgsize; end + if isempty(ByteOrder), ByteOrder = imgp.RECO_byte_order; end + if isempty(WordType), WordType = imgp.RECO_wordtype; end +end + +% set image size if needed %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if isempty(ImgSize), + if isempty(reco), reco = pvread_reco(imgfile); end + if isempty(acqp), acqp = pvread_acqp(imgfile); end + nx = reco.RECO_size(1); + if length(reco.RECO_size) < 2, + ny = 1; + else + ny = reco.RECO_size(2); + end + ns = acqp.NSLICES; + nt = acqp.NR; + if strncmpi(acqp.PULPROG,' 2, + ns = reco.RECO_size(3); + end + nt = acqp.NI; + end + ImgSize = [nx ny ns nt]; + % check transposition on reco + transpos = 0; + if isfield(reco,'RECO_transposition'), + transpos = reco.RECO_transposition(1); + elseif isfield(reco,'RECO_transpose_dim'), + transpos = reco.RECO_transpose_dim(1); + end + if any(transpos), + if transpos == 1, + % (x,y,z) --> (y,x,z) + tmpvec = [2 1 3]; + elseif transpos == 2, + % (x,y,z) --> (x,z,y) + tmpvec = [1 3 2]; + elseif transpos == 3, + % (x,y,z) --> (z,y,x) + tmpvec = [3 2 1]; + end + ImgSize(1:3) = ImgSize(tmpvec); + end +end + +% check image crop %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if ~isempty(ImgCrop), + % ImgCrop as [x,y,width,height] + selx = [1:ImgCrop(3)] + ImgCrop(1) - 1; + sely = [1:ImgCrop(4)] + ImgCrop(2) - 1; + if min(selx) < 1 | max(selx) > ImgSize(1) | min(sely) < 1 | max(sely) > ImgSize(2), + fprintf('\n ImgSize=['); fprintf(' %d',ImgSize); fprintf(' ]'); + fprintf('\n ImgCrop=['); fprintf(' %d',ImgCrop); fprintf(' ]'); + error('\n %s error: imgcrop is out of range.\n',mfilename); + end +end + +% check slice crop %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if ~isempty(SliceCrop), + % SliceCrop as [s0, nslices] + sels = [1:SliceCrop(2)] + SliceCrop(1) - 1; + if min(sels) < 1 | max(sels) > ImgSize(3), + fprintf('\n ImgSize=['); fprintf(' %d',ImgSize); fprintf(' ]'); + fprintf('\n SliceCrop=['); fprintf(' %d',SliceCrop); fprintf(' ]'); + error('\n %s error: slicecrop is out of range.\n',mfilename); + end +end + +% check time crop %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if ~isempty(TimeCrop), + % TimeCrop as [t0, tlen] + selt = [1:TimeCrop(2)] + TimeCrop(1) - 1; + if min(selt) < 1 | max(selt) > ImgSize(4), + fprintf('\n ImgSize=['); fprintf(' %d',ImgSize); fprintf(' ]'); + fprintf('\n TimeCrop=['); fprintf(' %d',TimeCrop); fprintf(' ]'); + error('\n %s error: timecrop is out of range.\n',mfilename); + end +end + + +% set byte order %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if isempty(ByteOrder), + if isempty(reco), reco = pvread_reco(imgfile); end + ByteOrder = reco.RECO_byte_order; +end +switch lower(ByteOrder), + case {'s','swap','b','big','bigendian','big-endian'} + ByteOrder = 'ieee-be'; + case {'n','noswap','non-swap','l','little','littleendian','little-endian'} + ByteOrder = 'ieee-le'; +end + + +% set data type %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if isempty(WordType), + if isempty(reco), reco = pvread_reco(imgfile); end + WordType = reco.RECO_wordtype; +end +switch WordType, + case {'_16_BIT','_16BIT_SGN_INT','int16'} + WordType = 'int16=>int16'; + case {'_32_BIT','_32BIT_SGN_INT','int32'} + WordType = 'int32=>int32'; + otherwise + error(' %s error: unknown data type, ''%s''.',WordType,mfilename); +end + + +% READ DATA %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +fid = fopen(imgfile,'rb',ByteOrder); +IDATA = fread(fid,inf,WordType); +fclose(fid); + +if isfield(reco,'RECO_image_type') & strcmp(reco.RECO_image_type, 'COMPLEX_IMAGE'), + % According to ParaVision manual, + % first all real data is written to 2dseq, then imaginary data is appended to it. + IDATA = reshape(IDATA,length(IDATA)/2,2); + IDATA = complex(IDATA(:,1),IDATA(:,2)); +end + +try, + IDATA = reshape(IDATA,ImgSize); +catch + fprintf('\n Num.elements=%d,',numel(IDATA)); + fprintf('\n expected ImgSize=['); fprintf(' %d',ImgSize); fprintf(' ]'); + error('\n %s error: size mismatch.\n',mfilename); +end + + +% CROPPING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if ~isempty(ImgCrop), + IDATA = IDATA(selx,sely,:,:); +end +if ~isempty(SliceCrop), + IDATA = IDATA(:,:,sels,:); +end +if ~isempty(TimeCrop), + IDATA = IDATA(:,:,:,selt); +end + + +% RETURN VALUES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if nargout, + varargout{1} = IDATA; + if nargout > 1, + varargout{2} = imgp; + end +end + + +return; + diff --git a/mpi_code/pvread/pvread_acqp.m b/mpi_code/pvread/pvread_acqp.m new file mode 100644 index 0000000..6b67cab --- /dev/null +++ b/mpi_code/pvread/pvread_acqp.m @@ -0,0 +1,472 @@ +function varargout = pvread_acqp(varargin) +%PVREAD_ACQP - Read ParaVision "acqp". +% ACQP = PVREAD_ACQP(ACQPFILE,...) +% ACQP = PVREAD_ACQP(2DSEQFILE,...) +% ACQP = PVREAD_ACQP(SESSION,EXPNO,...) reads ParaVision's "acqp" and +% returns its contents as a structre, ACQP. +% Unknown parameter will be returned as a string. +% +% Supported options are +% 'verbose' : 0|1, verbose or not. +% +% VERSION : +% 0.90 13.06.05 YM pre-release +% 0.91 27.02.07 YM supports also 2dseq as the first argument +% 0.92 26.03.08 YM returns empty data if file not found. +% 0.93 18.09.08 YM supports both new csession and old getses. +% 0.94 15.01.09 YM supports some new parameters +% +% See also pv_imgpar pvread_2dseq pvread_imnd pvread_method pvread_reco pvread_visu_pars + +if nargin == 0, help pvread_acqp; return; end + + +if ischar(varargin{1}) & ~isempty(strfind(varargin{1},'acqp')), + % Called like pvread_acqp(ACQPFILE) + ACQPFILE = varargin{1}; + ivar = 2; +elseif ischar(varargin{1}) & ~isempty(strfind(varargin{1},'2dseq')), + % Called like pvread_acqp(2DSEQFILE) + ACQPFILE = fullfile(fileparts(fileparts(fileparts(varargin{1}))),'acqp'); + ivar = 2; +else + % Called like pvread_acqp(SESSION,ExpNo) + if nargin < 2, + error(' ERROR %s: missing 2nd arg. as ExpNo.\n',mfilename); + return; + end + if exist('csession','class'), + ses = csession(varargin{1}); + ACQPFILE = ses.filename(varargin{2},'acqp'); + else + ses = goto(varargin{1}); + ACQPFILE = catfilename(ses,varargin{2},'acqp'); + end + ivar = 3; +end + +% SET OPTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +VERBOSE = 1; +for N = ivar:2:nargin, + switch lower(varargin{N}), + case {'verbose'} + VERBOSE = varargin{N+1}; + end +end + + +if ~exist(ACQPFILE,'file'), + if VERBOSE, + fprintf(' ERROR %s: ''%s'' not found.\n',mfilename,ACQPFILE); + end + % SET OUTPUTS, IF REQUIRED %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + if nargout, + varargout{1} = []; + if nargout > 1, varargout{2} = {}; end + end + return; +end + + +% READ TEXT LINES OF "ACQP" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +texts = {}; +fid = fopen(ACQPFILE,'rt'); +while ~feof(fid), + texts{end+1} = fgetl(fid); + %texts{end+1} = fgets(fid); +end +fclose(fid); + + + +% MAKE "acqp" structure %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +acqp.filename = ACQPFILE; + +acqp.PULPROG = ''; +acqp.GRDPROG = ''; +acqp.ACQ_experiment_mode = ''; +acqp.ACQ_user_filter = ''; +acqp.ACQ_DS_enabled = ''; +acqp.ACQ_switch_pll_enabled= ''; +acqp.ACQ_preload = []; +acqp.ACQ_dim = []; +acqp.ACQ_dim_desc = ''; +acqp.ACQ_size = []; +acqp.ACQ_ns_list_size = []; +acqp.ACQ_ns = []; +acqp.ACQ_phase_factor = []; +acqp.ACQ_scan_size = ''; +acqp.NI = []; +acqp.NA = []; +acqp.NAE = []; +acqp.NR = []; +acqp.DS = []; +acqp.D = []; +acqp.P = []; +acqp.PL = []; +acqp.TPQQ = ''; +acqp.DPQQ = ''; +acqp.SW_h = []; +acqp.SW = []; +acqp.FW = []; +acqp.RG = []; +acqp.AQ_mod = ''; +acqp.DR = []; +acqp.PAPS = ''; +acqp.PH_ref = []; +acqp.ACQ_BF_enable = ''; +acqp.BF1 = []; +acqp.SFO1 = []; +acqp.O1 = []; +acqp.ACQ_O1_list_size = []; +acqp.ACQ_O1_list = []; +acqp.ACQ_O1B_list_size = []; +acqp.ACQ_O1B_list = []; +acqp.BF2 = []; +acqp.SFO2 = []; +acqp.O2 = []; +acqp.ACQ_O2_list_size = []; +acqp.ACQ_O2_list = []; +acqp.BF3 = []; +acqp.SFO3 = []; +acqp.O3 = []; +acqp.ACQ_O3_list_size = []; +acqp.ACQ_O3_list = []; +acqp.BF4 = []; +acqp.SFO4 = []; +acqp.O4 = []; +acqp.BF5 = []; +acqp.SFO5 = []; +acqp.O5 = []; +acqp.BF6 = []; +acqp.SFO6 = []; +acqp.O6 = []; +acqp.BF7 = []; +acqp.SFO7 = []; +acqp.O7 = []; +acqp.BF8 = []; +acqp.SFO8 = []; +acqp.O8 = []; +acqp.NUC1 = ''; +acqp.NUC2 = ''; +acqp.NUC3 = ''; +acqp.NUC4 = ''; +acqp.NUC5 = ''; +acqp.NUC6 = ''; +acqp.NUC7 = ''; +acqp.NUC8 = ''; +acqp.NUCLEUS = ''; +acqp.ACQ_coil_config_file = ''; +acqp.ACQ_coils = ''; +acqp.ACQ_coil_elements = ''; +acqp.ACQ_operation_mode = ''; +acqp.ACQ_Routing = ''; +acqp.ACQ_routing_mode = ''; +acqp.L = []; +acqp.ACQ_vd_list_size = []; +acqp.ACQ_vd_list = []; +acqp.ACQ_vp_list_size = []; +acqp.ACQ_vp_list = []; +acqp.ACQ_status = ''; +acqp.ACQ_Routing_base = ''; +acqp.ACQ_protocol_location = ''; +acqp.ACQ_protocol_name = ''; +acqp.ACQ_scan_name = ''; +acqp.ACQ_method = ''; +acqp.ACQ_completed = ''; +acqp.ACQ_pipe_status = ''; +acqp.ACQ_scans_completed = []; +acqp.ACQ_nr_completed = []; +acqp.ACQ_total_completed = []; +acqp.ACQ_word_size = ''; +acqp.NECHOES = []; +acqp.ACQ_n_echo_images = []; +acqp.ACQ_n_movie_frames = []; +acqp.ACQ_echo_descr = ''; +acqp.ACQ_movie_descr = ''; +acqp.ACQ_fov = []; +acqp.ACQ_read_ext = []; +acqp.ACQ_slice_angle = []; +acqp.ACQ_slice_orient = ''; +acqp.ACQ_patient_pos = ''; +acqp.ACQ_read_offset = []; +acqp.ACQ_phase1_offset = []; +acqp.ACQ_phase2_offset = []; +acqp.ACQ_slice_sepn = []; +acqp.ACQ_slice_sepn_mode = ''; +acqp.ACQ_slice_thick = []; +acqp.ACQ_slice_offset = []; +acqp.ACQ_obj_order = []; +acqp.ACQ_flip_angle = []; +acqp.ACQ_flipback = ''; +acqp.ACQ_echo_time = []; +acqp.ACQ_inter_echo_time = []; +acqp.ACQ_recov_time = []; +acqp.ACQ_repetition_time = []; +acqp.ACQ_scan_time = []; +acqp.ACQ_inversion_time = []; +acqp.ACQ_temporal_delay = []; +acqp.ACQ_time = ''; +acqp.ACQ_time_points = []; +acqp.ACQ_abs_time = []; +acqp.ACQ_operator = ''; +acqp.ACQ_RF_power = []; +acqp.ACQ_transmitter_coil = ''; +acqp.ACQ_receiver_coil = ''; +acqp.ACQ_contrast_agent = ''; +acqp.ACQ_trigger_enable = ''; +acqp.ACQ_trigger_reference = ''; +acqp.ACQ_trigger_delay = []; +acqp.ACQ_institution = ''; +acqp.ACQ_station = ''; +acqp.ACQ_sw_version = ''; +acqp.ACQ_calib_date = ''; +acqp.ACQ_grad_str_X = []; +acqp.ACQ_grad_str_Y = []; +acqp.ACQ_grad_str_Z = []; +acqp.ACQ_position_X = []; +acqp.ACQ_position_Y = []; +acqp.ACQ_position_Z = []; +acqp.Coil_operation = ''; +acqp.BYTORDA = ''; +acqp.INSTRUM = ''; +acqp.ACQ_adc_overflow = ''; +acqp.GRPDLY = []; +acqp.FRQLO3 = []; +acqp.FQ1LIST = ''; +acqp.FQ2LIST = ''; +acqp.FQ3LIST = ''; +acqp.FQ8LIST = ''; +acqp.SP = []; +acqp.SPOFFS = []; +acqp.SPNAM0 = ''; +acqp.SPNAM1 = ''; +acqp.SPNAM2 = ''; +acqp.SPNAM3 = ''; +acqp.SPNAM4 = ''; +acqp.SPNAM5 = ''; +acqp.SPNAM6 = ''; +acqp.SPNAM7 = ''; +acqp.SPNAM8 = ''; +acqp.SPNAM9 = ''; +acqp.SPNAM10 = ''; +acqp.SPNAM11 = ''; +acqp.SPNAM12 = ''; +acqp.SPNAM13 = ''; +acqp.SPNAM14 = ''; +acqp.SPNAM15 = ''; +acqp.HPPRGN = ''; +acqp.LOCNUC = ''; +acqp.QNP = []; +acqp.SOLVENT = ''; +acqp.DIGMOD = ''; +acqp.DIGTYP = ''; +acqp.DQDMODE = ''; +acqp.DSPFIRM = ''; +acqp.DECIM = []; +acqp.DSPFVS = []; +acqp.ACQ_scan_shift = []; +acqp.DEOSC = []; +acqp.DE = []; +acqp.FCUCHAN = []; +acqp.RSEL = []; +acqp.SWIBOX = []; +acqp.HPMOD = []; +acqp.RECCHAN = []; +acqp.RECSEL = []; +acqp.RECPRE = []; +acqp.NLOGCH = []; +acqp.POWMOD = ''; +acqp.PRECHAN = []; +acqp.PRECHRX = []; +acqp.OBSCHAN = []; +acqp.ACQ_2nd_preamp = ''; +acqp.ACQ_n_trim = []; +acqp.ACQ_trim = []; +acqp.ACQ_scaling_read = []; +acqp.ACQ_scaling_phase = []; +acqp.ACQ_scaling_slice = []; +acqp.ACQ_grad_matrix = []; +acqp.NSLICES = []; +acqp.ACQ_rare_factor = []; +acqp.ACQ_phase_encoding_mode = ''; +acqp.ACQ_phase_enc_start = []; +acqp.ACQ_spatial_size_1 = []; +acqp.ACQ_spatial_phase_1 = []; +acqp.GS_dim = []; +acqp.GS_disp_update = ''; +acqp.GS_online_reco = ''; +acqp.GS_reco_display = ''; +acqp.GS_image_type = ''; +acqp.GS_typ = ''; +acqp.GS_auto_name = ''; +acqp.GS_info_dig_filling = ''; +acqp.GS_info_normalized_area = ''; +acqp.GS_info_max_point = ''; +acqp.GS_get_info_points = ''; +acqp.GS_continue = ''; +acqp.GS_ReceiverSelect = ''; +acqp.GO_init_files = ''; +acqp.GO_data_save = ''; +acqp.GO_block_size = ''; +acqp.GO_raw_data_format = ''; +acqp.GO_disp_update = ''; +acqp.GO_online_reco = ''; +acqp.GO_reco_display = ''; +acqp.GO_reco_each_nr = ''; +acqp.GO_max_reco_mem = []; +acqp.GO_time_est = ''; +acqp.GO_use_macro = ''; +acqp.GO_macro = ''; + +% for MDEFT +acqp.ACQ_spatial_size_2 = []; + +% new parameters + + + + + + +% GET "acqp" VALUES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +for N = 1:length(texts), + if strncmpi(texts{N},'##$',3), + % get the parameter name + idx = strfind(texts{N},'='); + tmpname = texts{N}(4:idx-1); + % get the value(s) + if isempty(strfind(texts{N},'=(')), + tmpval = texts{N}(idx+1:end); + tmpdim = []; + else + s1 = strfind(texts{N},'('); + s2 = strfind(texts{N},')'); + if isempty(s2), + tmpdim = []; + tmpval = texts{N}(s1:end); + else + % get dimension + tmpdim = str2num(texts{N}(s1+1:s2-1)); + tmpval = ''; + end + K = N; + while ~strncmpi(texts{K+1},'##',2), + K = K + 1; + end + % USE sprintf() since strcat remove blank... + if isempty(tmpdim), + tmpval = sprintf('%s',tmpval,texts{N+1:K}); + else + tmpval = sprintf('%s ',tmpval,texts{N+1:K}); + end + %tmpval = strcat(texts{N+1:K}); + N = K + 1; + end + + % WHY?? THIS HAPPENS + idx = strfind(tmpval,'$$'); + if ~isempty(idx), tmpval = tmpval(1:idx-1); end + + % set the value(s) + tmpval = strtrim(tmpval); + if isfield(acqp,tmpname), + if ischar(acqp.(tmpname)), + if any(tmpdim) && tmpval(1) ~= '<', + acqp.(tmpname) = subStr2CellStr(tmpval,tmpdim); + else + acqp.(tmpname) = tmpval; + end + elseif isnumeric(acqp.(tmpname)), + acqp.(tmpname) = str2num(tmpval); + if length(tmpdim) > 1 & prod(tmpdim) == numel(acqp.(tmpname)), + acqp.(tmpname) = reshape(acqp.(tmpname),fliplr(tmpdim)); + acqp.(tmpname) = permute(acqp.(tmpname),length(tmpdim):-1:1); + end + else + acqp.(tmpname) = tmpval; + end + else + acqp.(tmpname) = tmpval; + end + end +end + +% after care of some parameters.... +%acqp.xxxx = subStr2CellNum(acqp.xxxx); + + +% remove empty members +fields = fieldnames(acqp); +IDX = zeros(1,length(fields)); +for N = 1:length(fields), IDX(N) = isempty(acqp.(fields{N})); end +acqp = rmfield(acqp,fields(find(IDX))); + + +% SET OUTPUTS, IF REQUIRED %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if nargout, + varargout{1} = acqp; + if nargout > 1, + varargout{2} = texts; + end +end + +return; + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCITON to make a cell string from a 'space' or '()' separeted string +function val = subStr2CellStr(str,dim) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if isempty(str) || iscell(str), + val = str; + return; +end + +if nargin < 2, dim = []; end + +val = {}; + +if str(1) == '(', + idx1 = strfind(str,'('); + idx2 = strfind(str,')'); + for N = 1:length(idx1), + val{N} = strtrim(str(idx1(N)+1:idx2(N)-1)); + end +else + % 'space' separated + [token, rem] = strtok(str,' '); + while ~isempty(token), + val{end+1} = token; + [token, rem] = strtok(rem,' '); + end +end + +if length(dim) > 1 && prod(dim) > 0, + val = reshape(val,dim); +end + +return; + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCITON to make a cell matrix from a '()' separeted string +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function val = subStr2CellNum(str) +if isempty(str), + val = str; + return; +end + +idx1 = strfind(str,'('); +idx2 = strfind(str,')'); + +val = {}; +for N = 1:length(idx1), + val{N} = str2num(str(idx1(N)+1:idx2(N)-1)); +end + +return; diff --git a/mpi_code/pvread/pvread_imnd.m b/mpi_code/pvread/pvread_imnd.m new file mode 100644 index 0000000..89371da --- /dev/null +++ b/mpi_code/pvread/pvread_imnd.m @@ -0,0 +1,466 @@ +function varargout = pvread_imnd(varargin) +%PVREAD_IMND - Read ParaVision "imnd". +% IMND = PVREAD_IMND(IMNDFILE,...) +% IMND = PVREAD_IMND(2DSEQFILE,...) +% IMND = PVREAD_IMND(SESSION,EXPNO,...) reads ParaVision's "imnd" and +% returns its contents as a structre, IMND. +% Unknown parameter will be returned as a string. +% +% Supported options are +% 'verbose' : 0|1, verbose or not. +% +% VERSION : +% 0.90 13.06.05 YM pre-release +% 0.91 14.06.05 YM checked both 'mdeft' and 'epi'. +% 0.92 27.02.07 YM supports also 2dseq as the first argument +% 0.93 26.03.08 YM returns empty data if file not found. +% 0.94 18.09.08 YM supports both new csession and old getses. +% +% See also pv_imgpar pvread_2dseq pvread_acqp pvread_method pvread_reco pvread_visu_pars + +if nargin == 0, help pvread_imnd; return; end + + +if ischar(varargin{1}) & ~isempty(strfind(varargin{1},'imnd')), + % Called like pvread_imnd(IMNDFILE) + IMNDFILE = varargin{1}; + ivar = 2; +elseif ischar(varargin{1}) & ~isempty(strfind(varargin{1},'2dseq')), + % Called like pvread_imnd(2DSEQFILE) + IMNDFILE = fullfile(fileparts(fileparts(fileparts(varargin{1}))),'imnd'); + ivar = 2; +else + % Called like pvread_imnd(SESSION,ExpNo) + if nargin < 2, + error(' ERROR %s: missing 2nd arg. as ExpNo.\n',mfilename); + return; + end + if exist('csession','class'), + ses = csession(varargin{1}); + IMNDFILE = ses.filename(varargin{2},'imnd'); + else + ses = goto(varargin{1}); + IMNDFILE = catfilename(ses,varargin{2},'imnd'); + end + ivar = 3; +end + + +% SET OPTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +VERBOSE = 1; +for N = ivar:2:nargin, + switch lower(varargin{N}), + case {'verbose'} + VERBOSE = varargin{N+1}; + end +end + + +if ~exist(IMNDFILE,'file'), + if VERBOSE, + fprintf(' ERROR %s: ''%s'' not found.\n',mfilename,IMNDFILE); + end + % SET OUTPUTS, IF REQUIRED %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + if nargout, + varargout{1} = []; + if nargout > 1, varargout{2} = {}; end + end + return; +end + + +% READ TEXT LINES OF "IMND" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +texts = {}; +fid = fopen(IMNDFILE,'rt'); +while ~feof(fid), + texts{end+1} = fgetl(fid); + %texts{end+1} = fgets(fid); +end +fclose(fid); + + + +% MAKE "imnd" structure %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +imnd.filename = IMNDFILE; + +imnd.IMND_method = ''; +imnd.IMND_method_display_name = ''; +imnd.IMND_dummy_method = ''; +imnd.IMND_nucleus = ''; +imnd.IMND_matrix_eq = []; +imnd.IMND_matrix = []; +imnd.IMND_sw_h = []; +imnd.IMND_scout_orient_matrix_curr = []; +imnd.IMND_scout_orient_matrix = []; +imnd.IMND_rep_time = []; +imnd.IMND_recov_time = []; +imnd.IMND_echo_time = []; +imnd.IMND_add_delay = []; +imnd.IMND_homospoil_delay = []; +imnd.IMND_pulse_angle = []; +imnd.IMND_total_time = []; +imnd.IMND_pulse_length = []; +imnd.IMND_refocus_length = []; +imnd.IMND_sat_pulse_length = []; +imnd.IMND_n_averages = []; +imnd.IMND_flipback = ''; +imnd.IMND_n_echo_images = []; +imnd.IMND_echo_scan_eq = []; +imnd.IMND_n_echoes = []; +imnd.IMND_rare_factor = []; +imnd.EPI_AQ_mod = ''; +imnd.EPI_DIGMOD = ''; +imnd.EPI_DSPFIRM = ''; +imnd.EPI_max_read = []; +imnd.IMND_max_read = []; +imnd.EPI_int = []; +imnd.EPI_double = []; +imnd.EPI_diff_use_corr = ''; +imnd.EPI_supp_flag = ''; +imnd.EPI_trim = []; +imnd.EPI_scan_mode = ''; +imnd.EPI_TE_eff = []; +imnd.EPI_se_asymmetry_offset = []; +imnd.EPI_read_spoiler = []; +imnd.EPI_zero_phase = []; +imnd.EPI_zero_phase_ms = []; +imnd.EPI_seg_acq_time = []; +imnd.EPI_image_time = []; +imnd.EPI_even_only = ''; +imnd.EPI_read_echo_pos = []; +imnd.EPI_phaseblip_asym = []; +imnd.EPI_phasedur_asym = []; +imnd.EPI_phaseblip_ms = []; +imnd.EPI_phase_off = ''; +imnd.EPI_use_pipefilter = ''; +imnd.EPI_linear_regrid = ''; +imnd.IMND_regrid_mode = ''; +imnd.IMND_regrid_traj = []; +imnd.EPI_correction_mode = ''; +imnd.EPI_navigation_type = ''; +imnd.EPI_ramp_time = []; +imnd.EPI_ramp_gap = []; +imnd.EPI_ramp_time_x = []; +imnd.EPI_ramp_time_y = []; +imnd.EPI_ramp_time_z = []; +imnd.IMND_assym_acq = []; +imnd.IMND_matched_bw = ''; +imnd.IMND_max_read = []; +imnd.IMND_flow = []; +imnd.EPI_FID = ''; +imnd.EPI_NAV_FIRST_NR = ''; +imnd.EPI_SE_DIFFUSION = ''; +imnd.EPI_SE_Inversion = ''; +imnd.EPI_SE_Tagging = ''; +imnd.EPI_SPIN_ECHO = ''; +imnd.EPI_STE_DIFFUSION = ''; +imnd.EPI_STIMULATED_ECHO = ''; +imnd.EPI_Not_TC = ''; +imnd.EPI_Set_TC = ''; +imnd.EPI_Set_TCnav = ''; +imnd.EPI_Set_TCnF = ''; +imnd.EPI_seg_grad = []; +imnd.EPI_tagging_phase = ''; +imnd.EPI_tagging_read = ''; +imnd.EPI_O3_list_size = []; +imnd.EPI_O6_list_size = []; +imnd.EPI_O6_list = []; +imnd.Trigger_In_Once = ''; +imnd.Trigger_In_Every_Package = ''; +imnd.Trigger_In_Every_Excitation = ''; +imnd.Trigger_Out_Once = ''; +imnd.Trigger_Out_Every_Package = ''; +imnd.Trigger_Out_Every_Excitation= ''; +imnd.EPI_xfer_buffer_size = []; +imnd.EPI_grad_cal_const = []; +imnd.EPI_X_factor = []; +imnd.EPI_Y_factor = []; +imnd.EPI_Z_factor = []; +imnd.EPI_status = ''; +imnd.EPI_preemp_file = ''; +imnd.EPI_resid = ''; +imnd.IMND_store_sw_h = []; +imnd.EPI_SEG_CALC = ''; +imnd.EPI_Trigger_In = ''; +imnd.EPI_Trigger_Out = ''; +imnd.EPI_Pause_Trigger_Out = ''; +imnd.EPI_DS_enabled = ''; +imnd.EPI_recm_slice_rep_time = []; +imnd.EPI_slice_rep_time = []; +imnd.EPI_use_vd = ''; +imnd.EPI_use_id = ''; +imnd.EPI_use_Synch = ''; +imnd.EPI_TC_mode = ''; +imnd.EPI_TimeToNav = []; +imnd.EPI_TC_nslices = []; +imnd.EPI_TC_DS = []; +imnd.EPI_nav_DS = []; +imnd.EPI_navAU_DS = []; +imnd.EPI_n_navfids = []; +imnd.EPI_n_navprep = []; +imnd.EPI_n_navecho = []; +imnd.EPI_TC_rep_time = []; +imnd.EPI_TC_respFreq = []; +imnd.EPI_dummy_echoes = []; +imnd.EPI_ds_echopairs = []; +imnd.EPI_recm_image_rep_time = []; +imnd.EPI_image_rep_time = []; +imnd.EPI_swh_eff_phase = []; +imnd.EPI_segmentation_mode = ''; +imnd.IMND_numsegments = []; +imnd.EPI_numsegments = []; +imnd.EPI_nr = []; +imnd.EPI_act_rep_time = []; +imnd.IMND_inv_delay_storage = []; +imnd.IMND_num_segments = []; +imnd.IMND_tau_time = []; +imnd.IMND_MagPrep_mode = ''; +imnd.IMND_dim = []; +imnd.IMND_patient_pos = ''; +imnd.IMND_dimension = ''; +imnd.IMND_square_fov_matrix = ''; +imnd.IMND_isotropic = ''; +imnd.IMND_fov_eq = []; +imnd.IMND_fov = []; +imnd.IMND_slice_orient = ''; +imnd.IMND_n_slices = []; +imnd.IMND_slice_offset = []; +imnd.IMND_slice_sepn_mode = ''; +imnd.IMND_slice_sepn = []; +imnd.IMND_slice_thick = []; +imnd.IMND_slice_angle = []; +imnd.IMND_slice_angle_eq = []; +imnd.IMND_ScoutRel_SgRotAngle = []; +imnd.IMND_ScoutRel_SgRotAngle_eq = []; +imnd.IMND_ScoutRel_SgTiltAngle = []; +imnd.IMND_ScoutRel_SgTiltAngle_eq= []; +imnd.IMND_ScoutRel_RgRotAngle = []; +imnd.IMND_ScoutRel_RgRotAngle_eq = []; +imnd.IMND_read_ext = []; +imnd.IMND_read_offset = []; +imnd.IMND_read_offset_eq = []; +imnd.IMND_slice_scheme = ''; +imnd.IMND_slice_list = []; +imnd.IMND_n_slicepacks = []; +imnd.IMND_slicepack_n_slices = []; +imnd.IMND_slicepack_vector = []; +imnd.IMND_slicepack_position = []; +imnd.IMND_slicepack_gap = []; +imnd.IMND_read_vector = []; +imnd.IMND_slicepack_read_offset = []; +imnd.IMND_phase1_offset = []; +imnd.IMND_phase2_offset = []; +imnd.IMND_anti_alias = []; +imnd.IMND_csind_flag = ''; +imnd.IMND_acq_mode = ''; +imnd.IMND_trigger_enable = ''; +imnd.IMND_auto_adv = ''; +imnd.IMND_evolution_trigger = ''; +imnd.IMND_movie = ''; +imnd.IMND_mtc_mode = ''; +imnd.IMND_inv_mode = ''; +imnd.IMND_fat_mode = ''; +imnd.IMND_suppression = ''; +imnd.IMND_supp_shape_enum = ''; +imnd.IMND_supp_length = []; +imnd.IMND_sat_mode = ''; +imnd.IMND_sat_shape = ''; +imnd.IMND_sat_slice_thick_hz = []; +imnd.IMND_FovSat_n_slices = []; +imnd.IMND_FovSat_thick = []; +imnd.IMND_FovSat_offset = []; +imnd.IMND_FovSat_dir_vector = []; +imnd.IMND_FovSat_rot_angle = []; +imnd.IMND_FovSat_tilt_angle = []; +imnd.IMND_InflowSat_n_slices = []; +imnd.IMND_InflowSat_thick = []; +imnd.IMND_InflowSat_slice_offset = []; +imnd.IMND_contrast_agent = ''; +imnd.IMND_grad_refo = ''; +imnd.IMND_rf_spoil = ''; +imnd.IMND_use_grad = []; +imnd.IMND_use_rise_time = []; +imnd.IMND_max_spoil_time = []; +imnd.IMND_imag_shape_enum = ''; +imnd.IMND_imag_shape = ''; +imnd.IMND_sl_thick_hz = []; +imnd.IMND_acq_time = []; +imnd.IMND_DW_time = []; +imnd.IMND_rep_delay = []; +imnd.IMND_nuc1 = ''; +imnd.IMND_bf1 = []; +imnd.IMND_rcvr_offset_bc = ''; +imnd.IMND_isotropic_reco = ''; +imnd.IMND_zf = []; +imnd.IMND_apc = ''; +imnd.IMND_phase_encoding_mode_1 = ''; +imnd.IMND_phase_encoding_mode = ''; +imnd.IMND_phase_start_1 = []; +imnd.IMND_phase_enc_start = []; +imnd.IMND_user_phase = []; +imnd.IMND_dscan_time = []; +imnd.IMND_dscans = []; +imnd.IMND_derive_gains = ''; +imnd.IMND_reference_gain = []; +imnd.IMND_ref_gain_state = ''; +imnd.IMND_rg_defined = ''; +imnd.IMND_motionsup = ''; +imnd.IMND_EffEchoTime1 = []; +imnd.IMND_NEchoScan1 = []; +imnd.IMND_RareMaxEchoes = []; +imnd.IMND_flowcomp = ''; +imnd.IMND_bandwidth_1 = []; +imnd.IMND_ScanSummary = ''; +imnd.IMND_invflag = ''; +imnd.IMND_mtcflag = ''; +imnd.IMND_fatflag = ''; +imnd.IMND_FovSat_flag = []; +imnd.IMND_InflowSat_flag = []; +imnd.IMND_TE_long = ''; + + + +% GET "imnd" VALUES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +for N = 1:length(texts), + if strncmpi(texts{N},'##$',3), + % get the parameter name + idx = strfind(texts{N},'='); + tmpname = texts{N}(4:idx-1); + % get the value(s) + if isempty(strfind(texts{N},'=(')), + tmpval = texts{N}(idx+1:end); + tmpdim = []; + else + s1 = strfind(texts{N},'('); + s2 = strfind(texts{N},')'); + if isempty(s2), + tmpdim = []; + tmpval = texts{N}(s1:end); + else + % get dimension + tmpdim = str2num(texts{N}(s1+1:s2-1)); + tmpval = ''; + end + K = N; + while ~strncmpi(texts{K+1},'##',2), + K = K + 1; + end + % USE sprintf() since strcat remove blank... + if isempty(tmpdim), + tmpval = sprintf('%s',tmpval,texts{N+1:K}); + else + tmpval = sprintf('%s ',tmpval,texts{N+1:K}); + end + %tmpval = strcat(texts{N+1:K}); + N = K + 1; + end + + % WHY?? THIS HAPPENS + idx = strfind(tmpval,'$$'); + if ~isempty(idx), tmpval = tmpval(1:idx-1); end + + % set the value(s) + tmpval = strtrim(tmpval); + if isfield(imnd,tmpname), + if ischar(imnd.(tmpname)), + if any(tmpdim) && tmpval(1) ~= '<', + imnd.(tmpname) = subStr2CellStr(tmpval,tmpdim); + else + imnd.(tmpname) = tmpval; + end + imnd.(tmpname) = tmpval; + elseif isnumeric(imnd.(tmpname)), + imnd.(tmpname) = str2num(tmpval); + if length(tmpdim) > 1 & prod(tmpdim) == numel(imnd.(tmpname)), + imnd.(tmpname) = reshape(imnd.(tmpname),fliplr(tmpdim)); + imnd.(tmpname) = permute(imnd.(tmpname),length(tmpdim):-1:1); + end + else + imnd.(tmpname) = tmpval; + end + else + imnd.(tmpname) = tmpval; + end + end +end + +% after care of some parameters.... +%imnd.xxxx = subStr2CellNum(imnd.xxxx); + + +% remove empty members +fields = fieldnames(imnd); +IDX = zeros(1,length(fields)); +for N = 1:length(fields), IDX(N) = isempty(imnd.(fields{N})); end +imnd = rmfield(imnd,fields(find(IDX))); + + + + +% SET OUTPUTS, IF REQUIRED %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if nargout, + varargout{1} = imnd; + if nargout > 1, + varargout{2} = texts; + end +end + +return; + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCITON to make a cell string from a 'space' or '()' separeted string +function val = subStr2CellStr(str,dim) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if isempty(str) || iscell(str), + val = str; + return; +end + +if nargin < 2, dim = []; end + +val = {}; + +if str(1) == '(', + idx1 = strfind(str,'('); + idx2 = strfind(str,')'); + for N = 1:length(idx1), + val{N} = strtrim(str(idx1(N)+1:idx2(N)-1)); + end +else + % 'space' separated + [token, rem] = strtok(str,' '); + while ~isempty(token), + val{end+1} = token; + [token, rem] = strtok(rem,' '); + end +end + +if length(dim) > 1 && prod(dim) > 0, + val = reshape(val,dim); +end + +return; + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCITON to make a cell matrix from a '()' separeted string +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function val = subStr2CellNum(str) +if isempty(str), + val = str; + return; +end + +idx1 = strfind(str,'('); +idx2 = strfind(str,')'); + +val = {}; +for N = 1:length(idx1), + val{N} = str2num(str(idx1(N)+1:idx2(N)-1)); +end + +return; diff --git a/mpi_code/pvread/pvread_method.m b/mpi_code/pvread/pvread_method.m new file mode 100644 index 0000000..25a88f8 --- /dev/null +++ b/mpi_code/pvread/pvread_method.m @@ -0,0 +1,530 @@ +function varargout = pvread_method(varargin) +%PVREAD_METHOD - Read ParaVision "method". +% METHOD = PVREAD_METHOD(METHODFILE,...) +% METHOD = PVREAD_METHOD(2DSEQFILE,...) +% METHOD = PVREAD_METHOD(SESSION,EXPNO,...) reads ParaVision's "method" and +% returns its contents as a structre, METHOD. +% Unknown parameter will be returned as a string. +% +% Supported options are +% 'verbose' : 0|1, verbose or not. +% +% VERSION : +% 0.90 26.03.08 YM pre-release, checked epi/mdeft/rare/flash of 7T. +% 0.91 18.09.08 YM supports both new csession and old getses. +% 0.92 15.01.09 YM supports some new parameters +% +% See also pv_imgpar pvread_2dseq pvread_acqp pvread_imnd pvread_reco pvread_visu_pars + +if nargin == 0, help pvread_method; return; end + + +if ischar(varargin{1}) & ~isempty(strfind(varargin{1},'method')), + % Called like pvread_method(METHODFILE) + METHODFILE = varargin{1}; + ivar = 2; +elseif ischar(varargin{1}) & ~isempty(strfind(varargin{1},'2dseq')), + % Called like pvread_method(2DSEQFILE) + METHODFILE = fullfile(fileparts(fileparts(fileparts(varargin{1}))),'method'); + ivar = 2; +else + % Called like pvread_method(SESSION,ExpNo) + if nargin < 2, + error(' ERROR %s: missing 2nd arg. as ExpNo.\n',mfilename); + return; + end + if exist('csession','class'), + ses = csession(varargin{1}); + METHODFILE = ses.filename(varargin{2},'method'); + else + ses = goto(varargin{1}); + METHODFILE = catfilename(ses,varargin{2},'method'); + end + ivar = 3; +end + + +% SET OPTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +VERBOSE = 1; +for N = ivar:2:nargin, + switch lower(varargin{N}), + case {'verbose'} + VERBOSE = varargin{N+1}; + end +end + + +if ~exist(METHODFILE,'file'), + if VERBOSE, + fprintf(' ERROR %s: ''%s'' not found.\n',mfilename,METHODFILE); + end + % SET OUTPUTS, IF REQUIRED %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + if nargout, + varargout{1} = []; + if nargout > 1, varargout{2} = {}; end + end + return; +end + + +% READ TEXT LINES OF "METHOD" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +texts = {}; +fid = fopen(METHODFILE,'rt'); +while ~feof(fid), + texts{end+1} = fgetl(fid); + %texts{end+1} = fgets(fid); +end +fclose(fid); + + + +% MAKE "method" structure %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +method.filename = METHODFILE; + +method.Method = ''; +method.EchoTime = []; +method.PVM_MinEchoTime = []; +method.NSegments = []; +method.PVM_RepetitionTime = []; +method.PackDel = []; +method.PVM_NAverages = []; +method.PVM_NRepetitions = []; +method.PVM_ScanTimeStr = ''; +method.SignalType = ''; +method.PVM_UserType = ''; +method.PVM_DeriveGains = ''; +method.PVM_EncUseMultiRec = ''; +method.PVM_EncActReceivers= ''; +method.PVM_EncZfRead = []; +method.PVM_EncPpiAccel1 = []; +method.PVM_EncPftAccel1 = []; +method.PVM_EncPpiRefLines1= []; +method.PVM_EncZfAccel1 = []; +method.PVM_EncOrder1 = ''; +method.PVM_EncStart1 = []; +method.PVM_EncMatrix = []; +method.PVM_EncSteps1 = []; +method.PVM_EncCentralStep1= []; +method.PVM_EncTotalAccel = []; +method.PVM_EncNReceivers = []; +method.PVM_EncAvailReceivers = []; +method.PVM_EncChanScaling = []; +method.PVM_OperationMode = ''; +method.ExcPulseEnum = ''; +method.ExcPulse = ''; +method.RefPulseEnum = ''; +method.RefPulse = ''; +method.PVM_GradCalConst = []; +method.PVM_Nucleus1Enum = ''; +method.PVM_Nucleus1 = ''; +method.PVM_RefAttMod1 = ''; +method.PVM_RefAttCh1 = []; +method.PVM_RefAttStat1 = ''; +method.PVM_Nucleus2Enum = ''; +method.PVM_Nucleus3Enum = ''; +method.PVM_Nucleus4Enum = ''; +method.PVM_Nucleus5Enum = ''; +method.PVM_Nucleus6Enum = ''; +method.PVM_Nucleus7Enum = ''; +method.PVM_Nucleus8Enum = ''; +method.RephaseTime = []; +method.PVM_EffSWh = []; +method.PVM_EpiNavigatorMode=''; +method.PVM_EpiPrefixNavYes= ''; +method.PVM_EpiGradSync = ''; +method.PVM_EpiRampMode = ''; +method.PVM_EpiRampForm = ''; +method.PVM_EpiRampComp = ''; +method.PVM_EpiNShots = []; +method.PVM_EpiEchoPosition= []; +method.PVM_EpiRampTime = []; +method.PVM_EpiSlope = []; +method.PVM_EpiEffSlope = []; +method.PVM_EpiBlipTime = []; +method.PVM_EpiSwitchTime = []; +method.PVM_EpiEchoDelay = []; +method.PVM_EpiModuleTime = []; +method.PVM_EpiGradDwellTime=[]; +method.PVM_EpiAutoGhost = ''; +method.PVM_EpiAcqDelayTrim= []; +method.PVM_EpiBlipAsym = []; +method.PVM_EpiReadAsym = []; +method.PVM_EpiReadDephTrim= []; +method.PVM_EpiEchoTimeShifting=''; +method.PVM_EpiEchoShiftA = []; +method.PVM_EpiEchoShiftB = []; +method.PVM_EpiDriftCorr = ''; +method.PVM_EpiGrappaThresh= []; +method.PVM_EpiEchoSpacing = []; +method.PVM_EpiEffBandwidth= []; +method.PVM_EpiDephaseTime = []; +method.PVM_EpiDephaseRampTime= []; +method.PVM_EpiPlateau = []; +method.PVM_EpiAcqDelay = []; +method.PVM_EpiInterTime = []; +method.PVM_EpiReadDephGrad = []; +method.PVM_EpiReadOddGrad = []; +method.PVM_EpiReadEvenGrad= []; +method.PVM_EpiPhaseDephGrad= []; +method.PVM_EpiPhaseRephGrad= []; +method.PVM_EpiBlipOddGrad = []; +method.PVM_EpiBlipEvenGrad= []; +method.PVM_EpiPhaseEncGrad= []; +method.PVM_EpiPhaseRewGrad= []; +method.PVM_EpiNEchoes = []; +method.PVM_EpiEchoCounter = []; +method.PVM_EpiRampUpIntegral= []; +method.PVM_EpiRampDownIntegral= []; +method.PVM_EpiBlipIntegral= []; +method.PVM_EpiSlopeFactor = []; +method.PVM_EpiSlewRate = []; +method.PVM_EpiNSamplesPerScan = []; +method.PVM_EpiPrefixNavSize = []; +method.PVM_EpiPrefixNavDur= []; +method.PVM_EpiNScans = []; +method.PVM_EpiNInitNav = []; +method.PVM_EpiAdjustMode = []; +method.PVM_EpiReadCenter = []; +method.PVM_EpiPhaseCorrection = []; +method.PVM_EpiGrappaCoefficients = []; +method.BwScale = []; +method.PVM_TrajectoryMeasurement = ''; +method.PVM_UseTrajectory = ''; +method.PVM_ExSliceRephaseTime = []; +method.SliceSpoilerDuration = []; +method.SliceSpoilerStrength = []; +method.PVM_DigAutSet = ''; +method.PVM_DigQuad = ''; +method.PVM_DigFilter = ''; +method.PVM_DigRes = []; +method.PVM_DigDw = []; +method.PVM_DigSw = []; +method.PVM_DigNp = []; +method.PVM_DigShift = []; +method.PVM_DigGroupDel = []; +method.PVM_DigDur = []; +method.PVM_DigEndDelMin = []; +method.PVM_DigEndDelOpt = []; +method.PVM_GeoMode = ''; +method.PVM_SpatDimEnum = ''; +method.PVM_Isotropic = ''; +method.PVM_Fov = []; +method.PVM_FovCm = []; +method.PVM_SpatResol = []; +method.PVM_Matrix = []; +method.PVM_MinMatrix = []; +method.PVM_MaxMatrix = []; +method.PVM_AntiAlias = []; +method.PVM_MaxAntiAlias = []; +method.PVM_SliceThick = []; +method.PVM_ObjOrderScheme = ''; +method.PVM_ObjOrderList = []; +method.PVM_NSPacks = []; +method.PVM_SPackArrNSlices= []; +method.PVM_MajSliceOri = ''; +method.PVM_SPackArrSliceOrient = ''; +method.PVM_SPackArrReadOrient = ''; +method.PVM_SPackArrReadOffset = []; +method.PVM_SPackArrPhase1Offset = []; +method.PVM_SPackArrPhase2Offset = []; +method.PVM_SPackArrSliceOffset = []; +method.PVM_SPackArrSliceGapMode = ''; +method.PVM_SPackArrSliceGap = []; +method.PVM_SPackArrSliceDistance = []; +method.PVM_SPackArrGradOrient = []; +method.Reco_mode = ''; +method.NDummyScans = []; +method.PVM_TriggerModule = ''; +method.PVM_TaggingOnOff = ''; +method.PVM_TaggingPulse = ''; +method.PVM_TaggingDeriveGainMode = ''; +method.PVM_TaggingMode = ''; +method.PVM_TaggingDir = ''; +method.PVM_TaggingDistance = []; +method.PVM_TaggingMinDistance = []; +method.PVM_TaggingThick = []; +method.PVM_TaggingOffset1 = []; +method.PVM_TaggingOffset2 = []; +method.PVM_TaggingAngle = []; +method.PVM_TaggingDelay = []; +method.PVM_TaggingModuleTime = []; +method.PVM_TaggingPulseNumber = []; +method.PVM_TaggingPulseElement = []; +method.PVM_TaggingGradientStrength = []; +method.PVM_TaggingSpoilGrad = []; +method.PVM_TaggingSpoilDuration = []; +method.PVM_TaggingGridDelay = []; +method.PVM_TaggingD0 = []; +method.PVM_TaggingD1 = []; +method.PVM_TaggingD2 = []; +method.PVM_TaggingD3 = []; +method.PVM_TaggingD4 = []; +method.PVM_TaggingD5 = []; +method.PVM_TaggingP0 = []; +method.PVM_TaggingLp0 = []; +method.PVM_TaggingGradAmp1= []; +method.PVM_TaggingGradAmp2= []; +method.PVM_TaggingGradAmp3= []; +method.PVM_TaggingGradAmp4= []; +method.PVM_TaggingSpoiler = []; +method.PVM_FatSupOnOff = ''; +method.PVM_MagTransOnOff = ''; +method.PVM_FovSatOnOff = ''; +method.PVM_FovSatNSlices = []; +method.PVM_FovSatSliceOrient = ''; +method.PVM_FovSatThick = []; +method.PVM_FovSatOffset = []; +method.PVM_FovSatSliceVec = []; +method.PVM_SatSlicesPulseEnum = ''; +method.PVM_SatSlicesPulse = ''; +method.PVM_SatSlicesDeriveGainMode = ''; +method.PVM_FovSatGrad = []; +method.PVM_FovSatSpoilTime = []; +method.PVM_FovSatSpoilGrad = []; +method.PVM_FovSatModuleTime = []; +method.PVM_FovSatFL = []; +method.PVM_SatD0 = []; +method.PVM_SatD1 = []; +method.PVM_SatD2 = []; +method.PVM_SatP0 = []; +method.PVM_SatLp0 = []; +method.PVM_TriggerOutOnOff = ''; +method.PVM_TriggerOutMode = ''; +method.PVM_TriggerOutDelay = []; +method.PVM_TrigOutD0 = []; +method.PVM_PreemphasisSpecial = ''; +method.PVM_PreemphasisFileEnum = ''; +method.PVM_EchoTime1 = []; +method.PVM_EchoTime2 = []; +method.PVM_EchoTime = []; +method.PVM_NEchoImages = []; + +% for MDEFT +method.EchoRepTime = []; +method.SegmRepTime = []; +method.SegmDuration = []; +method.SegmNumber = []; +method.PVM_InversionTime = []; +method.PVM_EchoPosition = []; +method.SequenceOptimizationMode = ''; +method.EchoPad = []; +method.RFSpoilerOnOff = ''; +method.SpoilerDuration = []; +method.SpoilerStrength = []; +method.NDummyEchoes = []; +method.Mdeft_PreparationMode = ''; +method.Mdeft_ExcPulseEnum = ''; +method.Mdeft_ExcPulse = ''; +method.Mdeft_InvPulseEnum = ''; +method.Mdeft_InvPulse = ''; +method.Mdeft_PrepDeriveGainMode = ''; +method.Mdeft_PrepSpoilTime = []; +method.Mdeft_PrepMinSpoilTime = []; +method.Mdeft_PrepSpoilGrad = []; +method.Mdeft_PrepModuleTime = []; +method.PVM_ppgMode1 = []; +method.PVM_ppgFreqList1Size = []; +method.PVM_ppgFreqList1 = []; +method.PVM_ppgGradAmp1 = []; + +% for RARE +method.EffectiveTE = []; +method.PVM_RareFactor = []; +method.PVM_SliceBandWidthScale = []; +method.PVM_ReadDephaseTime = []; +method.PVM_2dPhaseGradientTime = []; +method.PVM_EvolutionOnOff = ''; +method.PVM_SelIrOnOff = ''; +method.PVM_FatSupprPulseEnum = ''; +method.PVM_FatSupprPulse = ''; +method.PVM_FatSupDeriveGainMode = ''; +method.PVM_FatSupBandWidth = []; +method.PVM_FatSupSpoilTime = []; +method.PVM_FatSupSpoilGrad = []; +method.PVM_FatSupModuleTime = []; +method.PVM_FatSupFL = []; +method.PVM_FsD0 = []; +method.PVM_FsD1 = []; +method.PVM_FsD2 = []; +method.PVM_FsP0 = []; +method.PVM_InFlowSatOnOff = ''; +method.PVM_InFlowSatNSlices = []; +method.PVM_InFlowSatThick = []; +method.PVM_InFlowSatGap = []; +method.PVM_InFlowSatSide = []; +method.PVM_FlowSatPulse = ''; +method.PVM_FlowSatDeriveGainMode= ''; +method.PVM_InFlowSatSpoilTime = []; +method.PVM_InFlowSatSpoilGrad = []; +method.PVM_InFlowSatModuleTime = []; +method.PVM_SfD0 = []; +method.PVM_SfD1 = []; +method.PVM_SfD2 = []; +method.PVM_SfP0 = []; +method.PVM_SfLp0 = []; +method.PVM_MotionSupOnOff = ''; +method.PVM_FlipBackOnOff = ''; + +% for FLASH +method.PVM_MotionSupOnOff = ''; +method.EchoTimeMode = ''; +method.ReadSpoilerDuration = []; +method.ReadSpoilerStrength = []; +method.PVM_MovieOnOff = ''; +method.PVM_NMovieFrames = []; +method.TimeForMovieFrames = []; +method.PVM_BlBloodOnOff = ''; +method.PVM_ppgFlag1 = ''; + +% new parameters +method.RECO_wordtype = ''; +method.RECO_map_mode = ''; +method.RECO_map_percentile = []; +method.RECO_map_error = []; +method.RECO_map_range = []; + + + +% GET "method" VALUES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +for N = 1:length(texts), + if strncmpi(texts{N},'##$',3), + % get the parameter name + idx = strfind(texts{N},'='); + tmpname = texts{N}(4:idx-1); + % get the value(s) + if isempty(strfind(texts{N},'=(')), + tmpval = texts{N}(idx+1:end); + tmpdim = []; + else + s1 = strfind(texts{N},'('); + s2 = strfind(texts{N},')'); + if isempty(s2), + tmpdim = []; + tmpval = texts{N}(s1:end); + else + % get dimension + tmpdim = str2num(texts{N}(s1+1:s2-1)); + tmpval = ''; + end + K = N; + while ~strncmpi(texts{K+1},'##',2), + K = K + 1; + end + % USE sprintf() since strcat remove blank... + if isempty(tmpdim), + tmpval = sprintf('%s',tmpval,texts{N+1:K}); + else + tmpval = sprintf('%s ',tmpval,texts{N+1:K}); + end + %tmpval = strcat(texts{N+1:K}); + N = K + 1; + end + + % WHY?? THIS HAPPENS + idx = strfind(tmpval,'$$'); + if ~isempty(idx), tmpval = tmpval(1:idx-1); end + + % set the value(s) + tmpval = strtrim(tmpval); + if isfield(method,tmpname), + if ischar(method.(tmpname)), + if any(tmpdim) && tmpval(1) ~= '<', + method.(tmpname) = subStr2CellStr(tmpval,tmpdim); + else + method.(tmpname) = tmpval; + end + elseif isnumeric(method.(tmpname)), + method.(tmpname) = str2num(tmpval); + if length(tmpdim) > 1 & prod(tmpdim) == numel(method.(tmpname)), + method.(tmpname) = reshape(method.(tmpname),fliplr(tmpdim)); + method.(tmpname) = permute(method.(tmpname),length(tmpdim):-1:1); + end + else + method.(tmpname) = tmpval; + end + else + method.(tmpname) = tmpval; + end + end +end + +% after care of some parameters.... +%method.xxxx = subStr2CellStr(method.xxxx); + + +% remove empty members +fields = fieldnames(method); +IDX = zeros(1,length(fields)); +for N = 1:length(fields), IDX(N) = isempty(method.(fields{N})); end +method = rmfield(method,fields(find(IDX))); + + + + +% SET OUTPUTS, IF REQUIRED %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if nargout, + varargout{1} = method; + if nargout > 1, + varargout{2} = texts; + end +end + +return; + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCITON to make a cell string from a 'space' or '()' separeted string +function val = subStr2CellStr(str,dim) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if isempty(str) || iscell(str), + val = str; + return; +end + +if nargin < 2, dim = []; end + +val = {}; + +if str(1) == '(', + idx1 = strfind(str,'('); + idx2 = strfind(str,')'); + for N = 1:length(idx1), + val{N} = strtrim(str(idx1(N)+1:idx2(N)-1)); + end +else + % 'space' separated + [token, rem] = strtok(str,' '); + while ~isempty(token), + val{end+1} = token; + [token, rem] = strtok(rem,' '); + end +end + +if length(dim) > 1 && prod(dim) > 0, + val = reshape(val,dim); +end + +return; + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCITON to make a cell matrix from a '()' separeted string +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function val = subStr2CellNum(str) +if isempty(str), + val = str; + return; +end + +idx1 = strfind(str,'('); +idx2 = strfind(str,')'); + +val = {}; +for N = 1:length(idx1), + val{N} = str2num(str(idx1(N)+1:idx2(N)-1)); +end + +return; diff --git a/mpi_code/pvread/pvread_reco.m b/mpi_code/pvread/pvread_reco.m new file mode 100644 index 0000000..3632678 --- /dev/null +++ b/mpi_code/pvread/pvread_reco.m @@ -0,0 +1,311 @@ +function varargout = pvread_reco(varargin) +%PVREAD_RECO - Read PraVision "reco". +% RECO = PVREAD_RECO(RECOFILE,...) +% RECO = PVREAD_RECO(2DSEQFILE,...) +% RECO = PVREAD_RECO(SESSION,EXPNO,...) reads ParaVision's "reco" and returns +% its contents as a structre, RECO. +% Unknown parameter will be returned as a string. +% +% Supported options are +% 'verbose' : 0|1, verbose or not. +% +% VERSION : +% 0.90 13.06.05 YM pre-release +% 0.91 27.02.07 YM supports also 2dseq as the first argument +% 0.92 26.03.08 YM returns empty data if file not found. +% 0.93 18.09.08 YM supports both new csession and old getses. +% 0.94 15.01.09 YM supports some new parameters. +% +% See also pv_imgpar pvread_2dseq pvread_acqp pvread_imnd pvread_method pvread_visu_pars + +if nargin == 0, help pvread_reco; return; end + + +if ischar(varargin{1}) & ~isempty(strfind(varargin{1},'reco')), + % Called like pvread_reco(RECOFILE) + RECOFILE = varargin{1}; + ivar = 2; +elseif ischar(varargin{1}) & ~isempty(strfind(varargin{1},'2dseq')), + % Called like pvread_reco(2DSEQFILE) + RECOFILE = fullfile(fileparts(varargin{1}),'reco'); + ivar = 2; +else + % Called like pvread_reco(SESSION,ExpNo) + if exist('csession','class'), + ses = csession(varargin{1}); + RECOFILE = ses.filename(varargin{2},'reco'); + else + ses = goto(varargin{1}); + RECOFILE = catfilename(ses,varargin{2},'reco'); + end + ivar = 3; +end + + +% SET OPTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +VERBOSE = 1; +for N = ivar:2:nargin, + switch lower(varargin{N}), + case {'verbose'} + VERBOSE = varargin{N+1}; + end +end + + +if ~exist(RECOFILE,'file'), + if VERBOSE, + fprintf(' ERROR %s: ''%s'' not found.\n',mfilename,RECOFILE); + end + % SET OUTPUTS, IF REQUIRED %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + if nargout, + varargout{1} = []; + if nargout > 1, varargout{2} = {}; end + end + return; +end + + +% READ TEXT LINES OF "RECO" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +texts = {}; +fid = fopen(RECOFILE,'rt'); +while ~feof(fid), + texts{end+1} = fgetl(fid); + %texts{end+1} = fgets(fid); +end +fclose(fid); + + + +% MAKE "reco" structure %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +reco.filename = RECOFILE; + +reco.RECO_mode = ''; +reco.RECO_inp_order = ''; +reco.RECO_inp_size = []; +reco.RECO_ft_size = []; +reco.RECO_fov = []; +reco.RECO_size = []; +reco.RECO_offset = []; +reco.RECO_regrid_mode = ''; +reco.RECO_regrid_offset = []; +reco.RECO_ramp_gap = []; +reco.RECO_ramp_time = []; +reco.RECO_ne_mode = ''; +reco.RECO_ne_dist = ''; +reco.RECO_ne_dens = ''; +reco.RECO_ne_type = ''; +reco.RECO_ne_vals = []; +reco.RECO_bc_mode = ''; +reco.RECO_bc_start = []; +reco.RECO_bc_len = []; +reco.RECO_dc_offset = []; +reco.RECO_dc_divisor = []; +reco.RECO_bc_coroff = []; +reco.RECO_qopts = ''; +reco.RECO_wdw_mode = ''; +reco.RECO_lb = []; +reco.RECO_sw = []; +reco.RECO_gb = []; +reco.RECO_sbs = []; +reco.RECO_tm1 = []; +reco.RECO_tm2 = []; +reco.RECO_ft_mode = ''; +reco.RECO_pc_mode = ''; +reco.RECO_pc_lin = {}; +reco.RECO_rotate = []; +reco.RECO_ppc_mode = ''; +reco.RECO_ref_image = []; +reco.RECO_nr_supports = []; +reco.RECO_sig_threshold = []; +reco.RECO_ppc_degree = []; +reco.RECO_ppc_coeffs = []; +reco.RECO_dc_elim = ''; +reco.RECO_transposition = []; +reco.RECO_image_type = ''; +reco.RECO_image_threshold = []; +reco.RECO_ir_scale = []; +reco.RECO_wordtype = ''; +reco.RECO_map_mode = ''; +reco.RECO_map_range = []; +reco.RECO_map_percentile = []; +reco.RECO_map_error = []; +reco.RECO_globex = []; +reco.RECO_minima = []; +reco.RECO_maxima = []; +reco.RECO_map_min = []; +reco.RECO_map_max = []; +reco.RECO_map_offset = []; +reco.RECO_map_slope = []; +reco.RECO_byte_order = ''; +reco.RECO_time = ''; +reco.RECO_abs_time = []; +reco.RECO_base_image_uid = ''; +reco.GS_reco_display = ''; +reco.GS_image_type = ''; +reco.GO_reco_display = ''; +reco.GO_reco_each_nr = ''; +reco.GO_max_reco_mem = []; + +% new parameters +reco.RecoUserUpdate = ''; +reco.RecoNumInputChan = []; +reco.RecoScaleChan = []; +reco.RecoCombineMode = ''; +reco.RecoSortDim = []; +reco.RecoSortSize = []; +reco.RecoSortRange = []; +reco.RecoSortSegment = []; +reco.RecoSortMaps = []; +reco.RecoGrappaAccelFactor = []; +reco.RecoGrappaKernelRead = []; +reco.RecoGrappaKernelPhase = []; +reco.RecoGrappaNumRefRead = []; +reco.RecoGrappaNumRefPhase = []; +reco.RecoGrappaIncludeRefLines = ''; +reco.RecoGrappaReadCenter = []; +reco.RecoGrappaPhaseCenter = []; +reco.RecoGrappaTruncThresh = []; + + + + +% GET "reco" VALUES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +for N = 1:length(texts), + if strncmpi(texts{N},'##$',3), + % get the parameter name + idx = strfind(texts{N},'='); + tmpname = texts{N}(4:idx-1); + % get the value(s) + if isempty(strfind(texts{N},'=(')), + tmpval = texts{N}(idx+1:end); + tmpdim = []; + else + s1 = strfind(texts{N},'('); + s2 = strfind(texts{N},')'); + if isempty(s2), + tmpdim = []; + tmpval = texts{N}(s1:end); + else + % get dimension + tmpdim = str2num(texts{N}(s1+1:s2-1)); + tmpval = ''; + end + K = N; + while ~strncmpi(texts{K+1},'##',2), + K = K + 1; + end + % USE sprintf() since strcat remove blank... + if isempty(tmpdim), + tmpval = sprintf('%s',tmpval,texts{N+1:K}); + else + tmpval = sprintf('%s ',tmpval,texts{N+1:K}); + end + %tmpval = strcat(texts{N+1:K}); + N = K + 1; + end + + % WHY?? THIS HAPPENS + idx = strfind(tmpval,'$$'); + if ~isempty(idx), tmpval = tmpval(1:idx-1); end + + % set the value(s) + tmpval = strtrim(tmpval); + if isfield(reco,tmpname), + if ischar(reco.(tmpname)), + if any(tmpdim) && tmpval(1) ~= '<', + reco.(tmpname) = subStr2CellStr(tmpval,tmpdim); + else + reco.(tmpname) = tmpval; + end + elseif isnumeric(reco.(tmpname)), + reco.(tmpname) = str2num(tmpval); + if length(tmpdim) > 1 & prod(tmpdim) == numel(reco.(tmpname)), + reco.(tmpname) = reshape(reco.(tmpname),fliplr(tmpdim)); + reco.(tmpname) = permute(reco.(tmpname),length(tmpdim):-1:1); + end + else + reco.(tmpname) = tmpval; + end + else + reco.(tmpname) = tmpval; + end + end +end + +% after care of some parameters.... +reco.RECO_pc_lin = subStr2CellNum(reco.RECO_pc_lin); + +% remove empty members +fields = fieldnames(reco); +IDX = zeros(1,length(fields)); +for N = 1:length(fields), IDX(N) = isempty(reco.(fields{N})); end +reco = rmfield(reco,fields(find(IDX))); + + +% SET OUTPUTS, IF REQUIRED %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if nargout, + varargout{1} = reco; + if nargout > 1, + varargout{2} = texts; + end +end + +return; + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCITON to make a cell string from a 'space' or '()' separeted string +function val = subStr2CellStr(str,dim) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if isempty(str) || iscell(str), + val = str; + return; +end + +if nargin < 2, dim = []; end + +val = {}; + +if str(1) == '(', + idx1 = strfind(str,'('); + idx2 = strfind(str,')'); + for N = 1:length(idx1), + val{N} = strtrim(str(idx1(N)+1:idx2(N)-1)); + end +else + % 'space' separated + [token, rem] = strtok(str,' '); + while ~isempty(token), + val{end+1} = token; + [token, rem] = strtok(rem,' '); + end +end + +if length(dim) > 1 && prod(dim) > 0, + val = reshape(val,dim); +end + +return; + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCITON to make a cell matrix from a '()' separeted string +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function val = subStr2CellNum(str) +if isempty(str), + val = str; + return; +end + +idx1 = strfind(str,'('); +idx2 = strfind(str,')'); + +val = {}; +for N = 1:length(idx1), + val{N} = str2num(str(idx1(N)+1:idx2(N)-1)); +end + +return; diff --git a/mpi_code/pvread/pvread_visu_pars.m b/mpi_code/pvread/pvread_visu_pars.m new file mode 100644 index 0000000..6b0c9a3 --- /dev/null +++ b/mpi_code/pvread/pvread_visu_pars.m @@ -0,0 +1,290 @@ +function varargout = pvread_visu_pars(varargin) +%PVREAD_VISU_PARS - Read ParaVision "visu_pars". +% VISUPARS = PVREAD_VISU_PARS(VISUPARSFILE,...) +% VISUPARS = PVREAD_VISU_PARS(2DSEQFILE,...) +% VISUPARS = PVREAD_VISU_PARS(SESSION,EXPNO,...) reads ParaVision's "visu_pars" and +% returns its contents as a structre, VISUPARS. +% Unknown parameter will be returned as a string. +% +% Supported options are +% 'verbose' : 0|1, verbose or not. +% +% VERSION : +% 0.90 16.04.08 YM pre-release, checked epi/mdeft/rare/flash of 7T. +% 0.91 18.09.08 YM supports both new csession and old getses. +% +% See also pv_imgpar pvread_2dseq pvread_acqp pvread_imnd pvread_method pvread_reco + +if nargin == 0, help pvread_visu_pars; return; end + + +if ischar(varargin{1}) & ~isempty(strfind(varargin{1},'visu_pars')), + % Called like pvread_visu_pars(VISUFILE) + VISUFILE = varargin{1}; + ivar = 2; +elseif ischar(varargin{1}) & ~isempty(strfind(varargin{1},'2dseq')), + % Called like pvread_visu_pars(2DSEQFILE) + VISUFILE = fullfile(fileparts(varargin{1}),'visu_pars'); + ivar = 2; +else + % Called like pvread_visu_pars(SESSION,ExpNo) + if nargin < 2, + error(' ERROR %s: missing 2nd arg. as ExpNo.\n',mfilename); + return; + end + if exist('csession','class'), + ses = csession(varargin{1}); + VISUFILE = ses.filename(varargin{2},'visu_pars'); + else + ses = goto(varargin{1}); + VISUFILE = catfilename(ses,varargin{2},'visu_pars'); + end + ivar = 3; +end + + +% SET OPTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +VERBOSE = 1; +for N = ivar:2:nargin, + switch lower(varargin{N}), + case {'verbose'} + VERBOSE = varargin{N+1}; + end +end + + +if ~exist(VISUFILE,'file'), + if VERBOSE, + fprintf(' ERROR %s: ''%s'' not found.\n',mfilename,VISUFILE); + end + % SET OUTPUTS, IF REQUIRED %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + if nargout, + varargout{1} = []; + if nargout > 1, varargout{2} = {}; end + end + return; +end + + +% READ TEXT LINES OF "VISU_PARS" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +texts = {}; +fid = fopen(VISUFILE,'rt'); +while ~feof(fid), + texts{end+1} = fgetl(fid); + %texts{end+1} = fgets(fid); +end +fclose(fid); + + + +% MAKE "visu" structure %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +visu.filename = VISUFILE; + +visu.VisuVersion = []; +visu.isuUid = ''; +visu.VisuCreator = ''; +visu.VisuCreatorVersion = ''; +visu.VisuCreationDate = ''; +visu.VisuCoreFrameCount = []; +visu.VisuCoreDim = []; +visu.VisuCoreSize = []; +visu.VisuCoreDimDesc = ''; +visu.VisuCoreExtent = []; +visu.VisuCoreFrameThickness = []; +visu.VisuCoreUnits = ''; +visu.VisuCoreOrientation = []; +visu.VisuCorePosition = []; +visu.VisuCoreDataMin = []; +visu.VisuCoreDataMax = []; +visu.VisuCoreDataOffs = []; +visu.VisuCoreDataSlope = []; +visu.VisuCoreFrameType = ''; +visu.VisuCoreWordType = ''; +visu.VisuCoreByteOrder = ''; +visu.VisuFGOrderDescDim = []; +visu.VisuFGOrderDesc = ''; +visu.VisuGroupDepVals = ''; +visu.VisuSubjectName = ''; +visu.VisuSubjectId = ''; +visu.VisuSubjectBirthDate = ''; +visu.VisuSubjectSex = ''; +visu.VisuSubjectComment = ''; +visu.VisuStudyUid = ''; +visu.VisuStudyDate = ''; +visu.VisuStudyId = ''; +visu.VisuStudyNumber = []; +visu.VisuSubjectWeight = []; +visu.VisuStudyReferringPhysician = ''; +visu.VisuStudyDescription = ''; +visu.VisuSeriesNumber = []; +visu.VisuSubjectPosition = ''; +visu.VisuSeriesTypeId = ''; +visu.VisuAcqSoftwareVersion = []; +visu.VisuInstitution = ''; +visu.VisuStation = ''; +visu.VisuAcqDate = ''; +visu.VisuAcqEchoTrainLength = []; +visu.VisuAcqSequenceName = ''; +visu.VisuAcqNumberOfAverages = []; +visu.VisuAcqImagingFrequency = []; +visu.VisuAcqImagedNucleus = ''; +visu.VisuAcqRepetitionTime = []; +visu.VisuAcqPhaseEncSteps = []; +visu.VisuAcqPixelBandwidth = []; +visu.VisuAcqFlipAngle = []; +visu.VisuAcqSize = []; +visu.VisuAcqImageSizeAccellerated = ''; +visu.VisuAcqImagePhaseEncDir = ''; +visu.VisuAcqEchoTime = []; +visu.VisuAcquisitionProtocol = ''; +visu.VisuAcqScanTime = []; + +% for MDEFT +visu.VisuCoreDiskSliceOrder = ''; +visu.VisuAcqInversionTime = []; + + + + +% GET "visu_pars" VALUES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +for N = 1:length(texts), + if strncmpi(texts{N},'##$',3), + % get the parameter name + idx = strfind(texts{N},'='); + tmpname = texts{N}(4:idx-1); + % get the value(s) + if isempty(strfind(texts{N},'=(')), + tmpval = texts{N}(idx+1:end); + tmpdim = []; + else + s1 = strfind(texts{N},'('); + s2 = strfind(texts{N},')'); + if isempty(s2), + tmpdim = []; + tmpval = texts{N}(s1:end); + else + % get dimension + tmpdim = str2num(texts{N}(s1+1:s2-1)); + tmpval = ''; + end + K = N; + while ~strncmpi(texts{K+1},'##',2), + K = K + 1; + end + % USE sprintf() since strcat remove blank... + if isempty(tmpdim), + tmpval = sprintf('%s',tmpval,texts{N+1:K}); + else + tmpval = sprintf('%s ',tmpval,texts{N+1:K}); + end + %tmpval = strcat(texts{N+1:K}); + N = K + 1; + end + + % WHY?? THIS HAPPENS + idx = strfind(tmpval,'$$'); + if ~isempty(idx), tmpval = tmpval(1:idx-1); end + + % set the value(s) + tmpval = strtrim(tmpval); + if isfield(visu,tmpname), + if ischar(visu.(tmpname)), + if any(tmpdim) && tmpval(1) ~= '<', + visu.(tmpname) = subStr2CellStr(tmpval,tmpdim); + else + visu.(tmpname) = tmpval; + end + elseif isnumeric(visu.(tmpname)), + visu.(tmpname) = str2num(tmpval); + if length(tmpdim) > 1 & prod(tmpdim) == numel(visu.(tmpname)), + visu.(tmpname) = reshape(visu.(tmpname),fliplr(tmpdim)); + visu.(tmpname) = permute(visu.(tmpname),length(tmpdim):-1:1); + end + else + visu.(tmpname) = tmpval; + end + else + visu.(tmpname) = tmpval; + end + end +end + +% after care of some parameters.... +%visu.xxxx = subStr2CellNum(visu.xxxx); + +% remove empty members +fields = fieldnames(visu); +IDX = zeros(1,length(fields)); +for N = 1:length(fields), IDX(N) = isempty(visu.(fields{N})); end +visu = rmfield(visu,fields(find(IDX))); + + + + +% SET OUTPUTS, IF REQUIRED %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if nargout, + varargout{1} = visu; + if nargout > 1, + varargout{2} = texts; + end +end + +return; + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCITON to make a cell string from a 'space' or '()' separeted string +function val = subStr2CellStr(str,dim) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if isempty(str) || iscell(str), + val = str; + return; +end + +if nargin < 2, dim = []; end + +val = {}; + +if str(1) == '(', + idx1 = strfind(str,'('); + idx2 = strfind(str,')'); + for N = 1:length(idx1), + val{N} = strtrim(str(idx1(N)+1:idx2(N)-1)); + end +else + % 'space' separated + [token, rem] = strtok(str,' '); + while ~isempty(token), + val{end+1} = token; + [token, rem] = strtok(rem,' '); + end +end + +if length(dim) > 1 && prod(dim) > 0, + val = reshape(val,dim); +end + +return; + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SUBFUNCITON to make a cell matrix from a '()' separeted string +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function val = subStr2CellNum(str) +if isempty(str), + val = str; + return; +end + +idx1 = strfind(str,'('); +idx2 = strfind(str,')'); + +val = {}; +for N = 1:length(idx1), + val{N} = str2num(str(idx1(N)+1:idx2(N)-1)); +end + +return; diff --git a/mpi_code/readme.txt b/mpi_code/readme.txt new file mode 100644 index 0000000..906a62b --- /dev/null +++ b/mpi_code/readme.txt @@ -0,0 +1,10 @@ +put the folder mex_anz in your matlab path and use: + +bru2analyze to convert the raw data (bruker 2dseq) to analyze + +see help function of bru2analyze on how to use it. + +the 2dseq files are in the: session_directory/scan number/pdata/n + +where n usually equals 1 and represents the reconstruction number +rarely there will be a second reconstruction with different parameters \ No newline at end of file diff --git a/nhpMpiBrukerBuildAnalyze.m b/nhpMpiBrukerBuildAnalyze.m new file mode 100644 index 0000000..371b138 --- /dev/null +++ b/nhpMpiBrukerBuildAnalyze.m @@ -0,0 +1,35 @@ +function savedir = nhpMpiBrukerBuildAnalyze(scans,baseDir,saveDir) +% +% Reconstruct one Bruker/MPI scan at the time. Saves an analyze file. +% This is a wrapper around the MPI bru2analyze.m +% +% INPUTS: +% scans - A vector of scan indexes (1:n). These indexes refer to the +% folders under baseDir/nhpDir. +% baseDir - This is the base directory where all the MPI data set reside, +% currently /azure/scr1/frk/nhp/ +% saveDir - This is the folder where the analyze files will be saved. +% +% OUTPUTS +% savedir - Full-path to analyze file. +% +% Franco (c) Stanford Vista Team 2012 + + +% Loop over the scans for the current subject and save out an analyze file. +for fi = length(scans) % Scan types + twodseqFile = fullfile(baseDir,sprintf('%i',scans(fi)),'/pdata/1/2dseq'); + + % Preprocess the Bruker scan only if it exists. + if exist(twodseqFile,'file') + % make a directory to save the ANALYZE file + savedir = fullfile(baseDir,saveDir,sprintf('scan00%i',scans(fi))); + if ~isdir(savedir), mkdir(savedir); end + + fprintf('\n[%s] Saving analyze files: /*.hdr & *.img\n%s\n',mfilename, savedir); + bru2analyze(twodseqFile, 'SaveDir',savedir); + end +end + +if nargout < 1, clear savedir;end +end \ No newline at end of file diff --git a/nhpMpiBrukerBuildDiffusionGradients.m b/nhpMpiBrukerBuildDiffusionGradients.m new file mode 100644 index 0000000..13f8f33 --- /dev/null +++ b/nhpMpiBrukerBuildDiffusionGradients.m @@ -0,0 +1,117 @@ +function [bvecs,bvals,dw] = nhpMpiBrukerBuildDiffusionGradients(method_fname) +% +% Read the 'method' file from a the MPI Bruker scanner and build diffusion +% gradients informatation (bvecs and bvals). +% +% [bvecs,bvals,dw] = nhpMpiBrukerBuildDiffusionGradients(method_fname) +% +% INPUTS: +% method_fname - the full path to a bruker 'method' file. +% +% OUTPUTS: +% bvecs - 3xnBvecs vecotr containing the bvecs as expected by mrDiffusion. +% +% bvals - 1xNbvecs vector of bvals, as epxceted by mrDiffusion +% +% dw - a structure containing all the information rearding gradient +% direction and bvals. +% +% See: http://filer.case.edu/vxs33/pvman/A/Docs/A06_MethDescr.pdf +% http://filer.case.edu/vxs33/pvman/D/Docs/A13_MethProg.pdf +% +% Notes: +% In an email Georgios A. Keliris he gave us the following +% information regaridng the MPI-Bruker scan sequences: +% - z (3rd dimension) in the image refers to the main filed (b0) +% - The NHP head is positioned as follows: +% z=H-F | x=A-P | y=R-L +% - Gradeitns are most certainly stored as consecutie triplets: +% [[x1,y,1z1],[x2,y2,z2],...,[xn,yn,zn]] +% - Grdients are always normalized (PVM_DwDirectScale='yes') +% - B0 and diffusion data are stored in the files as follows: +% GAK: Based on the image (2dseg file). First volume respectively frame +% 1 to Slices is B0 and Slices+1 to 2xSlices is the diffusion image. +% Example: Study: M00.yO1, Scan 20, frame 1 to 48 is B0 and frame 49 +% to 96 is diffusion image. +% +% Franco (c) Stanford Vista Team 2012 + +dw.bvals = [];dw.bvecs = []; + +% Read the method file +mth = pvread_method(method_fname); + +% Check that this was a Diffusion scan: +if ~strcmpi(mth.Method,'DtiEpi') + error('[%s] This scan does not seem to be a DW scan.\n[PVM_DwMeasMode: %s].',mafilename,mth.PVM_DwMeasMode); +end + +% Check whether the diffusion directions vectors are normalized to norm = 1.0 +if ~strcmpi(mth.PVM_DwDirectScale,'no') + warning('[%s] The diffusion directions were not set to be normalized to 1.\nThe resulting bvecs might be wrong.',mafilename); +end + +% Number of average DW measurements +dw.nAverages = mth.PVM_DwNDiffExpEach; + +% Get the number of diffusion directions acquired. +dw.nBvecs = str2double( mth.PVM_DwNDiffDir ); + +% Get the number of bvals acquired: +dw.nBvals = str2double( mth.PVM_DwAoImages ); + +% Get the bvalue sued for this scan +dw.bval = str2double( mth.PVM_DwBvalEach ); + +% No bulld the bvals +dw.bvals =repmat(dw.bval,dw.nBvals,3); + +% The indices of the b0 measuements in the DWI data file can be figured out +% from the list of phases of the gradients. THe b0 measurements have +% 0-phase (I think). +dw.indicesb0 = find(str2num(mth.PVM_DwGradPhase) == 0); +dw.indices = find(str2num(mth.PVM_DwGradPhase)); + +% The diffusion directions on a DW sequence on a bruker scanner are stroed +% in the struct variable: 'PVM_DwDir' +dw.bvecs = str2num(mth.PVM_DwDir); +dw.bvecs = reshape(dw.bvecs,3,dw.nBvecs)'; + +% Check that the vectors are unit length. +% If we organized the vectors corretly the dot product of the vector in the +% rows of bvecs with itself should be 1. +% This is valid onlyin the case in which 'PVM_DwDirectScale='no'. See +% above. +if ~all(round(dot(dw.bvecs,dw.bvecs,2)) == 1), keyboard; end + +% Concatenate the bvecs and set the gradients for the bvals to zero +bvecs = zeros(3,size(dw.bvecs,1) + size(dw.bvals,1)); +bvecs(:,dw.indices) = dw.bvecs'; +% gradients (bvecs) are aligned in scanner space. Here we use the xform of +% the nifti to reorient them in image space: +% +% xfrom from scanner to image space +%xform = ni.qto_xyz; +% +% X-form the bvecs +%bvecs2 = xform*bvecs'; +bvecNorm = sqrt(sum(bvecs.^2)); +nz = bvecNorm~=0; +bvecs(:,nz) = bvecs(:,nz)./repmat(bvecNorm(nz),[3 1]); + +bvals = zeros(size(dw.bvecs,1) + size(dw.bvals,1),1); +if (dw.bval > 10), divideby = 1000; +else divideby = 1;end +bvals(dw.indices) = dw.bval/divideby; +bvals = bvals'; + +% Save out mrDiffusion bevecs/bvals files +% +% Scale the bvalues according to gradient magnitude. This assumes that the +% specified b-value is the max bvalue. Note that we only do this when all +% the bvec norms are 1 or less. If any of the bvec norms are >1, then we +% assume that the bvecs are just encoded sloppily and their norms do not +% really reflect the gradient amplitudes. +if( all(bvecNorm<=1) ), bvals = bvals.*bvecNorm.^2; end + +return diff --git a/nhpMpiBuildNiftiFromAnalyze.m b/nhpMpiBuildNiftiFromAnalyze.m new file mode 100644 index 0000000..09c6d5b --- /dev/null +++ b/nhpMpiBuildNiftiFromAnalyze.m @@ -0,0 +1,52 @@ +function [fname,p, ni] = nhpMpiBuildNiftiFromAnalyze(analyzeFile,nFiles) +% +% Build a 3D nifti file from the individual analyze files +% +% analyzeFile = fullfile(baseDir,nhpDir,'analyze','scan0040','M00EM1_scan40_00001.img') +% + +% Extract the path informatin from the analyzeFile. +[p,fname] = fileparts(analyzeFile); + +% We rebuild the file name as a string +fname = fname(1:14); + +% Load the first of many files +% We will use this as a template for the ehader information. +if exist(analyzeFile,'file') + ni = niftiRead(analyzeFile); +else + keyboard +end + + +% We open on file at the time +sz3d = size(ni.data); +ni.data = nan(sz3d(1),sz3d(2),sz3d(3),nFiles); +c=1; +for fi = 1:nFiles + if fi < 10 + thisfile = fullfile(p,sprintf('%s0000%i.hdr',fname,fi)); + else + thisfile = fullfile(p,sprintf('%s000%i.hdr',fname,fi)); + end + fprintf('Loading file: %s\n',thisfile) + ni_temp = niftiRead(thisfile); + % We append the data into the first opened file + ni.data(:,:,:,c) = ni_temp.data; + c = c +1; +end + +% We update the header information +% Notice, the headers in the analyze files do not have the corect center. +% Build that here. +fname = sprintf('%snA%i.nii.gz',fname,nFiles); +ni.fname = fname; +ni.dim = size(ni.data); +ni.qform_code = 1; % the qto_* fields contain the xForm information +ni.slice_dim = 3; +ni.phase_dim = 2; +ni.freq_dim = 1; +ni.slice_start=0; +ni.slice_end =size(ni.data,3)-1; +end diff --git a/nhpMpiDwiRootPath.m b/nhpMpiDwiRootPath.m new file mode 100644 index 0000000..a7a3435 --- /dev/null +++ b/nhpMpiDwiRootPath.m @@ -0,0 +1,26 @@ +function rootPath = nhpMpiDwiRootPath(dataDir) +% Determine path to root of the NHP MPI code set. +% +% rootPath = nhpMpiDwiRootPath; +% +% INPUTS: +% dataDir - Logical. +% - 1, returns the path to the data dir which is: +% '/biac2/wandell2/data/diffusion/nhp' +% - 0, returns the path to the code base which lives in +% vistaproj/mpi_nhp. Default is 0. +% +% This function MUST reside in the directory at the base of the nhpMpiDwi +% directory structure +% +% Franco & Hiromasa (c) Stanford Vista Team 2012 +if notDefined('dataDir'), dataDir = 0;end + +if ~dataDir % Return path to code set +rootPath = which('nhpMpiDwiRootPath'); +rootPath = fileparts(rootPath); +else + rootPath = '/biac2/wandell2/data/diffusion/nhp/'; +end + +return diff --git a/nhpMpiSwapDimensions.m b/nhpMpiSwapDimensions.m new file mode 100644 index 0000000..598ea91 --- /dev/null +++ b/nhpMpiSwapDimensions.m @@ -0,0 +1,29 @@ +function ni = nhpMpiSwapDimensions(ni,swapType) +% +% Sawp the dimensions of the nifti file created by loading a series of +% analzuse fiels from the rbuker scanner. +% +% ni = nhpMpiSwapDimensions(ni,swapType) +% +% This might not be used. Still work in progress. +% +% Franco (c) Stanford Vista Team 2012 + +switch swapType + case 'x' + case 'y' + [ni.data] = applyCannonicalXform(ni.data, img2std, ni.pixdim, insertMarkerFlag); + case 'z' + ni.data = applyCannonicalXform(ni.data, img2std, ni.pixdim, insertMarkerFlag); + case 'xy' + ni.data = applyCannonicalXform(ni.data, img2std, ni.pixdim, insertMarkerFlag); + case 'xz' + ni.data = applyCannonicalXform(ni.data, img2std, ni.pixdim, insertMarkerFlag); + case 'yz' + ni.data = applyCannonicalXform(ni.data, img2std, ni.pixdim, insertMarkerFlag); + case 'xyz' + ni.data = applyCannonicalXform(ni.data, img2std, ni.pixdim, insertMarkerFlag); + otherwise + keyboard +end +end diff --git a/s_vista_2dseqToAnalyze.m b/s_vista_2dseqToAnalyze.m new file mode 100644 index 0000000..71ba14b --- /dev/null +++ b/s_vista_2dseqToAnalyze.m @@ -0,0 +1,106 @@ +%% Transform Bruker scan format (2dseq) to ANALYZE-7 +% +% First attempt to debunk the bruker data from the MPI. +% +% Notes: +% - Set the qform_code or sform_code to 1 depending on whether the xform +% is stored in the qt_xyz/ijk or sto_xyz/ijk +% - bvecs and bvals should be saved as (3,nDirs) amd (1,nDirs) in dimensions. +% +% Franco (c) Stanford Vista Team 2012 + +% Move to the folder with NHP data +baseDir = '/azure/scr1/frk/nhp'; + +% Base folder for each subjct +nhpDir = 'M00.EM1';% 'M00.yO1'; +analyzeDir = 'analyze'; +niftiDir = 'nifti'; +niftiFolder = fullfile(baseDir,nhpDir,'scan40/raw'); +scanstoload = {'40'}; + +% Build an analyze file froma Bruker file +nhpMpiBrukerBuildAnalyze(20,fullfile(baseDir,nhpDir),analyzeDir) + +%% function nhpMpiBuildNiftiFromAnalyze(analyzeFiles,saveName) +% Build a 3D nifti file from the individual analyze files +cd(fullfile(baseDir,nhpDir,'analyze','scan0040')) +ni = niftiRead('M00EM1_scan40_00001.img'); + +% We open on file at the time +sz3d = size(ni.data); +ni.data = nan(sz3d(1),sz3d(2),sz3d(3),68*length(scanstoload)); +c=1; +for is = 1:length(scanstoload) + cd(fullfile(baseDir,nhpDir,'analyze',sprintf('scan00%s',scanstoload{is}))); + for fi = 1:68 + if fi < 10 + thisfile = sprintf('M00EM1_scan%s_0000%i.hdr',scanstoload{is},fi); + else + thisfile = sprintf('M00EM1_scan%s_000%i.hdr',scanstoload{is},fi); + end + fprintf('Loading file: %s\n',thisfile) + ni_temp = niftiRead(thisfile); + % We append the data into the first opened file + ni.data(:,:,:,c) = ni_temp.data; + c = c +1; + end +end +% We update the header information +% Notice, the headers in the analyze files do not have the corect center. +% Build that here. +ni.fname = 'M00EM1_scan40.nii.gz'; +ni.dim = size(ni.data); +ni.qform_code = 1; % the qto_* fields contain the xForm information +ni.slice_dim = 3; +ni.phase_dim = 2; +ni.freq_dim = 1; +ni.slice_start=0; +ni.slice_end =size(ni.data,3)-1; + +% Save the nifti file just created, one folder up +if ~(exist(niftiFolder,'dir') == 7) + mkdir(niftiFolder); +end +p = pwd; +cd(niftiFolder) +niftiWrite(ni) +cd(p) +%% END nhpMpiBuildNiftiFromAnalyze + + +% Build the bvecs +c=1; +for is = 1:length(scanstoload) +% Build the gradients information fromt he Bruker 'method' file +method_fname = fullfile(baseDir,nhpDir,sprintf('%s/method',scanstoload{is})); +[bvecs,bvals,dw] = nhpMpiBrukerBuildDiffusionGradients(method_fname); + +all_bvecs = horzcat(bvecs); +all_bvals = horzcat(bvals); +end + +% Write out the bvals and bvecs +b_fileName = fullfile(niftiFolder, 'M00EM1_scan40'); +dlmwrite([b_fileName '.bvecs'],all_bvecs,' '); +dlmwrite([b_fileName '.bvals'],all_bvals,' '); + +% Reconstruct the T1 anatomical file +cd(fullfile(baseDir, 'M00.yO1','analyze','scan0024')) +ni = niftiRead('M00yO1_scan24.hdr'); +ni.fname = [ni.fname(1:end-4),'_t1.nii.gz']; +ni.qform_code = 1; % the qto_* fields contain the xForm information +ni.slice_dim = 3; +ni.phase_dim = 2; +ni.freq_dim = 1; +ni.slice_start=0; +ni.slice_end =size(ni.data,3)-1; + +p = pwd; +cd(niftiFolder) +niftiWrite(ni) +cd(p) + +%% Preprocess the file +cd(niftiFolder) +dtiInit('M00EM1_scan40.nii.gz','M00yO1_scan24_t1.nii.gz') diff --git a/s_vista_test_build_nifti.m b/s_vista_test_build_nifti.m new file mode 100644 index 0000000..2f1b330 --- /dev/null +++ b/s_vista_test_build_nifti.m @@ -0,0 +1,90 @@ +% This script tests how to flip the dimensions of the analyze files before +% building the nifti file that we use with mr diffusion. +% +% Really the only way to test that the nifti file was build the way we want +% it is to run the process all the way down to dtiInit and tractography. +% +% Only by looking at the tracts generated using the tensor fit we can +% understand whether the nifti were build correctly. +% +% Franco (c) Stanford Vista Team 2012 + +% Move to the folder with NHP data +baseDir = '/azure/scr1/frk/nhp'; + +% Base folder for each subjct +nhpDir = 'M00.yO1'; +analyzeDir = fullfile('analyze','scan0020'); +niftiDir = 'nifti'; +niftiFolder = fullfile(baseDir,nhpDir,'scan20/raw'); +nFiles = 68; % this is the number fo analuze files inside a folder, + % each analyze file is one volume acuired of diffusion + % weighted or b0-signal +analyzeName = 'M00yO1_scan20_00001.img'; + +% We assume that the analyzefiles were created already. +% To build an analyze file from a Bruker file use: +% nhpMpiBrukerBuildAnalyze(20,fullfile(baseDir,nhpDir),analyzeDir) + +% Now we build the nifti file by loadin a bunch of analyze files. +analyzeFile = fullfile(baseDir,nhpDir,analyzeDir,analyzeName); +[dw_name,~,ni] = nhpMpiBuildNiftiFromAnalyze(analyzeFile,nFiles); + +% This is the critical step. After we build the nifti file we need to check +% whether the x,y or z dimension needs to be flipped. +% +% If one of the dimensions needs to be flipped the same flipping needs to +% be applied to the bvecs. See below. +% +% First lets try without swapping dimensions. + + +% Save the nifti file just created, one folder up +if ~(exist(niftiFolder,'dir') == 7) + mkdir(niftiFolder); +end +p = pwd; +cd(niftiFolder) +niftiWrite(ni) +cd(p) + +% Build the bvecs +% Build the gradients information fromt he Bruker 'method' file +method_fname = fullfile(baseDir,nhpDir,sprintf('%s/method','20')); +[bvecs,bvals,dw] = nhpMpiBrukerBuildDiffusionGradients(method_fname); + +% Write out the bvals and bvecs +b_fileName = fullfile(p, dw_name(1:end-7)); +dlmwrite([b_fileName '.bvecs'],bvecs,' '); +dlmwrite([b_fileName '.bvals'],bvals,' '); + +% Reconstruct the T1 anatomical file +cd(fullfile(baseDir, 'M00.yO1','analyze','scan0024')) +ni = niftiRead('M00yO1_scan24.hdr'); +ni.fname = [ni.fname(1:end-4),'_t1.nii.gz']; +ni.qform_code = 1; % the qto_* fields contain the xForm information +ni.slice_dim = 3; +ni.phase_dim = 2; +ni.freq_dim = 1; +ni.slice_start = 0; +ni.slice_end = size(ni.data,3)-1; + +p = pwd; +cd(niftiFolder) +niftiWrite(ni) +cd(p) + +% Align first then save it and do dtiInit/ +% http://white.stanford.edu/newlm/index.php/Anatomical-Processing + +% Align the T1 to ACPC and resample to a predetermined Resolution. +% t1_name = 't1.nii.gz'; +% mrAnatAverageAcpcNifti({'M00yO1_scan24_t1.nii.gz'},t1_name,[],ni.pixdim(1:3)) + +%% Preprocess the file +cd(niftiFolder) +dwParams = dtiInitParams('clobber',1,... + 'phaseEncodeDir',2, ... + 'dwOutMm',[1 1 1], ... + 'numBootStrapSamples',2); +dtiInit(dw_name,t1_name,dwParams)