Matlab Imaging Tutorial
Matlab Imaging Tutorial
Getting Started
Matlab is a programming language and interface that is especially good at dealing with matrices of numbers. Read the CNL matlab web page (http://cnl.web.arizona.edu/matlab.htm) before continuing with this tutorial. When you start Matlab, you will see a screen divided into several windows: The large window on the right is the Command window. Here you can display variables, type commands etc. On the lower left, are two tabbed windows, the Current Directory window which allows you to see and manipulate files in your current directory, navigate to other directories etc., the Command History window which keeps track of all the commands youve typed as well as copying those commands to the current command line or rerunning (evaluating) the lines. On the upper left is the Workspace window. This window displays all current variables and allows you to perform various operations on them by right clicking and selecting from the popup window. On the menu bar, the File menu allows you to create new files, open files, import data, and set the path (see below). The Help menu gives you access to extensive online help files. Conventions: I will show you what to type at the matlab prompt >> in bold black (dont type the prompt). Comments will adhere to Matlab conventions: preceded by a % and in green. Matlab will not try to interpret anything on the line after a percent sign.
Setting the Path Unzip cnl_mfiles.zip in a directory where you want to work. Matlab finds m-files by looking in all the directories in its path. To tell Matlab where to look for these new m-files, click file->set path. You should see the Set path window. Click Add Folder or Add with subfolders (depending on how many levels of directories you want Matlab to search for m-files). Browse to the directory you want to add. Select it and click Ok .
M-files
Use File->Open (Browse) to find and display m-files. As you progress, m-files should make more sense. Within m-files, select and right-click for a menu: For keyword help choose help selection. To run parts of the program and see what they do, choose evaluate selection. When you get to "Control Structures", use File->New->M-file to create your own blank m-file.
Vector a 1 2 3 4 or a2 1 2 3 4
Figure 1
Typically [ ] are used for concatenation, e.g., [1 2 3 4]. The other statements are not really concatenation statements so either () or [ ] seem to work. The colon operator is used in several ways: In a=[1:4] and a=(1:4) it means 1 thru 4, or start with 1and count up to 4. In a=[1:1:4] and a=(1:1:4) a value is inserted in the middle that refers to the increment. These say Start with 1, count up by 1 (the default), end at 4. Think of this latter as the basic way to write the statement, and think of a=[1:4] and a=(1:4) are a shorthand that works because the default increment is 1. Column vectors can be created from scratch:
>> a2 = [1;2;3;4]
The 2-D matrix in Fig. 1, can be created by putting a hard return between rows:
>> b = [1 4 7 10 2 5 8 11 3 6 9 12]
creates a 3-D array with 2 rows, 2 columns and two pages, but it is filled with zeros. How might you create the 3-D array in Figure 1?:
>> c = [6 3 2 5 1 4 7 6 8 4 9 3] >> c = reshape(c, 2, 3, 2)
Describing Arrays
>> size(a) % Size as an ordered list: #rows, #columns, #pages etc. >> ndims(a) % Number of dimensions >> numel(a) % The number of elements in the array. >> length(a) % Equivalent to max(size(a)), returns the largest dimension of a.
Each array element has a simple index based on the count (e.g., 1, 2, 3 etc.) AND an index based on array shape (like a Cartesian Coordinate); e.g., the simple index 1 corresponds to the 2D index 1,1 or the 3D index 1,1,1. 2 corresponds to the 2-D 2,1 etc. Finally, each element in an array has a value assigned to it. For our grayscale Mri and fMRI images, this value represents intensity: black is zero, white is the largest value (256 for an 8 bit image, 65,536 for a 16 bit image). To find the value of an element/voxel, simply enter a valid index for it. Consider the 3-D array, Figure 1:
>> size(c) >> c(1) >> c(1,1,1) >> c(2) >> c(2,1,1) >> c(7) >> c(1,1,2) % 2 rows, 2 columns and 2 pages (like 2 slices from an image) % Produces the answer (ans) 6. 6 is the value % Same as above % Has the value 3 % Same as above % Has the value 7 % Same as above
The above examples only show you the output values. To extract the subarray into a variable, you need a variable name (e.g., d) and the assignment operator (= is the assignment operator, not to be confused with ==, the equal sign), e.g.:
>> d = a(4:-1:1)
% Create f by concatenating d2 with all rows % Of e in the first thru second columns. % Concatenate e and f along the 3rd dimension to create g
Merging Arrays
a= 123 b=4 5 4 456 454 789 545 >> b(3:4,:) = a(1:2,:) creates b= 454 % For rows 3:4 of b(whether or not they exist), all 454 % columns, substitute all columns of rows 1:2 from a. 123 456 % Put the contents of columns 2 thru 3 from b >> g(1:8) = b(:,2:3) % into a row vector % called g. creates: 55254436
% The first command creates h, a column % of 6 ones. h can then be filled with % values from some other array, in this case % a, without changing the shape of h.
>> b = a(:) >> b = reshape(a,1,9) >> b = a 147 258 369 >> b(2,:) = [ ] 147 369 >> a(2,:) = b(2,:) 123 369 789 >> a(2,:) = 6 >> a(2,:) = [ 6 6 6] 123 666 789
% Reshape a into a column b % Reshape a into a 1x9 vector b (a row vector) % Transpose a to create b (transpose is not equivalent to reshape)
% Replace all elements of row 2 in a with 6s. % Same as above, but without relying on scalar expansion of 6
>> a(1,[1,3]) = 1 101 000 000 >> a([1 3], 1) = 2 200 000 200
% Run on the original a, this puts the % value 2 into the first and third % elements of column 1.
________________________________________________________________
________________________________________________________________
Cell Arrays
A cell array is a useful structure to know about if you want to work in SPM. A cell array can hold different sized vectors in each cell. In SPM, you can use the cell array to hold a vector of stimulus onsets for each of several conditions (e.g., the vector for the first condition is in cell 1. The vector for the second condition is in cell 2 etc.) To create a cell array:
>>a{1,1} = [1 2 4 6 8] >>a{1,2} = [ 5 77 89] >>a{1,3} = [3 4 5 6 2 1 7 8 9 334]
You now have a cell array, a, that contains 3 row vectors (this is perfect for SPM stimulus onset times) in 3 cells. To view a description of the cell array:
>>a
________________________________________________________________
Alternative: a + 5 % Add 5 to each element in a. This is the matrix solution ___________________________________ If-else-end If statements come in levels of complexity depending on how many conditions (1,2 or more): 1) if-end, 2) if-else-end, 3) if-elseif-else-end 1) A simple if statement:
if apples > 5;
Note that for both surface and surf plots, you can rotate the plot and see it displayed as a topo map. You can also annotate it, display or change the color bar, etc. If you imported your image from Afni with AFNItoANALYZE, and your original BRIK was in radiological orientation (as it generally would be in Afni), then viewing the array with surf or surface will show you an image in radiological orientation. However, that same image, viewed with imshow (see below) will be switched into neurological orientation. In addition, for both imshow and surface, the z axis (dim 3) will be flipped relative to the Afni slices (e.g., in a 12 slice image, slice 0 in Afni will be slice 12 in Matlab, Afni slice 1 will be Matlab slice 11 etc.).
>>plot(imgarray(:,32,4,2)) % Make an intensity line plot of all columns at the point where they intersect row 32 of the fourth physical slice at the second timepoint (in effect, plot row 32 of slice 4, timepoint 2). >>plot(imgarray(32,:,4,2) % Make an intensity line plot of all rows at the point where they intersect column 32 of the fourth physical slice at the second timepoint (in effect, plot column 32 of slice 4, timepoint 2). >>a=(imgarray(:,:,:,1) % Extracts all values (a 3D brain volume) at timepoint 1. >>slice(a,32,32,10) %Creates figure of 3 planes from "a" intersecting at x(row)=32, y(column)=32 and z=10.
Right click any variable in the Matlab workspace to find 2D and 3D graphing options. Keep in mind that once you have displayed a figure window, it may simply minimize and you wont see the results of your graphing unless you go click the figure window in the start bar or request a new figure window:
>>figure
At least two other statistics for n-dimensional arrays, corr2 and std2 that come with the image processing toolbox
>>mean(mean(mean(mean(randarray)))) % same result as above for a 4-D array (4 levels of nesting for the 4D array), but doesnt require the image processing toolbox.
You can use the same technique for the standard functions std (the standard deviation of the array), min (the minimum value in the array), and max (the maximum value in the array). Normally, these simple statistics work on 1-D vectors, but if you nest them for the number of dimensions, as in the above example, they can be made to work on any sized array. Check out zscore.m in cnl_mfiles.
In edit mode, you can right click any button and choose Inspect properties. Simply set the Callback property to be the name of the m-file that the button should run when pressed. You may wish to set tooltip string to be the explanatory help that comes up when someone mouses over the button.
>>guide % Brings up the gui development environment so you can make your own interface.
The image processing toolbox will not automatically treat the results of running loadimg (which requires spm) as images, because it expects images to contain certain structures. For example, the image type we are primarily interested in, intensity images, must have values between 0 and 1. imgarray.mat in Arrays.zip does not contain the correct values. You can use mat2gray to convert it:
>>imgarray2 = mat2gray(imgarray);
A slice out of imgarray2 can now be directly displayed as a proper intensity image:
>>imshow (imgarray2(:,:,7,3)); %A figure window should come up. If it does not, type: >>figure, imshow (imgarray2(:,:,7,3));
You can get imshow to interpret your array values and display a slice without converting with mat2gray:
>>figure, imshow (imgarray2(:,:,7,3), []); % add an empty matrix [] to the statement.
But if you are interested in playing with other image processing functions, you will run into trouble unless you do the mat2gray conversion. anatarray is a 256x256x17 mri structural image, already converted with mat2gray. Note that the simple mat2gray conversion produced an image that was way too dark. By default, the min value and max value in the array are used as the limits (In this case 0 and 1454). However, a histogram of one of the slices revealed that most values in the image were less than 300 and only a few ranged between 300 and 750 on a typical slice. Explicitly setting a tighter range, based on the histogram, brightened up the image considerably:
>>anatarray2 = mat2gray(anatarray, [0, 500]);
Other ranges are possible. 1000 looked better than 1454, but I liked 500 best. You should be very reluctant to crop the upper part of the range for a functional image, since that range provides vital information. However, cropping the range for a structural should be less crucial, especially if it improves your ability to resolve features by eye. Now that you have a figure window up, displaying a slice, type:
>>roipoly % This allows you to draw a shape on a displayed image which it automatically makes into a binary mask, so if you draw around the brain, then an image will be produced in which everything outside the brain is black (0) and everything inside is white (1). >>impixel % This allows you to select points (a little star will appear at each point) on a displayed image. When you hit enter, the intensity values are returned for each star (they are presented in RGB format, for an intensity image, this means you'll get a row of 3 equivalent values R=G=B for each star). Similar to picker.m. >>improfile % This allows you to draw a line on a displayed image, or series of line segments on the image and get back an intensity profile. A complex set of line segments results in a 3-D histogram. Similar to rowpicker.m and historypicker.m. >>imcontour (imgarray(:,:,7,3)) % This draws an edge contour of the slice, even if the slice is not from a mat2gray converted array. >>imhist (imgarray(:,:,7,3)) % Creates an image histogram, seems to be finicky about the range of values (It may require a true intensity image converted with mat2gray). "hist" will work on any slice of an array, whether or not it is in the "image" range.
Montage creates a montage of multiple images. Mov creates a movie. Both montage and mov expect the multiple images to be arranged on the 4th dimension. montage requires that the image be converted with mat2gray first. mov require that the image be converted from an intensity image to an indexed image. The following steps should work to create a montage and movie respectively:
>>anatmontage = reshape(anatarray, [256,256,1,17]); % Create anatmontage by reshaping anatarray so that it has an extra singleton dimension and the slices are arranged on the 4th dimension. Remember anatarray has already been converted to a true intensity image with mat2gray. >>figure, montage(anatmontage) %This should bring up a figure window and display the montage.
To create a movie:
>>[ind_anat, gray] = gray2ind(anatmontage, 256); %This converts the image from intensity to indexed. Indexed images havetwo parts, an image and a colormap. In this example, "ind_anat" is the indexed image and "gray" is the colormap. >>anat_mov=immovie(ind_anat, gray); % This creates the movie (and should play it once) >>movie(anat_mov) % This plays the movie
Summary
This should get you started. Look on-line for m-files, and look at the m-files you have. The ones youve downloaded with this tutorial are pretty straightforward (load imgarray or anatarray and then type the name of the m-file you want to run). Look at simple ones like mkmatrixrand.m, and zscore.m. See corall9.m to see a switch-case statement. Let me ([email protected]) know when you have suggestions or find errors. Thanks, Dianne.
Functions Covered
(*=Image Processing Toolbox) cat clear corr2 * delete figure find for gray2ind * guide hist if-else imcontour * imhist * immovie * impixel * improfile * imshow * length load ls mat2gray * max mean mean2 *
min montage * movie * ndims numel ones permute plot rand repmat reshape roipoly *
save size squeeze std std2 * surf surface ver what who whos zeros