Filling Multiple Images in Matlab - image

I have the following code to import multiple images from one directory into a struct in Matlab, here is an example of the images.
myPath= 'E:\conduit_stl(smooth contour)\Collagen Contour Slices\'; %'
fileNames = dir(fullfile(myPath, '*.tif'));
C = cell(length(fileNames), 1);
for k = 1:length(fileNames)
filename = fileNames(k).name;
C{k} = imread(filename);
se = strel('disk', 2, 0);
C = imclose(C, se);
filled = imfill(C,'holes');
end
Though now I would like to perform a fill on all the images, later finding the centroids. However, when attempting this, an error stating: "Expected input number 1, I1 or BW1, to be one of these types: double, ... etc" I tried converting the images into double precision, though that just resulted in: "Conversion to double from cell is not possible."
This is most likely due to the structure type, the images are 'housed' in, but I have no idea concerning that.
Help on this would be greatly appreciated.

So to elaborate on my previous comments, here are a few things to change with your code:
C is not a structure but a cell array. The content of a cell array is access with {curly brackets}. If all your images are the same size, then it is more efficient to store them into a numeric array instead of a cell array. Since they seem to be logical images, your array would have 3 dimensions:
[height, width, numberofimages]
You could therefore start your code with:
myPath= 'E:\conduit_stl(smooth contour)\Collagen Contour Slices\'; %'
fileNames = dir(fullfile(myPath, '*.tif'));
%// if your images are of type uint8
C(height,width,length(fileNames)) = uint8(0);
C_filled = C; %// initialize new array to stored filled images
Also, since you are using the same structuring elements for your morphological operation on all the images, you can define it once outside the loop.
So your code could look like this:
se = strel('disk', 2, 0);
for k = 1:length(fileNames)
C(:,:,k) = imread(fileNames(k).name);
C_filled(:,:,k) = imfill(imclose(C(:,:,k), se),'holes');
end

Related

How can I find the size of an image?

I need the size of the image as a variable.
Here is what I tried:
a = dir('C:\example\Desktop\imagefolder\*.png');
numberofImages = length(a);
%sizeofimage?
matrix = zeros(numberofImages, sizeofimage);
How can I get the size of my image?
Maybe this will help. It will give you the size of each of the images in your folder.
a = dir('C:\example\Desktop\imagefolder\*.png');
numberofImages = length(a);
for i=1:numberofImages
img = imread(a(i).name);
sizeofImage{i} = size(img)
end
You can then access the sizes of the images using this notation:
sizeofImage{1}
Which will return something like this for an image 400x400:
ans =
400 400 3
You require an array of numbers to go into zeros, and size already provides you with one. Simply horzcat that (or use square brackets) with the number of images and you're done:
matrix = zeros([numberofImages, size(image)]);
Although I strongly suggest you to stop working on your project and start taking a class in MATLAB, read a book on it or take the MathWorks own tutorial, as this is about as basic as MATLAB gets. Since MATrix LABoratory is about matrices, size is important.

Importing Stack of Images

So I have the code to import a stack of images, but I am getting an error: Subscripted assignment dimension mismatch.
myPath = 'E:\folder name\'; %'
fileNames = dir(fullfile(myPath, '*.tif'));
width = 1400;
height = 1050;
nbImages = length(fileNames);
C=uint8(zeros(width, height, nbImages));
for i=1:length(fileNames)
C(:,:,i)=imread(cat(2,'E:\folder name\',fileNames(i).name));
i
end
I understand that the error is originating from the for loop, but I don't know of any other way to fill in an empty matrix with images.
Your images must not be all the same size. You can handle this by using explicit assignment for the first two dimensions. This will zero-pad any images which are smaller than the rest.
im = imread(...);
C(1:size(im, 1), 1:size(im, 2), i) = im;
Also, there is a good chance that your images have multiple color channels (the third dimension), so you'll likely want to concatenate along the fourth dimension rather than the third.
C(:,:,:,i) = imread(...)
Obviously it all depends what you want to do with the images, but in general, if you want a "stack" of images (or a "stack" of anything, really), then it sounds like you should be collecting them as a cell array instead.
Also, the correct way to create safe filenames is using the fullfile command
e.g.
C = cell(1, length(nbImages));
for i = 1 : length (fileNames)
C{i} = imread (fullfile ('E:','folder name', fileNames(i).name));
end
If you really want to concatenate to a 3D matrix from your cell array, assuming you have checked this is possible, you can do this very easily using comma-separated-list generator syntax:
My3DMatrix = cat(3, C{:});

Image blending with mask

I'm trying to combine the two images based on the information from the mask. I'm using the color information from the background image if the mask is 0 and color information from foreground image if the mask is 1. Because the mask and both
Images are of the same size, I would like to use logical indexing of matrices to achieve this.
My attempt:
mask = imread('mask.png');
foreground = imread('fg.jpg');
background = imread('bg.jpg');
[r,c,~]=size(mask);
A = zeros(size(mask));
for i=1:r
for j=1:c
if mask(i,j) == 0
A(i,j,:) = background(i,j,:);
end
if mask(i,j) > 0
A(i,j,:) = foreground(i,j,:);
end
end
end
imshow(A);
The result looks like a flickering blue image, but I don't want that. Please help.
You can do this a bit more concisely:
f = double(foreground).*double(mask);
b = double(background).*double(~mask);
blend = f+b;
imshow(blend, []);
Using logical indexing you could also do
foreground(logical(mask)) = 0;
background(logical(~mask)) = 0;
blend = foreground+background;
The ISNOT operator '~' inverts your matrix in the second line, so you cut out the area you would like for background.
NOTE: This works for black and white (one channel). For coloured images see rayryeng's solution.
There are two problems with your code. The first problem is that you are trying to assign colour pixels to the output image A, yet this image is only two-dimensional. You want an image with three channels, not two. In addition, the output image type you are specifying is wrong. By default, the output image A is of type double, yet you are copying values into it that aren't double... most likely unsigned 8-bit integer.
As such, cast the image to the same type as the input images. Assuming both input images are the same type, initialize your A so that:
A = zeros(size(foreground), class(foreground));
This correctly makes a colour image with the same type as any of the inputs, assuming that they're both the same type.
Now, your for loop is fine, but it's better if you do this in one shot with logical indexing. If you want to use logical indexing, create a new image that's initially blank like what you've done, but then make sure your mask has three channels to match the number of channels the other images have. After, you simply need to index into each image and set the right locations accordingly:
mask = imread('mask.png');
foreground = imread('fg.jpg');
background = imread('bg.jpg');
[r,c,d]=size(mask); %// Change
%// If your mask isn't three channels, make it so
%// Change
if d ~= 3
mask = cat(3, mask, mask, mask);
end
A = zeros(size(foreground), class(foreground)); %// Change
A(mask) = foreground(mask); %// Assign pixels to foreground
A(~mask) = background(~mask); %// Assign pixels to background
imshow(A);

Add two images in MATLAB

I am trying to overlay an activation map over a baseline vasculature image but I keep getting the same error below:
X and Y must have the same size and class or Y must be a scalar double.
I resized each to 400x400 so I thought it would work but no dice. Is there something I am missing? It is fairly straight forward for a GUI I am working on. Any help would be appreciated.
a=imread ('Vasculature.tif');
b = imresize (a, [400,400]);
c=imread ('activation.tif');
d= imresize (c, [400,400]);
e=imadd (b,d);
Could it be the bit depth or dpi?
I think one of your images is RGB (size(...,3)==3) and the other is grayscale (size(...,3)==1). Say the vasculature image a is grayscale and the activation image c is RGB. To convert a to RGB to match c, use ind2rgb, then add.
aRGB = ind2rgb(a,gray(256)); % assuming uint8
Alternatively, you could do aRGB = repmat(a,[1 1 3]);.
Or to put the activation image into grayscale:
cGray = rgb2gray(c);
Also, according to the documentation for imadd the two images must be:
nonsparse numeric arrays with the same size and class
To get the uint8 and uint16 images to match use the im2uint8 or im2uint16 functions to convert. Alternatively, just rescale and cast (e.g. b_uint8 = uint8(double(b)*255/65535);).
Note that in some versions of MATLAB there is a bug with displaying 16-bit images. The fix depends on whether the image is RGB or gray scale, and the platform (Windows vs. Linux). If you run into problems displaying 16-bit images, use imshow, which has the fix, or use the following code for integer data type images following image or imagesc:
function fixint16disp(img)
if any(strcmp(class(img),{'int16','uint16'}))
if size(img,3)==1,
colormap(gray(65535)); end
if ispc,
set(gcf,'Renderer','zbuffer'); end
end
chappjc's answers is just fine, I want to add a more general answer to the question how to solve the error message
X and Y must have the same size and class or Y must be a scalar double
General solving strategy
At which line does the error occur
Try to understand the error message
a. "... must have the same size ...":
Check the sizes of the input.
Try to understand the meaning of your code for the given (type of) input parameters. Is the error message reasonable?
What do you want to achieve?
Useful command: size A: returns the size of A
b. "... must have the same class ...":
Check the data types of the input arguments.
Which common data type is reasonable?
Convert it to the chosen data type.
Usefull command: whos A: returns all the meta information of A, i.e. size, data type, ...
Implement the solution: your favorite search engine and the matlab documentation are your best friend.
Be happy: you solved your problem and learned something new.
A simple code :
a=imread ('image1.jpg');
b=imresize (a, [400,400]);
subplot(3,1,1), imshow(b), title('image 1');
c=imread ('image2.jpg');
d= imresize (c, [400,400]);
subplot(3,1,2), imshow(d), title('image 2');
[x1, y1] = size(b) %height and wedth of 1st image
[x2, y2] = size(d) %height and wedth of 2nd image
for i = 1: x1
for j = 1: y1
im3(i, j)= b(i, j)+d(i, j);
end
end
subplot(3,1,3), imshow (im3), title('Resultant Image');

image processing

I have this set of images as shown, I found the centroid of each by using the code below, now I stored the new images in Im01,Im02,Im03, and they are all N by N matrix images.
Im1 = imread('image1.png');
[x,y] = ait_centroid(Im1);
Im01=circshift(Im1, [-1 -5]);
[x,y] = ait_centroid(Im01);
Im01=uint16(Im01);
Im2 = imread('image2.png');
[x,y] = ait_centroid(Im2);
Im02=circshift(Im2, [-2 -4]);
[x,y] = ait_centroid(Im02);
Im02=uint16(Im02);
Im3 = imread('image3.png');
[x,y] = ait_centroid(Im3);
Im03=circshift(Im3, [-3 -5]);
[x,y] = ait_centroid(Im03);
Im03=uint16(Im03);
my challenge is how to add this images using iteration cos i hav a large set of images(not jst the 3 images) im working on.I was able to add them manually n show the mean by doin this
G=imadd(Im01,Im02,'uint16');
G=imadd(G,Im03,'uint16');
imshow(uint8(G/3),[]);
and it worked.But when I tried iterating by doin this
G=imadd(Im01,Im02,'uint16');
for i=1:1:3
G=imadd(G,Im(i),'uint16');
end
I get error, I also tired to define the images as a matrix of a matrix by
H = [ [Im01] [Im02] [Im03] ]
G=imadd(Im01,Im02,'uint16');
for i=1:1:3
G=imadd(G,H(i),'uint16');
end
error indicates in H(i).
The code is in Matlab
H = [ [Im01] [Im02] [Im03] ] does not create an array of matrices in Matlab. Instead, it catenates the three images into a single array. What you want to do is create a cell array, i.e. the following will work:
%# curly brackets to construct cell array
H = {Im01, Im02, Im03 };
G=H{1}; %# initialize G
for i=2:1:3 %# start at img#2
G=imadd(G,H{i},'uint16');
end
Alternatively, if all you want to do with the images is to add them, you can do the following:
%# in case you want to store the images
images = cell(numberOfImages,1);
%# loop over all images
for iImg = 1:numberOfImages
tmp = imread(sprintf('image%i.png',iImg));
[x,y] = ait_centroid(tmp);
Im01=circshift(tmp, [x y]); %# I assume that's what you want?
[x,y] = ait_centroid(Im01); %# not sure what you do this for
if iImg ==1
G = uint16(tmp);
else
G = imadd(G,uint16(tmp));
end
%# maybe you want to store your images
images{iImg} = uint16(tmp);
end
You can use sprintf and eval to iterate over the names of your images.
G=imadd(Im01,Im02,'uint16');
for i=1:1:3
Im_name = sprinft('Im0%i',i);
G=imadd(G,eval(Im_name),'uint16');
end
The sprintf function will add the number i behind the string 'Im0', so you will first get Im01, then Im02, etc.. The eval function is needed to interpret these strings into Matlab varibales.
EDIT: I think the best way to avoid problems like this is to save your images in a cell from the beginning. That is, when reading in the images, read them into one cell
Im{1} = imread('Im01.xxx')
Im{2} = imread('Im02.xxx')
etc...
you can then easily iterate over the different images without using strings.

Resources