123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- function varargout = spm_render(dat,brt,rendfile)
- % Render blobs on surface of a 'standard' brain
- % FORMAT spm_render(dat,brt,rendfile)
- %
- % dat - a struct array of length 1 to 3
- % each element is a structure containing:
- % - XYZ - the x, y & z coordinates of the transformed SPM{.}
- % values in units of voxels.
- % - t - the SPM{.} values.
- % - mat - affine matrix mapping from XYZ voxels to MNI.
- % - dim - dimensions of volume from which XYZ is drawn.
- % brt - brightness control:
- % If NaN, then displays using the old style with hot
- % metal for the blobs, and grey for the brain.
- % Otherwise, it is used as a ``gamma correction'' to
- % optionally brighten the blobs up a little.
- % rendfile - the file containing the images to render on to (see also
- % spm_surf.m) or a surface mesh file.
- %
- % Without arguments, spm_render acts as its own UI.
- %__________________________________________________________________________
- %
- % spm_render prompts for details of up to three SPM{.}s that are then
- % displayed superimposed on the surface of a 'standard' brain.
- %
- % The first is shown in red, then green then blue.
- %
- % The blobs which are displayed are the integral of all transformed t
- % values, exponentially decayed according to their depth. Voxels that
- % are 10mm behind the surface have half the intensity of ones at the
- % surface.
- %__________________________________________________________________________
- % Copyright (C) 1996-2015 Wellcome Trust Centre for Neuroimaging
- % John Ashburner
- % $Id: spm_render.m 7381 2018-07-25 10:27:54Z guillaume $
- SVNrev = '$Rev: 7381 $';
- global prevrend
- if ~isstruct(prevrend)
- prevrend = struct('rendfile','', 'brt',[], 'col',[]);
- end
- varargout = {};
- %-Parse arguments, get data if not passed as parameters
- %==========================================================================
- %-Get surface
- %--------------------------------------------------------------------------
- if nargin < 3 || isempty(prevrend.rendfile)
- spm('FnBanner',mfilename,SVNrev);
- [rendfile, sts] = spm_select(1,{'mat','mesh'},'Render file');
- if ~sts, return; end
- end
- prevrend.rendfile = rendfile;
- ext = spm_file(rendfile,'ext');
- loadgifti = false;
- if strcmpi(ext,'mat')
- load(rendfile);
- if ~exist('rend','var') && ~exist('Matrixes','var')
- loadgifti = true;
- end
- end
- if ~strcmpi(ext,'mat') || loadgifti
- try
- rend = gifti(rendfile);
- catch
- error('Cannot read render file "%s".\n', rendfile);
- end
- if ~isfield(rend,'vertices')
- try
- M = rend;
- rend = gifti(rend.private.metadata(1).value);
- try, rend.cdata = M.cdata(); end
- catch
- error('Cannot find a surface mesh to be displayed.');
- end
- end
- rend = export(rend,'patch');
- end
-
- %-Get data
- %--------------------------------------------------------------------------
- if isfield(rend,'facevertexcdata')
- dat = rend.facevertexcdata;
- num = 1;
- elseif nargin < 1
- spm('FigName','Results: render');
- num = spm_input('Number of sets',1,'1 set|2 sets|3 sets',[1 2 3],1);
- for i = 1:num
- [SPM,xSPM] = spm_getSPM;
- dat(i) = struct('XYZ', xSPM.XYZ,...
- 't', xSPM.Z',...
- 'mat', xSPM.M,...
- 'dim', xSPM.DIM);
- end
- showbar = 1;
- else
- if isstruct(dat)
- num = length(dat);
- showbar = 0;
- else
- files = cellstr(dat);
- clear dat
- num = numel(files);
- for i=1:num
- V = spm_vol(files{i});
- d = spm_read_vols(V);
- id = find(isfinite(d));
- [X,Y,Z] = ind2sub(V.dim,id);
- dat(i).XYZ = [X Y Z]';
- dat(i).t = d(id);
- dat(i).mat = V.mat;
- dat(i).dim = V.dim';
- clear X Y Z id
- end
- showbar = 1;
- end
- end
- %-Get brightness & colours (mesh)
- %--------------------------------------------------------------------------
- if isfield(rend,'vertices')
- if num == 1
- col = hot(256);
- else
- col = eye(3);
- if spm_input('Which colours?','+1','b',{'RGB','Custom'},[0 1],1)
- for k = 1:num
- col(k,:) = uisetcolor(col(k,:),sprintf('Colour of blob set %d',k));
- end
- end
- end
- surf_rend(dat,rend,col);
- return
- end
- %-Get brightness & colours (image)
- %--------------------------------------------------------------------------
- if nargin < 2 || isempty(prevrend.brt)
- brt = 1;
- if num==1
- brt = spm_input('Style',1,'new|old',[1 NaN], 1);
- end
- if isfinite(brt)
- brt = spm_input('Brighten blobs','+1','none|slightly|more|lots',[1 0.75 0.5 0.25], 1);
- col = eye(3);
- % ask for custom colours & get rgb values
- %------------------------------------------------------------------
- if spm_input('Which colours?','+1','b',{'RGB','Custom'},[0 1],1)
- for k = 1:num
- col(k,:) = uisetcolor(col(k,:),sprintf('Colour of blob set %d',k));
- end
- end
- else
- col = [];
- end
- elseif isfinite(brt) && isempty(prevrend.col)
- col = eye(3);
- elseif isfinite(brt) % don't need to check prevrend.col again
- col = prevrend.col;
- else
- col = [];
- end
- prevrend.brt = brt;
- prevrend.col = col;
- %-Perform the rendering
- %==========================================================================
- spm('Pointer','Watch');
- if showbar, spm_progress_bar('Init', size(dat,1)*length(rend),...
- 'Formatting Renderings', 'Number completed'); end
- for i=1:length(rend)
- rend{i}.max=0;
- rend{i}.data = cell(size(dat,1),1);
- if issparse(rend{i}.ren)
- % Assume that images have been DCT compressed
- % - the SPM99 distribution was originally too big.
- d = size(rend{i}.ren);
- B1 = spm_dctmtx(d(1),d(1));
- B2 = spm_dctmtx(d(2),d(2));
- rend{i}.ren = B1*rend{i}.ren*B2';
- % the depths did not compress so well with
- % a straight DCT - therefore it was modified slightly
- rend{i}.dep = exp(B1*rend{i}.dep*B2')-1;
- end
- rend{i}.ren(rend{i}.ren>=1) = 1;
- rend{i}.ren(rend{i}.ren<=0) = 0;
- if showbar, spm_progress_bar('Set', i); end
- end
- if showbar, spm_progress_bar('Clear'); end
- if showbar, spm_progress_bar('Init', length(dat)*length(rend),...
- 'Making pictures', 'Number completed'); end
- mx = zeros(length(rend),1)+eps;
- mn = zeros(length(rend),1);
- for j=1:length(dat)
- XYZ = dat(j).XYZ;
- t = dat(j).t;
- dim = dat(j).dim;
- mat = dat(j).mat;
- for i=1:length(rend)
- % transform from Talairach space to space of the rendered image
- %------------------------------------------------------------------
- M1 = rend{i}.M*mat;
- zm = sum(M1(1:2,1:3).^2,2).^(-1/2);
- M2 = diag([zm' 1 1]);
- M = M2*M1;
- cor = [1 1 1 ; dim(1) 1 1 ; 1 dim(2) 1; dim(1) dim(2) 1 ;
- 1 1 dim(3) ; dim(1) 1 dim(3) ; 1 dim(2) dim(3); dim(1) dim(2) dim(3)]';
- tcor= M(1:3,1:3)*cor + M(1:3,4)*ones(1,8);
- off = min(tcor(1:2,:)');
- M2 = spm_matrix(-off+1)*M2;
- M = M2*M1;
- xyz = (M(1:3,1:3)*XYZ + M(1:3,4)*ones(1,size(XYZ,2)));
- d2 = ceil(max(xyz(1:2,:)'));
- % Calculate 'depth' of values
- %------------------------------------------------------------------
- if ~isempty(d2)
- dep = spm_slice_vol(rend{i}.dep,spm_matrix([0 0 1])*inv(M2),d2,1);
- z1 = dep(round(xyz(1,:))+round(xyz(2,:)-1)*size(dep,1));
- if ~isfinite(brt), msk = find(xyz(3,:) < (z1+20) & xyz(3,:) > (z1-5));
- else msk = find(xyz(3,:) < (z1+60) & xyz(3,:) > (z1-5)); end
- else
- msk = [];
- end
-
- if ~isempty(msk)
- % Generate an image of the integral of the blob values.
- %--------------------------------------------------------------
- xyz = xyz(:,msk);
- if ~isfinite(brt), t0 = t(msk);
- else
- dst = xyz(3,:) - z1(msk);
- dst = max(dst,0);
- t0 = t(msk).*exp((log(0.5)/10)*dst)';
- end
- X0 = full(sparse(round(xyz(1,:)), round(xyz(2,:)), t0, d2(1), d2(2)));
- hld = 1; if ~isfinite(brt), hld = 0; end
- X = spm_slice_vol(X0,spm_matrix([0 0 1])*M2,size(rend{i}.dep),hld);
- msk = find(X<0);
- X(msk) = 0;
- else
- X = zeros(size(rend{i}.dep));
- end
- % Brighten the blobs
- %------------------------------------------------------------------
- if isfinite(brt), X = X.^brt; end
- mx(j) = max([mx(j) max(max(X))]);
- mn(j) = min([mn(j) min(min(X))]);
- rend{i}.data{j} = X;
- if showbar, spm_progress_bar('Set', i+(j-1)*length(rend)); end
- end
- end
- mxmx = max(mx);
- mnmn = min(mn);
- if showbar, spm_progress_bar('Clear'); end
- %-Display
- %==========================================================================
- if ~spm('CmdLine')
- Fgraph = spm_figure('GetWin','Graphics');
- spm_results_ui('Clear',Fgraph);
-
- nrow = ceil(length(rend)/2);
- if showbar, hght = 0.95; else hght = 0.5; end
- % subplot('Position',[0, 0, 1, hght]);
- ax = axes('Parent',Fgraph,...
- 'units','normalized',...
- 'Position',[0, 0, 1, hght],...
- 'Visible','off');
- image(0,'Parent',ax);
- set(ax,'YTick',[],'XTick',[]);
- end
- rgb = cell(1,length(rend));
- if ~isfinite(brt)
- % Old style split colourmap display
- %----------------------------------------------------------------------
- split = [gray(64); hot(64)];
- if ~spm('CmdLine'), colormap(split); end
- for i=1:length(rend)
- ren = rend{i}.ren;
- X = (rend{i}.data{1}-mnmn)/(mxmx-mnmn);
- msk = find(X);
- ren(msk) = X(msk)+(1+1.51/64);
- rgb{i} = ind2rgb(round(ren*64),split);
- if ~spm('CmdLine')
- ax = axes('Parent',Fgraph,...
- 'units','normalized',...
- 'Position',[rem(i-1,2)*0.5, floor((i-1)/2)*hght/nrow, 0.5, hght/nrow],...
- 'Visible','off');
- image(ren*64,'Parent',ax);
- set(ax,'DataAspectRatio',[1 1 1],...
- 'PlotBoxAspectRatioMode','auto',...
- 'YTick',[],'XTick',[],...
- 'XDir','normal','YDir','normal');
- end
- end
- else
- % Combine the brain surface renderings with the blobs, and display
- % using 24 bit colour
- %----------------------------------------------------------------------
- for i=1:length(rend)
- ren = rend{i}.ren;
- X = cell(3,1);
- for j=1:length(rend{i}.data)
- X{j} = rend{i}.data{j}/(mxmx-mnmn)-mnmn;
- end
- for j=(length(rend{i}.data)+1):3
- X{j}=zeros(size(X{1}));
- end
- rgb{i} = zeros([size(ren) 3]);
- tmp = ren.*max(1-X{1}-X{2}-X{3},0);
- for k = 1:3
- rgb{i}(:,:,k) = tmp + X{1}*col(1,k) + X{2}*col(2,k) +X{3}*col(3,k);
- end
- rgb{i}(rgb{i}>1) = 1;
- if ~spm('CmdLine')
- ax = axes('Parent',Fgraph,...
- 'units','normalized',...
- 'Position',[rem(i-1,2)*0.5, floor((i-1)/2)*hght/nrow, 0.5, hght/nrow],...
- 'nextplot','add', ...
- 'Visible','off');
- image(rgb{i},'Parent',ax);
- set(ax,'DataAspectRatio',[1 1 1],...
- 'PlotBoxAspectRatioMode','auto',...
- 'YTick',[],'XTick',[],...
- 'XDir','normal','YDir','normal');
- end
- end
- end
- spm('Pointer','Arrow');
- if nargout
- for i=1:numel(rgb)
- for ch=1:size(rgb{i},3)
- rgb{i}(:,:,ch) = flipud(rgb{i}(:,:,ch));
- end
- end
- varargout = { rgb };
- end
- %==========================================================================
- % function surf_rend(dat,rend,col)
- %==========================================================================
- function surf_rend(dat,rend,col)
- %-Setup figure and axis
- %--------------------------------------------------------------------------
- Fgraph = spm_figure('GetWin','Graphics');
- spm_results_ui('Clear',Fgraph);
- ax0 = axes(...
- 'Tag', 'SPMMeshRenderBackground',...
- 'Parent', Fgraph,...
- 'Units', 'normalized',...
- 'Color', [1 1 1],...
- 'XTick', [],...
- 'YTick', [],...
- 'Position', [-0.05, -0.05, 1.05, 0.555]);
- ax = axes(...
- 'Parent', Fgraph,...
- 'Units', 'normalized',...
- 'Position', [0.05, 0.05, 0.9, 0.4],...
- 'Visible', 'off');
- H = spm_mesh_render('Disp',rend,struct('parent',ax));
- spm_mesh_render('Overlay',H,dat,col);
- camlight(H.light);
- try
- setAllowAxesRotate(H.rotate3d, setxor(findobj(Fgraph,'Type','axes'),ax), false);
- end
-
- %-Register with MIP
- %--------------------------------------------------------------------------
- try % meaningless when called outside spm_results_ui
- hReg = spm_XYZreg('FindReg',spm_figure('GetWin','Interactive'));
- xyz = spm_XYZreg('GetCoords',hReg);
- hs = mydispcursor('Create',ax,dat.mat,xyz);
- spm_XYZreg('Add2Reg',hReg,hs,@mydispcursor);
- end
-
- %==========================================================================
- function varargout = mydispcursor(varargin)
- switch lower(varargin{1})
- %======================================================================
- case 'create'
- %======================================================================
- % hMe = mydispcursor('Create',ax,M,xyz)
- ax = varargin{2};
- M = varargin{3};
- xyz = varargin{4};
-
- [X,Y,Z] = sphere;
- vx = sqrt(sum(M(1:3,1:3).^2));
- X = X*vx(1) + xyz(1);
- Y = Y*vx(2) + xyz(2);
- Z = Z*vx(3) + xyz(3);
- hold(ax,'on');
- hs = surf(X,Y,Z,'parent',ax,...
- 'EdgeColor','none','FaceColor',[1 0 0],'FaceLighting', 'gouraud');
- set(hs,'UserData',xyz);
-
- varargout = {hs};
-
- %======================================================================
- case 'setcoords' % Set co-ordinates
- %======================================================================
- % [xyz,d] = mydispcursor('SetCoords',xyz,hMe,hC)
- hMe = varargin{3};
- pxyz = get(hMe,'UserData');
- xyz = varargin{2};
-
- set(hMe,'XData',get(hMe,'XData') - pxyz(1) + xyz(1));
- set(hMe,'YData',get(hMe,'YData') - pxyz(2) + xyz(2));
- set(hMe,'ZData',get(hMe,'ZData') - pxyz(3) + xyz(3));
- set(hMe,'UserData',xyz);
-
- varargout = {xyz,[]};
-
- %======================================================================
- otherwise
- %======================================================================
- error('Unknown action string')
- end
|