Image avergaing and keeping the images in MATLAB - 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).

Related

How to create an array with logical variables and iterate through those variables in a for loop?

I have 16 binary images of logic type, and I want to put those images (variable names) into an array and iterate through them in a for loop doing image processing.
Below is an example of my binary image names, and my current for loop (does not work).
bin_RD1 = imbinarize(rightDam1, T_RD1); %these are my binary images
bin_RD2 = imbinarize(rightDam2, T_RD2);
bin_RD3 = imbinarize(rightDam3, T_RD3);
bin_RD4 = imbinarize(rightDam4, T_RD4);
i = who('bin*'); %says of type 16x1 cell
for j = 1:length(i) %j is listed as just a number
k = i{j}; %char type: 'bin_RD1'
% logical k; did not work
roi = bwareaopen(k, 25);
graindata = regionprops('table',roi,'Area','EquivDiameter','MajorAxisLength','MinorAxisLength','Centroid','Orientation');
end
Your wording is confusing and I don't know if this is what you're looking for. Try assigning your variables in matrix form (please keep in mind I've never worked with image manipulation so my indexing could be very wrong):
for i=1:16
bin_RD(:,:,i) = imbinarize(rightDam(:,:,i),T_RD(i));
end
You can use an operation like this to process your bin_RD variable as well. You wouldn't even have to leave the loop.
for i=1:16
bin_RD(:,:,i) = imbinarize(rightDam(:,:,i),T_RD(i));
roi(:,:,i) = bwareaopen(bin_RD(:,:,i), 25);
graindata = regionprops('table',roi(:,:,i),'Area','EquivDiameter','MajorAxisLength','MinorAxisLength','Centroid','Orientation');
end
One last piece of advice: I used i=1:16, but if you ever want to use this code again on a situation where you might have 5, 22, 100, etc images, use for i=1:length(T_RD) or something like that and you won't have to change it every time.

How to use the PARFOR loop for image processing without loading all images together

I want to use a parfor loop for image processing. I do operations on single images and stacks of images. To keep the use of memory low I want to prevent storing all images in memory.
I start with the cell structure variable Imagepaths{}{} that contains
paths for different images in a cell in cell structure. function1 operates on all individual images and function2 operates on a stack of images, combining them into a single new image.
For example: Imagepaths{}{} contains 12 cell. Each cell contains a 1x5 cell with the paths of the images. function2 operates on such a 1x5 stack of images.
The following code i initially try to use but the variable Images{} gives an error for the PARFOR loop.
parfor l = 1:numel(Imagepaths)
for k = 1:numel(Imagepaths{l})
Image = imread(Imagepaths{l}{k});
Images{k} = function1(Image)
end
Image2{l} = function2(Images)
end
I came with a the following solution, but the disadvantage is that it takes a lot of memory as all images are stored.
parfor l = 1:numel(Imagepaths)
for k = 1:numel(Imagepaths{l})
Image = imread(Imagepaths{l}{k});
Images{l}{k} = function1(Image)
end
end
parfor l = 1:numel(Imagepaths)
Image2{l} = function2(Images{l})
end
Does somebody can mention a solution to preserve for storing all images.
In your original code, you've got two forms of indexing for Imagepaths inside the parfor loop, and that prevents slicing, which is what you want. See the doc for more on valid indexing forms for sliced variables. The easiest way to convince parfor that what you're doing is OK is to pull out a temporary array from Imagepaths using valid sliced indexing, and then operate on that.
The second problem I encountered is that your temporary array Images is used in a way that parfor thinks is order-dependent (which strictly speaking it could be, but I suspect in practice it is not). The simplest way to fix that is to assign a new empty cell array to Images on each iteration of the loop, like so:
parfor l = 1:numel(Imagepaths)
tmp = Imagepaths{l}; %# sliced indexing
Images = cell(1, numel(tmp)); %# force "Images" to be "temporary"
for k = 1:numel(tmp)
Image = imread(tmp{k});
Images{k} = function1(Image)
end
Image2{l} = function2(Images)
end
Based on the answer of Edric, mentioning temporary arrays, the following code also works without using the temporary variable "tmp" for the image paths.
parfor l = 1:numel(Imagepaths)
Images = cell(1, number(Imagepaths{l}));
for k = 1:numel(Imagepaths{l})
Image = imread(Imagepaths{l}{k});
Images{k} = function1(Image)
end
Image2{l} = function2(Images)
end

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.

MATLAB reduce function?

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)

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