How to remove last n elements of a matrix in matlab? - matlab

I have a matrix of order 363 X 726. Now I wanted to remove last 1394 elements in column-major format so that I can rearrange it into 512 X 512 matrix using MATLAB. Simply put, I want to perform the reversal of the operations seen in my previous question: How to resize an image by adding extra pixels using matlab. How can I do this in MATLAB?

Assuming your matrix you want to operate on is called B, you could also just do B = reshape(B(1:512*512), 512, 512);. No need for a temporary variable and the removal of the last 1394 elements is implicit with the indexing.

A = rand(363,726); % matrix of random elements with size 363x726
A(end-1393:end)=[] ; % removing last 1394 elements
A = reshape(A,[512 512]); % Rearranging it into 512 rows and 512 columns

Related

Check if nxm block of 1s is inside binary matrix (Matlab)

I have a 90x89 binary matrix (I can't attach .mat files so I can't provide the matrix). In short, the 1s are good and 0s are bad. I want a quick way to check and return any nxm blocks of all 1s within the large matrix. For example, I want to find out if there are any 3x6 (n=3, m=6) blocks of all 1s within the binary matrix. If there are, return the row and col for each cell within each block.
To find your result, it helps to think of the matrix as an image.
An erosion is an image processing operation that returns the minimum value within a local neighborhood: for each pixel (matrix element) you look at all the values in a neighborhood (in your case this would be a 3x6 rectangle) an find the minimum. This is the value that you write to that pixel in the output image.
Now, if a matrix element is in the middle of a 3x6 block with all 1s, then the minimum is 1. If there is even a single 0 in there, the minimum will be 0. So, the output image will have 1s in the middle element of each 3x6 block of 1s.
If you have access to the Image Processing Toolbox, use the imerode function.
If you want to find the coordinates of all matrix elements within these blocks, you can convert the output of the erosion using a dilation. This is the inverse operation, and will set to 1 all the elements belonging to these 3x6 blocks.
For example:
% Create some test matrix (66% are 1s, so we have some chance of finding a 3x6 block):
a = randi([0,2], 100,100) > 0;
% Look for 3x6 blocks:
b = imerode(a, ones(3,6));
any(b(:)) % returns true, hopefully
nnz(b) % returned 2 for me, there's 2 of these blocks
% Find all pixels belong the these two blocks:
c = imdilate(b, ones(3,6));
nnz(c) % returned 2*18 for me, as expected
[row,col] = find(c); % Now [row(i),col(i)] are the indices to one of these pixels

Using a Matrix of Indices to Construct a SIFT Feature Vector in MATLAB

I am attempting to elegantly construct a SIFT feature descriptor as described in Lowe's paper in MATLAB. Most of the methods that I have seen have been rather messy, and I want to find an elegant way of doing this. I have my keypoints as interpolated (x,y) coordinates, and I have determined the gradient magnitude and orientation at all pixels in my image using:
[Gmag,Gdir]=imgradient(image)
I can easily find the 16x16 window of the gradient about each keypoint by slicing Gdir. I now need to build the histograms of each cell. I use the following code to get a bin number for each orientation/magnitude:
binned=discretize(local_Gdir,[-180:45:180])
binned is now a matrix of indices corresponding to the feature vector for each cell (it is filled with numbers 1-8; the indices of the binned correspond to the local gradient indices).
In order to build the 128 element feature descriptor, I need to determine the feature vectors (histograms) of the 16 cells. I have been trying to split the binned matrix into the 16 cells while preserving the indices so that I can quickly refer to the local gradient magnitude matrix to sum the gradients in each bin for each cell before appending them into the final descriptor, but I can't find a clean way to do this.
How can I use the matrix of indices to build the 16 feature vectors of the 16 cells? Perhaps more generally, what is a good way of splitting an index matrix into sixteen submatrices without losing the original row/column indices?
there are 16 number of 4 * 4 subwindow in the 16 * 16 window and all elements of the 16 * 16 window have values form 1 to 8 so fo each subwindow separately a histogram should be created. This means that in a loop the hist function 16 times should be called.
Instead we can add a number to each subwindow ,then values of each subwindow become different than other sub windows.
for example for the first subwindow we add 0 to the binned value so values range from 1 to 8.
for the second subwindow we add 8 to the binned value so values range from 9 to 16.
for the third window add 16 .....
Then only one time the hist function will be called and 128 values computed.
% exmaple of a 16 * 16 window
binned_16 = randi([1 8],16 ,16);
% the values to be added to each 16* 16 window ;this matrix only one time needs to be computed
values_to_add = kron(reshape((0 : 15), 4, 4)*8 , ones(4));
% values added to the window
binned_added_values = values_to_add + binned_16;
% histogram computed
h = hist(binned_added_values(:), 1:128);

Randomly select Elements of 4D matrix in Matlab

I have a 4D matrix with dimensions 7x4x24x10 (Lets call it main_mat). I want to get a matrix of size 7x4x24 (rand_mat) so that each element of this (rand_mat) matrix is actually a uniformly random draw from the main matrix (main_mat). I am sorry if I have not put the question clearly, so I try to explain:
I have a stack of 24 sheets of 7x4 elements, and I have 10 such stacks. What I want is that I get a single stack of 24 sheets of 7x4 elements in such a way that every element out of resultant single stack is uniformly randomly drawn from exactly same sheet number from within 10 stacks. How can I do it without using loops?
If I am interpreting what you want correctly, for each unique 3D position in this matrix of 7 x 4 x 24, you want to be sure that we randomly sample from one out of the 10 stacks that share the same 3D spatial position.
What I would recommend you do is generate random integers that are from 1 to 10 that is of size 7 x 4 x 24 long, then use sub2ind along with ndgrid. You can certainly use randi as you have alluded to in the comments.
We'd use ndgrid to generate a grid of 3D coordinates, then use the random integers we generated to access the fourth dimension. Given the fact that your 4D matrix is stored in A, do something like this:
rnd = randi(size(A,4), size(A,1), size(A,2), size(A,3));
[R,C,D] = ndgrid(1:size(A,1), 1:size(A,2), 1:size(A,3));
ind = sub2ind(size(A), R, C, D, rnd);
B = A(ind);
Bear in mind that the above code will work for any 4D matrix. The first line of code generates a 7 x 4 x 24 matrix of random integers between [1,10]. Next, we generate a 3D grid of spatial coordinates and then use sub2ind to generate column-major indices where we can sample from the matrix A in such a way where each unique 3D spatial location of the matrix A only samples from one chunk and only one chunk. We then use these column-major indices to sample from A to produce our output matrix B.
This problem might not be solvable without the use of loops. One way that could work is:
mainMatrix = ... (7x4x24x10 matrix)
randMatrix = zeros(mainMatrix(:,1,1,1), mainMatrix(1,:,1,1), mainMatrix(1,1,:,1))
for x = 1:length(mainMatrix(:,1,1,1))
for y = 1:length(mainMatrix(1,:,1,1))
for z = 1:length(mainMatrix(1,2,:,1))
randMatrix(x,y,z) = mainMatrix(x,y,z,randi(10))
end
end
end

Replace matrix values with mean values extracted from smaller matrix in MATLAB

Let's say I have a 10 x 10 matrix. What I do then is iterate through the whole matrix with an 3 x 3 matrix (except from the edges to make it easier), and from this 3 x 3 matrix I get the mean/average value of this 3 x 3 space. What I then want to do is to replace the original matrix values, with those new mean/average values.
Can someone please explain to me how I can do that? Some code examples would be appreciated.
What you're trying to do is called convolution. In MATLAB, you can do the following (read up more on convolution and how it's done in MATLAB).
conv2( myMatrix , ones(3)/9 , 'same' );
A little deciphering is in order. myMatrix is the matrix you're working on (the 10x10 one you mentioned). The ones(3)/9 command creates a so-called mask of filter kernel, which is
1/9 1/9 1/9
1/9 1/9 1/9
1/9 1/9 1/9
When you take this mask and move it around, multiplying value-by-value the mask's entries with 3x3 entries of the image and then add the results (dot product, essentially), the you get the average of the 9 values that ended up underneath this mask. So once you've placed this mask over every 3x3 segment of you matrix (image, I imagine) and replaced the value in the middle by the average, you get the result of that command. You're welcome to experiment with it further. The 'same' flag simply means that the matrix you're getting back is the same size as you original one. This is important because, as you've yourself realized, there are multiple ways of dealing with the edges.
To do this, you need to keep the original intact until you have got all the means. This means that if you implement this using a loop, you have to store the averages in different matrix. To get the borders too, the easiest way is to copy the original matrix to the new matrix, although only the borders are needed to be copied.
This average3x3 function copies the input Matrix to AveragedMatrix and then goes through all the elements that are not on any border, calculates the mean of 3x3 space and stores it in the corresponding element of AveragedMatrix.
function [AveragedMatrix] = average3x3(Matrix)
AveragedMatrix = Matrix;
if ((size(Matrix, 1) < 3) || (size(Matrix, 2) < 3))
fprintf('Matrix is too small, minimum matrix size is 3x3.\n');
return
end
for RowIndex = 2:(size(Matrix, 1)-1)
Rows = RowIndex-1:RowIndex+1;
for ColIndex = 2:(size(Matrix, 2)-1)
Columns = ColIndex-1:ColIndex+1;
AveragedMatrix(RowIndex,ColIndex) = mean(mean(Matrix(Rows,Columns)));
end
end
return
To use this function, you can try:
A = randi(10,10);
AveragedA = average3x3(A);

Matlab : 256 binary matrices to one 256 levels grayscale image

a process of mine produces 256 binary (logical) matrices, one for each level of a grayscale source image.
Here is the code :
so = imread('bio_sd.bmp');
co = rgb2gray(so);
for l = 1:256
bw = (co == l); % Binary image from level l of original image
be = ordfilt2(bw, 1, ones(3, 3)); % Convolution filter
bl(int16(l)) = {bwlabel(be, 8)}; % Component labelling
end
I obtain a cell array of 256 binary images. Such a binary image contains 1s if the source-image pixel at that location has the same level as the index of the binary image.
ie. the binary image bl{12} contains 1s where the source image has pixels with the level 12.
I'd like to create new image by combining the 256 binary matrices back to a grayscale image.
But i'm very new to Matlab and i wonder if someone can help me to code it :)
ps : i'm using matlab R2010a student edition.
this whole answer only applies to the original form of the question.
Lets assume you can get all your binary matrices together into a big n-by-m-by-256 matrix binaryimage(x,y,greyvalue). Then you can calculate your final image as
newimage=sum(bsxfun(#times,binaryimage,reshape(0:255,1,1,[])),3)
The magic here is done by bsxfun, which multiplies the 3D (n x m x 256) binaryimage with the 1 x 1 x 256 vector containing the grey values 0...255. This produces a 3D image where for fixed x and y, the vector (y,x,:) contains many zeros and (for the one grey value G where the binary image contained a 1) it contains the value G. So now you only need to sum over this third dimension to get a n x m image.
Update
To test that this works correctly, lets go the other way first:
fullimage=floor(rand(100,200)*256);
figure;imshow(fullimage,[0 255]);
is a random greyscale image. You can calculate the 256 binary matrices like this:
binaryimage=false([size(fullimage) 256]);
for i=1:size(fullimage,1)
for j=1:size(fullimage,2)
binaryimage(i,j,fullimage(i,j)+1)=true;
end
end
We can now apply the solution I gave above
newimage=sum(bsxfun(#times,binaryimage,reshape(0:255,1,1,[])),3);
and verify that I returns the original image:
all(newimage(:)==fullimage(:))
which gives 1 (true) :-).
Update 2
You now mention that your binary images are in a cell array, I assume binimg{1:256}, with each cell containing an n x m binary array. If you can it probably makes sense to change the code that produces this data to create the 3D binary array I use above - cells are mostly usefull if different cells contain data of different types, shapes or sizes.
If there are good reasons to stick with a cell array, you can convert it to a 3D array using
binaryimage = reshape(cell2mat(reshape(binimg,1,256)),n,m,256);
with n and m as used above. The inner reshape is not necessary if you already have size(binimg)==[1 256]. So to sum it up, you need to use your cell array binimg to calculate the 3D matrix binaryimage, which you can then use to calculate the newimage that you are interested in using the code at the very beginning of my answer.
Hope this helps...
What your code does...
I thought it may be best to first go through what the code you posted is actually doing, since there are a couple of inconsistencies. I'll go through each line in your loop:
bw = (co == l);
This simply creates a binary matrix bw with ones where your grayscale image co has a pixel intensity equal to the loop value l. I notice that you loop from 1 to 256, and this strikes me as odd. Typically, images loaded into MATLAB will be an unsigned 8-bit integer type, meaning that the grayscale values will span the range 0 to 255. In such a case, the last binary matrix bw that you compute when l = 256 will always contain all zeroes. Also, you don't do any processing for pixels with a grayscale level of 0. From your subsequent processing, I'm guessing you purposefully want to ignore grayscale values of 0, in which case you probably only need to loop from 1 to 255.
be = ordfilt2(bw, 1, ones(3, 3));
What you are essentially doing here with ORDFILT2 is performing a binary erosion operation. Any values of 1 in bw that have a 0 as one of their 8 neighbors will be set to 0, causing islands of ones to erode (i.e. shrink in size). Small islands of ones will disappear, leaving only the larger clusters of contiguous pixels with the same grayscale level.
bl(int16(l)) = {bwlabel(be, 8)};
Here's where you may be having some misunderstandings. Firstly, the matrices in bl are not logical matrices. In your example, the function BWLABEL will find clusters of 8-connected ones. The first cluster found will have its elements labeled as 1 in the output image, the second cluster found will have its elements labeled as 2, etc. The matrices will therefore contain positive integer values, with 0 representing the background.
Secondly, are you going to use these labeled clusters for anything? There may be further processing you do for which you need to identify separate clusters at a given grayscale intensity level, but with regard to creating a grayscale image from the elements in bl, the specific label value is unnecessary. You only need to identify zero versus non-zero values, so if you aren't using bl for anything else I would suggest that you just save the individual values of be in a cell array and use them to recreate a grayscale image.
Now, onto the answer...
A very simple solution is to concatenate your cell array of images into a 3-D matrix using the function CAT, then use the function MAX to find the indices where the non-zero values occur along the third dimension (which corresponds to the grayscale value from the original image). For a given pixel, if there is no non-zero value found along the third dimension (i.e. it is all zeroes) then we can assume the pixel value should be 0. However, the index for that pixel returned by MAX will default to 1, so you have to use the maximum value as a logical index to set the pixel to 0:
[maxValue,grayImage] = max(cat(3,bl{:}),[],3);
grayImage(~maxValue) = 0;
Note that for the purposes of displaying or saving the image you may want to change the type of the resulting image grayImage to an unsigned 8-bit integer type, like so:
grayImage = uint8(grayImage);
The simplest solution would be to iterate through each of your logical matrices in turn, multiply it by its corresponding weight, and accumulate into an output matrix which will represent your final image.