Unintended infinite loop with `imshow` - matlab

for i = [I, J, K];
imshow(i);
end
I, J, K are 16-bit images.
The script keeps trying to pump out the images (but doesn't) and gets into an infinite loop.
Is there something I'm missing?

You can store multiple images in a matrix if they have the same sizes.
However, You should store the images in a cell if they have different sizes. This method is less messier because you don't need to worry about how to extract them later.
define a cell with the size equal to the number of images.
numImages = 3;
Images = cell(1,numImage);
Store an image I into a cell:
Images{1,1} = I;
Now go over the images and show them
for ii = 1:3
imshow(Images{1,ii});
end
Example:
I = imread('cameraman.tif');
J = imread('peppers.png');
K = imread('snowflakes.png');
Images = cell(1,3);
Images{1,1} = I;
Images{1,2} = J;
Images{1,3} = K;
for ii=1:numel(Images)
figure;imshow(Images{1,ii});
end

For better understanding as to which point exactly you are missing/what is happening here: Using square brackets works like a concatenation here. So the line
i = [I, J, K] % separated with commas or spaces for horzcat
i = [I; J; K] % separated with semi-colons for vertcat
does the same as horzcat or vertcat:
i = horzcat(I, J, K);
i = vertcat(I, J, K);
Let's say I, J, K are 64x64 gray valued images. A (horizontal) concatenation will create a 64x192 matrix. The for loop will go through your matrix column-wise, which means it will extract a 64x1 vector 192-times (or much more often for larger images, which might feel like "infinite"). Displaying only a vector with imshow() won't show anything.
As already pointed out, using cells is a more flexible way to store images. When using arrays you have to handle each dimension (and this only works if your images are equal in size):
sizeImage = size(I); % assume all img are same size (as I)
numImages = 3; % needed for allocating array
% init array for imgs and fill images into array: e.g. 64x64x3
imageArray = zeros([sizeImage numImages]);
imageArray(:,:,1) = I; % :,: selects all elements of a dimension
imageArray(:,:,2) = J;
imageArray(:,:,3) = K;
for n = 1:numImages % iterate over image index
figure; imshow(imageArray(:,:,n)); % n = 1, 2 ... , numImages
end % is used for position in imageArray
Using the colon : when accessing arrays/cells selects all elements of a dimension. E.g. imageArray(:,:,n) will select all elements of first and second dimension, corresponding to a 64x64 image. For RGB images an array with 3 images will be 64x64x3x3 and you'll have to use imageArray(:,:,:,n) to select all three color channels.
Note that using for i = img_array won't work, as this will give vectors again.
E.g. for img_array: 64x64x5 (five 64x64 gray-valued images), this will iterate over all but one dimensions (and assign the remaining dim to i): img_array(:,1,1), img_array(:,2,1), img_array(:,3,1), ..., img_array(:,1,2), img_array(:,2,2) ..., img_array(:,64,5) and will again produce 64*3 = 192 vectors for i.
As was already pointed out, if you have variable image sizes, using cell arrays is the way. You may want to consult: Difference between cell and matrix in matlab?

Related

How can I modify a set of vectors to have the same size?

i'm trying to extract HOG_features for mathematical symbols classification (i will use SVM classifier). I get a 1xn vector then i have to put all the vectors in a single matrix. The problem is that the size of the feature vector is different for each image so I can't concatenate them.
Is there a way to make all vectors having the same size ?
Thank you in advance.
Here is the code:
rep1 = 'D:\mémoire MASTER\data';
ext = '*.tif' ;
chemin = fullfile(rep1, ext);
list = dir(chemin);
for i=1:length(list)
I = imread(fullfile(rep1, list(i).name), ext(3:end));
if size(I,3)==3 % RGB image
I = rgb2gray(I);
end
I1 = imbinarize(I);
% Extract HOG features data
HOG_feat = extractHOGFeatures(I1,'CellSize', [2 2]);
HOG_feat1 = HOG_feat';
end
You can pad each one with zeros to be as long as the longest one:
e.g. to put two vectors, v1 and v2, into a matrix M:
M = zeros(2,max(length(v1),length(v2)));
M(1,1:length(v1)) = v1;
M(2,1:length(v2)) = v2;
You have the problem that all your vectors are a different size. Instead of trying to coerce them to be the sesame size by zero-padding or interpolating (both I think are bad ideas), change your computation so that the length of the output vector does not depend on the size of the image.
This is your current code:
HOG_feat = extractHOGFeatures(I1,'CellSize', [2 2]);
% ^^^
% the image is split in cells of 2x2 pixels
2x2 cells are way too small for this method anyway. You could instead divide your image into a set number of cells, say 100 cells:
cellSize = ceil(size(I1)/10);
HOG_feat = extractHOGFeatures(I1,'CellSize', cellSize);
(I’m using ceil in the division because I figure it’s necessary to have an integer size. But I’m not sure whether ceil or floor or round is needed here, and I don’t have access to this function to test it. A bit of trial and error should show which method gives consistent output size.)

Matlab array as index for matrix

I have an image and a pixellist of several large objects in that image defined with regionprops. Now I want to generate a new image that only contains one object which is resized to the size of the object. So what I do is
rawimage = imread('testfile.tif');
processimage = squeeze((sum(rawimage,3))');
IMAGE_labeled = bwlabel(processimage,8);
shapedata=regionprops (IMAGE_labeled,'Area','PixelList');
index = find ([shapedata.Area]>5000);
for i = 1:length(index)
ix = shapedata(index(i)).PixelList(:,1);
iy = shapedata(index(i)).PixelList(:,2);
newimage = zeros(max(ix)-min(ix)+1,max(iy)-min(iy)+1,3);
for im = 1:length(ix)
newimage(ix(im)-min(ix)+1,iy(im)-min(iy)+1,:) = rawimage(ix(im),iy(im),:);
end
newimage = uint8(newimage);
imwrite(newimage,'myimage.tif','tif')
end
Has anyone an idea how I can vectorize the second for loop to speed the whole code up? In the end the question is how can I use two vectors as index in a matrix.
I found
Vc = num2cell([ix,iy])
rawimage(sub2ind(size(rawimage),Vc{i,:}))
but this again requires a for loop to go through all indices of Vc as I cannot use
rawimage(sub2ind(size(rawimage),Vc))
Thanks for your suggestions
Because your image has a third dimension, you'll need to reshape it a bit into an [M*N x 3] array first. You can then use sub2ind as you've shown.
for k = 1:numel(shapedata)
% Flip the PixelList so it's row/column rather than x/y
list = fliplr(shapedata(k).PixelList);
% Figure out the extents of the PixelList values
minima = min(list, [], 1);
maxima = max(list, [], 1);
% Grab a square of the image containing the object of interest
subimage = rawimage(minima(1):maxima(1), minima(2):maxima(2),:);
% Store the size
sz = size(subimage);
% Convert the PixelList values to linear indices within this sub-image
inds = sub2ind(sz(1:2), bsxfun(#minus, list, minima - 1));
% Reshape so that we can index into the first two dimensions at the same time
subimage = reshape(subimage, [], size(subimage, 3));
% Now create the output which is all zeros, but then we grab the values that are
% in PixelList and set them within the new matrix.
newimage = zeros(size(subimage));
newimage(inds,:) = subimage(inds,:);
% Reshape the result to be the expected dimension
newimage = reshape(newimage, sz);
end

How to reshape 3D derivatives matrices to 3x3xn matrix?

I have 3D derivatives of image Dxx,Dyx,Dyy,Dxz,Dzz,Dzy each of 513x512x200
where 512x512 are the images dimensions of 200 images.
Now i want to use eig3 that can take 3x3xn matrix
How can i reshape these matrices to a 3x3xn matrix ?
EDIT
n is supposed to be the number of voxels and the 3x3 matrix should be like
Dxx Dxy Dxz
Dyx Dyy Dyz
Daz Dzy Dzz
The manipulation of the matrices can be achieved by using 'permute' and 'reshape' as follows.
% say you saved your 2nd derivative 3D image as 'Ds'
Ds = [Dxx(:) Dxy(:) Dxz(:) Dyz(:) Dyy(:) Dyz(:) Dzz(:) Dzy(:) Dzz(:)];
% permute
Ds = permute(Ds,[2 1]);
% reshape
n = numel(Dxx);
Ds = reshape(Ds,[3 3 n]);
Enjoy!
Maybe you were looking for something like this -
%%// M and N are the dims of each image and P is the count of images.
%%// Please not that for 3x3 block processing, you would need to make sure that
%%// the width of images are divisble by 3; if they are not, consider cropping or padding.
IN = some_MxNxP_data;
%%// In-code cropping, as mentioned earlier
IN = IN(:,1:3*floor(size(IN,2)/3),:);
%%// Final output would be a complex matrix of size Mx(N/3)xP
OUT = zeros(size(IN,1),size(IN,2)/3);
%%// Main calculation part that uses block processing creating 3x3 blocks and using eig3 on each of them
for k = 1:size(IN,3)
fun1 = #(block_struct) eig3(block_struct.data);
OUT(:,:,k) = blockproc(double(IN(:,:,k)),[3 3],fun1);
end
Edit 1
Code
M = 7; %%// Image height, which must be replaced by actual data, 512 in your case
N = 7; %%// Image width, which must be replaced by actual data, 512 in your case
P = 5; %%// Number of images, which must be replaced by actual data, 200 in your case
%%// Your Dxx,Dyx... data, which is created randomly here, for demo
Dxx= rand(M,N,P);
Dyx= rand(M,N,P);
Daz= rand(M,N,P);
Dxy= rand(M,N,P);
Dyy= rand(M,N,P);
Dzy= rand(M,N,P);
Dxz= rand(M,N,P);
Dyz= rand(M,N,P);
Dzz= rand(M,N,P);
voxel_mat = zeros(3,3,M,N,P);
eig_mat = zeros(M,N,3);
for k0 = 1:P
for k1 = 1:M
for k2 = 1:N
voxel_mat(:,:,k1,k2,k0) = [Dxx(k1,k2,k0) Dxy(k1,k2,k0) Dxz(k1,k2,k0); ...
Dyx(k1,k2,k0) Dyy(k1,k2,k0) Dyz(k1,k2,k0); ...
Daz(k1,k2,k0) Dzy(k1,k2,k0) Dzz(k1,k2,k0)];
eig_mat(k1,k2,:,k0) = eig3(voxel_mat(:,:,k1,k2,k0));
end
end
end

Matlab matrix of images, size issue

I have a matrix of m.n images like the following:
images = zeros( m, n, height, width );
It means I have m.n images whose width and height is given. Then, in a for loop; I fill these images like:
for i=1:m
for j=1:n
images(i,j,:,:) = imread('imagePath');
end
end
Then, let's say I want to use the image (1,1):
image1 = images(1,1,:,:);
I expect this image1 to have size = (h,w). However, when I say:
size(image1)
I get the result:
(1,1,h,w)
Questions:
1.
Why I don't have the following result?
(h,w)
2.
How can I reconstruct my code to have my expected result?
You can use the squeeze function to do just that :)
image1 = squeeze(image1);
size(image1)
should give
(h,w)
It has to do with how matlab does indexing. When you say
image1 = images(1,1,:,:);
You're telling matlab you want a 4 dimensional array, with first and second dimensions of size 1.
Where as, if you had said:
junk = images(:,:,1,1);
size(junk)
> [m,n]
Matlab treats a matrix of size [m,n] the same as if it were of size [m,n,1] or [m,n,1,1]. Can't do that on the front, thus the need for squeeze as #Junuxx points out. An alternative approach is to do thing as follows:
images = zeros( height, width, m, n );
for i=1:m
for j=1:n
images(:,:,m,n) = imread('imagePath');
end
end
image1 = images(:,:,1,1);

please help me Assignment has more non-singleton rhs dimensions than non-singleton

I have the following error in my code
Assignment has more non-singleton rhs
dimensions than non-singleton
This is the code:
string =['d:\face\face\ffw' int2str(r) '_' int2str(Sel(nSelRow,t)) '.bmp'];
A = imread(string);
B = im2double(A);
Train_Dat(:,:,s)=B;
Update 1:
When I updated the code we got new error in the next row
my code
for r=1:Class_Num
for t=1:Class_Train_Num
%string=['e:\face_lib\feret_80\ff' int2str(r) '_' int2str(t) '.tif'];
string =['d:\face\face\ffw' int2str(r) '_' int2str(Sel(nSelRow,t)) '.bmp'];
A=imread(string);
B=im2double(A);
Train_Dat(:,:,:,s)=B;
Train_Dat_Vector(:,s)=B(:); %here new error Subscripted assignment dimension mismatch.
s=s+1;
end
Update 2:
my define for
nImgW = 40;
nImgH = 40;
nImgSize = nImgW*nImgH;
Train_Dat_Vector = zeros( nImgSize, Train_Num );
A=imread(string);
B=im2double(A);
Train_Dat(:,:,:,s)=B;
Train_Dat_Vector(:,s)=B(:);%here i want convert matrix to 40x40,Train_Num
s=s+1;
I think the problem is that B is most likely a 3-D RGB image, and you're trying to assign it to a single 2-D plane of your 3-D matrix Train_Dat. If you're trying to collect a set of 3-D images to use as training data, you will have to make Train_Dat either a 4-D matrix (if all of your images have the exact same dimensions) or a cell array (with one image per cell):
Example #1: a 4-D matrix...
nRows = 100; %# The number of rows in the images
nCols = 100; %# The number of columns in the images
nDepth = 3; %# The depth of the images (3 color planes for RGB images)
nImages = 5; %# The number of images you will use
Train_Dat = zeros(nRows,nCols,nDepth,nImages); %# Initialize to zeros
Train_Dat(:,:,:,1) = B; %# Assign B as the first image
If you want to use this option, but all of your images are not the same size, you will have to resize them all to a given size. One way to do this, if you have the Image Processing Toolbox, is to use the function IMRESIZE:
newSize = [40 40]; %# The new size the image will be
C = imresize(B,newSize); %# Resize image B
If you don't have access to the Image Processing Toolbox, one alternative is to use the function INTERP2 to resize your image. Here's one example of resizing a 3-D RGB image of type UINT8:
B = double(B); %# Convert B to double (needed to use INTERP2)
[nRows,nCols,nDepth] = size(B); %# Get the old image size
C = zeros(40,40,3,'uint8'); %# Initialize the new 3-D 40-by-40 uint8 image
xi = linspace(1,nCols,40); %# Create a down-sampled set of x points
yi = linspace(1,nRows,40); %# Create a down-sampled set of y points
[X,Y] = meshgrid(xi,yi); %# Create 40-by-40 grids of x and y points
C(:,:,1) = interp2(B(:,:,1),X,Y,'spline'); %# Interpolate the red color plane
C(:,:,2) = interp2(B(:,:,2),X,Y,'spline'); %# Interpolate the green color plane
C(:,:,3) = interp2(B(:,:,3),X,Y,'spline'); %# Interpolate the blue color plane
The image C will now be a down-sampled 40-by-40 version of B.
Example #2: a cell array...
nImages = 5; %# The number of images you will use
Train_Dat = cell(1,nImages); %# Initialize the cell array
Train_Dat{1} = B; %# Assign B as the first image
In this case, the images you add to each cell can be different sizes and types, so no resizing is needed.