convert 3d matrix to 4d matrix using matlab - matlab

I have 2D matrixs of dimensions 400 x 500,each of these matrixs show an image. my process contain 2 steps:
1) I have to partition these images (split matrix to equal sized sub-matrices)
2) I have to save each of these split in one matrix
first step is done and dimention of matrix change from 2D-->3D (the last index shows index of splits)
now for the step 2 I have 100 images and I want to have matrix with 4 dimensions which the last index show the number of images
sample : for accessing split 3 of image 40 : [:,:,3,40]
I already try to using permut and reshape but not successful
here is my code
nCol = 10;
nRow = 4;
K=dir(p);
Len=length(K);
for i=3:Len
x1=imread(strcat(p,'\',K(i).name));
[m,n,d1]=size(x1);
if d1==1
x=double(x1);
else
x=double(rgb2gray(x1));
end
x=imresize(x,NN);
%% determined width and height of divided matrix %%%%%%%%%%%%%%%%%%%%%%%%%%
m = size(x,1)/nRow;
n = size(x,2)/nCol;
T = permute(reshape(permute(reshape(x, size(x, 1), n, []), [2 1 3]), n, m, []), [2 1 3]);
Im=[Im T(:,:,:,i-2)];
end
any idea would be appreciated.

reshape picks elements in column major ordering so you might have to write convoluted code to get it to work. Rather than going the way of using permute and reshape to create 4D matrices and potentially running into an out of memory issue I would advice the use of mat2cell to split your matrix into a cell array because mat2cell splits a matrix like you would want to split an image.
Here I show an example with an image
RGB = imread('peppers.png');
x = rgb2gray(RGB); % x is a 384 x 512 matrix, we want to split in 3 rows and 2 columns
x2 = mat2cell(x,384*ones(3,1)/3,512*ones(2,1)/2); % 2D cell array, each cell holds a part of the image
imshow(x2{1,1}) % Top left part of the image
You could loop over all your images and create a 3D cell array where each layer in the array represents each image split into pieces. I would suggest to preallocate you array and assign the matrix in the correct layer within the loop rather than incrementally increasing the size of your matrix.
Also there seems to be an Image processing toolbox specific function to do what you are trying to : Check this : How to divide an image into blocks in MATLAB?

Related

How can we reshape a matrix into a matrix of matrices

I have a 10*1300 matrix where each block of 10*10 values is an image. We can say that we have 130 images in a row. I want to rearrange this matrix so that I get all these images rearranged in 13 rows and 10 columns, where each (row,col) location is a 10*10 image. How can this be done? Thanks in advance.
Example:
I have a 10*1300 matrix where row=1:10 and col=1:10 represents the
first image, row=1:10 and col=11:20 represents the second image and so
on. Therefore we have 130 images arranged side by side horizontally. I want to arrange these 130 images in such a way that first 10 images are arranged in first horizontal pane,next 10 images are arranged in a second horizontal pane and so on, thus getting 13 horizontal panes with 10 images in each pane.
You can do this with a combination of reshape and permute:
blk_size = 10; % # of rows/columns in each block
blks_in_row = 10;
% reshape M matrix -> output in N
% you should first check that the dimensions of M are correct
N = reshape(M, blk_size, blk_size*blks_in_row, []);
N = permute(N, [1 3 2]);
N = reshape(N, [], blk_size*blks_in_row);
You can combine these three lines into one if you wish, but I expanded them out to give a better idea of what's going on.
The first line makes a 3D array with each 10x100 row of the output matrix is a plane. The second line permutes this matrix so that the planes become columns, and the third reshapes to a 2D array.
You can use this code to rearrange your matrix:
% suppose image is a defined matrix which is 10x1300
rearranged = [];
for i = 0:12
startIndex = 100 * i + 1;
endIndex = startIndex + 100 - 1;
rearranged = [rearranged; image(:, startIndex:endIndex)];
end
the rearranged matrix is what you want.

Sample 1D vectors from 3D array using a vector of points

I have a n channel image and I have a 100x2 matrix of points (in my case n is 20 but perhaps it is more clear to think of this as a 3 channel image). I need to sample the image at each point and get an nx100 array of these image points.
I know how to do this with a for loop:
for j = 1:100
samples(j,:) = image(points(j,1),points(j,2),:);
end
How would I vectorize this? I have tried
samples = image(points);
but this gives 200 samples of 20 channels. And if I try
samples = image(points,:);
this gives me 200 samples of 4800 channels. Even
samples = image(points(:,1),points(:,2));
gives me 100 x 100 samples of 20 (one for each possible combination of x in X and y in Y)
A concise way to do this would be to reshape your image so that you force your image that was [nRows, nCols, nChannels] to be [nRows*nCols, nChannels]. Then you can convert your points array into a linear index (using sub2ind) which will correspond to the new "combined" row index. Then to grab all channels, you can simply use the colon operator (:) for the second dimension which now represents the channels.
% Determine the new row index that will correspond to each point after we reshape it
sz = size(image);
inds = sub2ind(sz([1, 2]), points(:,2), points(:,1));
% Do the reshaping (i.e. flatten the first two dimensions)
reshaped_image = reshape(image, [], size(image, 3));
% Grab the pixels (rows) that we care about for all channels
newimage = reshaped_image(inds, :);
size(newimage)
100 20
Now you have the image sampled at the points you wanted for all channels.

How to form a vector from RGB matrices

I have a problem in constructing a vector from an image. I had used a 512 x 512 colour image and separated the rgb planes. Now i want to convert these three planes into three 1D vectors which should be as given in the following example.
Consider a 4x4x3 matrix. Converting it into RGB planes is easy. Now I need to convert these three planes into 1D vectors as given below
V=[r1g1b1....r6]
W=[g6b6r7...g11]
X=[b11r12...B16]
The program ive written is as follows. I used the reshape function to convert RGB planes into 1D vectors. Now I have trouble in regrouping them into different vectors.
A=imread('C:\Users\Desktop\lena.jpg');
% Extract the individual red, green, and blue color channels.
R = A(:, :, 1);
G = A(:, :, 2);
B = A(:, :, 3);
R1 = reshape(R.',1,[]);
G1 = reshape(G.',1,[]);
B1 = reshape(B.',1,[]);
I had converted the 2D matrices R G and B into 1D vectors R1, G1 and B1. Now I just need to create new vectores with all three values.I have no idea how to proceed...Please do help...Thanks in advance.
OK, given your example, what you want to do is given a RGB image, you want to separate the image into 3 vectors such that the RGB components are interleaved. This can easily be achieved by a permutation of the dimensions first. What you can do specifically is:
B = permute(A, [3 1 2]);
What permute does is that it rearranges the dimensions so that it produces another matrix. Specifically, what we're going to do is we are going to take each value in the third dimension and make them appear in the first dimension. Next we will take the rows of A and make them unroll into the columns, and finally the columns of A and make them go over each plane.
The result is that each column will be a unique RGB pixel that describes your image. How the unrolling will work though is that it will go in column-major order. We can then use linear indexing to split them up into arrays like so:
N = numel(A)/3;
V = B(1 : N);
W = B(N + 1 : 2*N);
X = B(2*N + 1 : end);
The job of linear indexing is that you access elements using a single index, rather than indexing each dimension separately. How linear indexing would work here is that if we had an image that was X x Y x 3, after permutation, the image would be reshaped such that it became a 3 x X x Y matrix. N in our case would be the total number of elements in a single plane. Because you are trying to split up the image into 3 vectors, the above operation where it's calculating N should be able to evenly divide by 3 as we have three colour planes to deal with.
By doing B(1 : N), we would access all of the elements from the first slice, second slice, in column-major format up until we retrieve N elements. These get placed into V. We then continue from this point and grab N more elements and place them into W, and finally the rest go into X.
If you want to access the pixels in row-major order, you simply need to change the way permute is accessing the dimensions like so:
B = permute(A, [3 2 1]);
You would then just access the elements with the above code normally. If you don't want to use linear indexing, you could use reshape to reshape the matrix such that it becomes a three-column matrix, where each column would be the desired vector:
C = reshape(B, [], 3);
V = C(:,1);
W = C(:,2);
X = C(:,3);
From your 4x4x3 example it's clear that you want to index first with the color index. I assume you then want row and then column. In that case, if A is your image (3D array), your desired three vectors are the columns of
B = reshape(permute(A,[3 1 2]),[],3);
So, if you need those vectors as explicit variables,
vector1 = B(:,1);
vector2 = B(:,2);
vector3 = B(:,3);
If the desired index order is color, then column, then row, use
B = reshape(permute(A,[3 2 1]),[],3);

How to access particular matrix element for all blocks in entire image?

I have a 512x512 image , which i made 4x4 block for entire image, then i want access the (3rd row , 3rd element) of the all indivial 4x4 matrices and add it to the index values, which i obtained. Please help me on below code.
[row col] = size(a);
m = zeros(row,col);
count = [(row-4)*(col-4)]/4;
outMat = zeros(4,4,count);
l = 0;
for i=2:4:row-4
for j=2:4:col-4
l = l + 1;
outMat(:,:,l) = double(a(i-1:i+2,j-1:j+2));% for each matrix i have to find(3rd row,3rd element of each matrix.
end;
end;
Adding the (3rd row,3rd element):
m(i,j) = sum(sum(a .* w)); %index value of each 4x4 matrix % w = 4x4 matrix.
LUT = m(i,j)+ outMat(3,3);%(3rd row,3rd element each matrix should be added to all m(i,j) values. In which i fail to add all(3rd row,3rd element) of all 4x4 matrices.
I am going to reword your question so that it's easier to understand, as well as allowing it to be easy for me to write an answer.
From your comments in Kostya's post, you have two images img1 and img2 where they are decomposed into 4 x 4 blocks. outMat would be a 3D matrix where each slice contains a 4 x 4 block extracted from img1. From this, you have a matrix m that stores a weighted sum of 4 x 4 blocks stored outMat.
Next, you'll have another matrix, let's call this outMat2, which also is a 3D matrix where each slice is a 4 x 4 block extracted from img2. From this 3D matrix, you wish to extract the third row and third column of each block, add this to the corresponding position of m and store the output into a variable called LUT.
All you have to do is extract a single vector that slices through all of the slices located at the third row and third column. You would then have to reshape this into a matrix that is the same size as m then add this on top of m and store it into a variable called LUT. Bear in mind that if we reshape this into a matrix, the reshaping will be done in column major format, and so you would stack the values by columns. Because your blocks were created row-wise, what we need to do reshape this matrix so that it has size(m,2) rows and size(m,1) columns then transpose it.
Therefore:
vec = outMat2(3,3,:);
vec = vec(:); %// Make sure it's a 1D vector
m2 = reshape(vec, size(m,2), size(m,1)).';
LUT = m + m2;
LUT will contain a 2D matrix where each element contains the weighted sum of the 4 x 4 blocks from img1 with the corresponding third row, third column of each block in img2.
Next time, please update your question so that you have all of the information. We shouldn't have to dig through your comments to figure out what you want.
I think you can do just
LUT = sum( sum( a(3:4:row,3:4,col) * w(3,3) ) );

MATLAB Average Every 5 Elements

I want to take a large matrix and take the average of all 5x5 grids in it.
The matrix is 245x85x1255.I reshaped the matrix into a 5x4165x1255 size (the z dimension is not that important) and I want to take the average of elements 1:5, 5:10, 10:15 etc in each row. And then, with the resulting matrix, I want to average the five columns. Then I'll resize it back to it's original shape (but smaller of course).
I don't have to do it this way. I just need to take a 5x5 grid and average all the points in it. Then I take the next 5x5 grid next to it and average all those points.
Here's how I did it for the first 5x5 grid:
A = data_SpecificArea(:,1:5,:);
B = mean(A,2);
C = mean(B,1);
** Here's the working code using blockproc
% Change dataAll_SpecificArea to a 1x1 degree grid (5x5 block averaging)
fun = #(block_struct) mean(block_struct.data);
A = blockproc(dataAll_SpecificArea,[5 1],fun); % Size goes from 245x85x1255 to 49x85x1255
B = blockproc(A,[1 5],fun); % Size is 49x17x1255
You can use blockproc for that. For example,
fun = #(block_struct) mean(block_struct.data);
new_matrix = blockproc(old_matrix,[5 5],fun);