MATLAB reduce function? - matlab

I would like to add a cell array of images together using imadd, but imadd only takes two arguments. Is there a reduce function in MATLAB which I could use add all of these images together without writing a for loop?
images = {im1, im2, im3};
sum = reduce(#imadd, images);

You could just use an array with an extra dimension. E.g. for 2-d (grayscale images)
images = {im1, im2, im3};
imarr = cat(3, images{:});
imsum = sum(imarr, 3);
Of course there's no need to create the cell array in the first place; you could go straight to
imarr = cat(3, im1, im2, im3);
imsum = sum(imarr, 3);
or even
imsum = sum(cat(ndims(im1)+1, im1, im2, im3),ndims(im1)+1);
which also more generally combines any dimensional matrices.

Since you are using the Image Processing Toolbox, the IMLINCOMB function (linear combination of images) can also be used, just give all coefficients as one:
imsum = imlincomb(1,im1, 1,im2, 1,im3)

Related

Image avergaing and keeping the images in MATLAB

I am recording a number of images and store them in a 3-dimensional array like a "stacked pile" of images, like this:
for i = 1:numberOfImages
ima = pfREAD_IMAGE(board_handle, 0, imasize, ima_ptr, 30000);
imArray(:,:,i) = ima;
end
Where pfREAD_IMAGE() is the function to acquire the images. Afterwards I want to calculate the average of all images, but keep all the individual images. I do it like this:
[imHeight, imWidth, imStackHeight] = size(imArray);
avgIma = zeros(imHeight, imWidth);
for i = 1:imHeight
for j = 1:imWidth
avgIma(i,j) = mean(imArray(i,j,:));
end
end
This method works, but is very slow due to MATLAB's slow looping. What is the best way to speed up the averaging?
The mean function in MATLAB supports a parameter to set the dimension it is working on.
Since you stacking the images on the 3rd dimension what you should do is apply the Mean Operator on that dimension - avgIma = mean(imArray, 3).

Sorting dicom images in Matlab

I am working with lung data sets in matlab, but I need to sort the slices correctly and show them.
I knew that can be done using the "instance number" parameter in Dicom header, but I did not manage to run the correct code.
How can I do that?
Here is my piece of code:
Dicom_directory = uigetdir();
sdir = strcat(Dicom_directory,'\*.dcm');
files = dir(sdir);
I = strcat(Dicom_directory, '\',files(i).name);
x = repmat(double(0), [512 512 1 ]);
x(:,:,1) = double(dicomread(I));
axes(handles.axes1);
imshow(x,[]);
First of all, to get the DICOM header, you need to use dicominfo which will return a struct containing each of the fields. If you want to use the InstanceNumber field to sort by, then you can do this in such a way.
%// Get all of the files
directory = uigetdir();
files = dir(fullfile(directory, '*.dcm'));
filenames = cellfun(#(x)fullfile(directory, x), {files.name}, 'uni', 0);
%// Ensure that they are actually DICOM files and remove the ones that aren't
notdicom = ~cellfun(#isdicom, filenames);
files(notdicom) = [];
%// Now load all the DICOM headers into an array of structs
infos = cellfun(#dicominfo, filenames);
%// Now sort these by the instance number
[~, inds] = sort([infos.InstanceNumber]);
infos = infos(inds);
%// Now you can loop through and display them
dcm = dicomread(infos(1));
him = imshow(dcm, []);
for k = 1:numel(infos)
set(him, 'CData', dicomread(infos(k)));
pause(0.1)
end
That being said, you have to be careful sorting DICOMs using the InstanceNumber. This is not a robust way of doing it because the "InstanceNumber" can refer to the same image acquired over time or different slices throughout a 3D volume. If you want one or the other, I would choose something more specific.
If you want to sort physical slices, I would recommend sorting by the SliceLocation field (if available). If sorting by time, you could use TriggerTime (if available).
Also you will need to consider that there could also potentially be multiple series in your folder so maybe consider using the SeriesNumber to differentiate these.

How do I create an array of image in matlab

I read one by one images from a directory and I wish to create an array of images with that to pass to my mexFunction that processes these images. What I am tried so far is not working. Let say I have 100 images 256x256 when I do
directory = uigetdir; fileList = dir(directory); imageVolume= [];
for idx = 3:numel(fileList)
tempImage = imread(fullfile(directory, fileList(idx).name));
imageVolume= [imageVolume tempImage];
end
Whenever I do that, I don't get an array of 256x256xn, instead I just get an image of 256x(256*n), which is not what I want. Any idea?
Use Cell Arrays. Assuming the rest of your code is right:
for idx = 3:numel(fileList)
tempImage{idx} = imread(fullfile(directory, fileList(idx).name));
end
Using cell arrays as #bjornsen suggested works. If you would rather not use cell arrays, you can use 3 dimensional matrices:
imageVolume(:,:,idx) = tempImage;
You must be sure, though, that all images are the same size. Otherwise, you're better off using cell arrays.

Can I store a MATLAB slice in a variable?

I have a lengthy slice sequence that I need to apply to lots of MATLAB matrices. How can I do this?
i.e. can I simplify,
y(1:some_var*3,1:some_other_var*3,1:another_var*3) = x1(1:some_var*3,1:some_other_var*3,1:another_var*3) .* x2(1:some_var*3,1:some_other_var*3,1:another_var*3) ./ x3(1:some_var*3,1:some_other_var*3,1:another_var*3)
to something like,
inds = slice(1:some_var*3,1:some_other_var*3,1:another_var*3)
y(inds) = x1(inds) .* x2(inds) ./ x3(inds)
like I can do in Python?
In your case, you can create a logical mask:
%# assuming x1,x2,x3,y are all of the same size
mask = false(size(x1));
mask(1:some_var*3,1:some_other_var*3,1:another_var*3) = true;
y(mask) = x1(mask).*x2(mask)./x3(mask);
Other functions that you might want to read about: FIND, SUB2IND
One option is to store each vector of indices in a cell of a cell array, then extract the cell array content as a comma-separated list like so:
inds = {1:some_var*3, 1:some_other_var*3, 1:another_var*3};
y(inds{:}) = x1(inds{:}) .* x2(inds{:}) ./ x3(inds{:});
If you have large matrices, with relatively small/sparse sets of indices, this may be more efficient than using a logical mask as Amro suggested.

Matlab: Subscript + squeeze conveniently

I'm using matlab and am quite new to it. I'm used to Java and other langauges.
Some background: I'm manipulating images, I work with the imread, imshow etc. commands. I want to store multiple images in an array.
So what I do is
img_list = zeroes(num_images, 1200, 1600, 3) % height,width,RGB
and then I load the images with img_list(i,:,:,:) = my_image; iteratively. That is all working fine.
Now I can display the images as I want by doing imshow(squeeze(img_list(1,:,:,:))). I can't stand this. I would like something as simple as imshow(img_list(1)).
Any idea how I can do this?
I definetly am open to change the type of img_list. Any hints is appreciated. Maybe I could do something so all my images in img_list don't have to be of the same size?
Thanks in advance. :)
The easiest solution would be to use a cell array. Each element of a cell array is a container that can hold a variable of any type and size. You access the element of a cell array as array(i) (which returns a 1-by-1 cell). To access the contents of an element of a cell array, you use curly brackets, i.e array{i}. Also have a look at CELLFUN, which allows you to perform operations on each image.
%# initialize the cell array
img_list = cell(num_images);
%# add an image to the cell array
img_list{4} = someImage;
%# display the image
imshow(img_list{4})
%# display only the red channel
imshow(img_list{4}(:,:,3))
Using cell arrays, as Jonas suggested, is probably the Right Thing -- especially if you want to be able to have images of different sizes. But it's worth mentioning that you can make the simple 4-dimensional-array approach a little nicer: make the image number the last index instead of the first. Then you can say img_list(:,:,:,i) = my_image; and imshow(img_list(:,:,:,1)); with no need for squeezing. That's probably a little better for memory locality (hence for performance) too, though it won't be any better than using cell arrays.
Define a local anonymous function:
% Get image list from somewhere.
img_list = ...;
% ...
% Easy-access to individual frames.
nth_image = #(k) squeeze(img_list(k,:,:,:));
image_count = size(img_list,1);
% Loop over images.
% ...
This allows you to write the following list:
% Process each image.
for i = 1 : image_count,
img = nth_image(i);
% ...
end
If you have multiple image lists or this pattern occurs often, you can write more generic functions:
function [ img ] = get_nth_image ( img_list, k )
img = squeeze(img_list(k,:,:,:));
end
function [ img_list ] = set_nth_image ( img_list, img, k )
img_list(k,:,:,:) = img;
end