====== Creating an animating GIF ====== This is a simple example to illustrate how to write your own custom 'analysis' code and functions to integrate with mrTools-4.5. The function writes an animated gif file that shows the mean or median fMRI/EPI data over time in false color, superimposed on your inplane anatomies. Not particularly life-changing, but quite useful for (0) learning how to get started coding, (1) inspecting whether you inplane anatomies and EPI data are aligned (2) how bad distortions of the EPI data is compared to nondistorted anatomy and (3) impressing your audience with moving false-color images if they like that kind of thing. **Things you will need:** most recent mrTools-4.5 install. **svn update** if you are not sure. The OSX command line tool **gifmerge** for turning individual gif images into animated gif. If you have FSL installed on your machine, you should have it. Try **which gifmerge** or **gifmerge** at the Terminal prompt. It's also handy to have the imagemagick convert tools http://www.imagemagick.org/script/binary-releases.php#macosx available. ===== Overview of code ===== - Function definition - Checking that all directories and unix tools are available on users machine - Loading in previous analysis (timeSeriesStats) and the anatomy - Getting information about number of slices, range of data, etc. using **viewGet** - Set range of overlay colors - Step through slices, render each one, grab image, save to tiff and convert to gif (because matlab gif-writing is a pain) - Glue all gif images together to make an animated gif - Open the resulting image up in Safari (which can display animated gifs dynamically) - Clean up by removing temporary files ===== Implementation ===== ==== 1. Function definition ==== Usual pre-amble with some comments on how to use the function. You can save the function anywhere on your matlab path. Its only input is the mrLoadRet view. So to use the function, the user will have to keep hold of it: v = newView; mrSliceExportTest( v ) Open a new file called **mrSliceExport** in your editor and start adding to the file: % mrSliceExportTest - output series of images across all slices % % usage: [ ] = mrSliceExportTest( v ) % by: denis schluppeck % date: 2007-11-22 % $Id: mrSliceExportTest.m,v 1.1 2008/01/25 17:12:20 ds1 Exp $: % inputs: v % outputs: % % purpose: export merged images of EPI data and underlying anatomy to an animated gif % % e.g: v = mrLoadRet; mrSliceExport( v ); % function [ ]=mrSliceExportTest( v ) % make sure user supplies input if nargin < 1 help mrSliceExportTest return end % get access to mrTools global variables mrGlobals ==== 2. Checking directories and unix tools are available ==== We assume that the user has been good and installed the imagemagick tools for converting images and the gifmerge program. Also he/she should have calculated the timeSeriesStats for the current scan/group. If not, the code just warns and returns: % check that the the timeSeriesStats have been calculated analysisdir = sprintf('%s/timeSeriesStats',viewGet(v,'datadir')); if ~exist(analysisdir, 'dir') mrWarnDlg('(mrSliceExportTest) You need to calculate timeSeriesStats first') return end % check that gifmerge and /usr/local/convert are installed for imageconversion [status,result]=system('which convert'); if status == 0 % unix success mrDisp(sprintf('(mrSliceExportTest) imagemagick "convert" found: %s', result)); else mrWarnDlg('(mrSliceExportTest) You need to install imagemagick first...'); return end [status,result]=system('which gifmerge'); if status == 0 % unix success mrDisp(sprintf('(mrSliceExportTest) "gifmerge" found: %s', result)); else mrWarnDlg('(mrSliceExportTest) you need to install gifmerge first...'); return end ==== 3. Loading in previous analysis (timeSeriesStats) and the anatomy ==== The next lines of code just load in the data from the analysis performed previously. For good measure read in the anatomy image again; this also lets the user specify another anatomy image (maybe the volume anatomy): % load in timeSeriesStatistics v = loadAnalysis(v, 'timeSeriesStats', analysisdir); % load anatomy v = loadAnat(v); By changing the type of analysis you are loading in, you can obviously change the overlay. You could use similar code to superimpose e.g. functional maps on very high resolution anatomies by loading the corresponding files. ==== 4. Getting information about number of slices, range of data, etc. using **viewGet** ==== This bit of code illustrates the power of the **viewGet** command - basically anything that you might ever want to query is accessible by the viewGet/viewSet commands. To see what's available for reading/writing type **viewGet** (or **viewSet**) at the matlab prompt and you will get a nicely formatted list of all the parameters. The code switches to the **median** view (which is the 2nd entry in the cell array of statistical maps), and gets various paramters. We then get the medianData and calculate its 5 and 95 percentiles to give the colormap a smaller range to display. % the timeSeriesStats data contains several statistics; #2 is the median. % let's grab that. v = viewSet(v, 'curoverlay', 2); viewNum = viewGet(v,'viewnum'); curGroup = viewGet(v,'curgroup'); curScan = viewGet(v,'curscan'); curOverlay = viewGet(v,'currentoverlay'); % set the range of displayed median values to 5 and 95 percentile medianData = viewGet(v,'overlaydata',curScan, curOverlay); robustRange = prctile(medianData(medianData>0), [5 95]); % clip can handle n-d data, use nanclip to set values to nan (instead of cmin,max) robustMedianData = nanclip(medianData, robustRange(1), robustRange(2)); ==== 5. Set range of overlay colors ==== Next set the display range used by the mrLoadRet GUI and the alpha transparency... v = viewSet(v,'overlaymin', robustRange(1)); v = viewSet(v,'overlaymax', robustRange(2)); % for alpha transparency, have to go via mlrGuiSet -- is this bad? mlrGuiSet(v,'alpha', 0.5); ==== 6. Step through slices, render each one, grab image, save to tiff and convert to gif (because matlab gif-writing is a pain) ==== Get info on how many slices we need to process. Next create a temporary directory, which we will clean up again later. % loop over slices and get images nSlices = viewGet(v,'nslices'); % clear a variable img = []; % make a temporary folder called '.tmptif' tmpdir = sprintf('%s/.tmptif',viewGet(v,'datadir')); % ignore warnings about directory already existing! warning('off','MATLAB:MKDIR:DirectoryExists'); mkdir(tmpdir); warning('on','MATLAB:MKDIR:DirectoryExists'); Loop over slices, display, grab image, write to tiff and convert in place to gif (using the OSX command line tool). for ii = 1:nSlices mlrGuiSet(v, 'slice', ii); refreshMLRDisplay(viewNum); disp(sprintf('..rendering slice %d to %s..',ii, tmpdir)); img(:,:,1:3,ii) = refreshMLRDisplay(viewNum); mglWaitSecs(0.1); % let the GUI catch up fname = sprintf('%sim%02d.tif', tmpdir,ii); imwrite(img(:,:,1:3,ii), fname , 'tif'); % convert to gif right here. % could increase imagesize by adding an option % convertcmd = sprintf('convert %s -resize 200% %s ' ,fname , strrep(fname, '.tif','.gif')); convertcmd = sprintf('convert %s %s', fname, strrep(fname, '.tif', '.gif')); system(convertcmd); end ==== 7. Glue all gif images together to make an animated gif ==== The unix tool **gifmerge** glues all of the gif frames together with some options: frame time 50, means 0.5s, -l0 means loop forever. % gifmerge - merge all the gif images together. animgifname = sprintf('%s/animatedGif.gif', viewGet(v,'datadir')); mrDisp(sprintf('(mrSliceExport) writing animated gif to %s',animgifname)) system(sprintf('gifmerge -50 -l0 %s/*.gif > %s', tmpdir, animgifname )); ==== 8. Open the resulting image up in safari (which can display animated gifs dynamically) ==== If you haven't used the Mac OSX command **open** yet, learn about it with **man open** in the Terminal. It's really useful for opening image files up in preview, text files in TextEdit, etc. (it's actually smart about filetypes, but we need to help it out here and point it to Safari browser). % open in safari... mrDisp(sprintf('(mrSliceExport) opening up in Safari.app')) system(sprintf('open -a Safari %s', animgifname)); ==== 9. Finally clean up and return ==== % clean up. mrDisp(sprintf('(mrSliceExport) cleaning up temporary directoryn')) system(sprintf('rm -r %s', tmpdir )); return; ==== 10. The final product ==== Looks different depending on what kind of color map, clip values, and alpha transparency you specify. Here a simple example:
{{:mrtools:animatedgif.gif|}}