How to form a vector from RGB matrices - matlab

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);

Related

Dimension of Filter in 3-D Convolution in MATLAB

The function to perform an N-dimensional convolution of arrays A and B in matlab is shown below:
C = convn(A,B) % returns the N-dimensional convolution of arrays A and B.
I am interested in a 3-D convolution with a Gaussian filter.
If A is a 3 x 5 x 6 matrix, what do the dimensions of B have to be?
The dimensions of B can be anything you want. There is no set restriction in terms of size. For the Gaussian filter, it can be 1D, 2D or 3D. In 1D, what will happen is that each row gets filtered independently. In 2D, what will happen is that each slice gets filtered independently. Finally, in 3D you will be doing what is expected in 3D convolution. I am assuming you would like a full 3D convolution, not just 1D or 2D.
You may be interested in the output size of convn. If you refer to the documentation, given the two N dimensional matrices, for each dimension k of the output and if nak is the size of dimension k for the matrix A and nbk is the size of dimension k for matrix B, the size of dimension of the output matrix C or nck is such that:
nck = max([nak + nbk - 1, nak, nbk])
nak + nbk - 1 is straight from convolution theory. The final output size of a dimension is simply the sum of the two sizes in dimension k subtracted by 1. However should this value be smaller than either of nak or nbk, we need to make sure that the output size is compatible so that any of the input matrices can fit in the final output. This is why you have the final output size and bounded by both A and B.
To make this easier, you can set the size of the filter guided by the standard deviation of the distribution. I would like to refer you to my previous Stack Overflow post: By which measures should I set the size of my Gaussian filter in MATLAB?
This determines what the output size of a Gaussian filter should be given a standard deviation.
In 2D, the dimensions of the filter are N x N, such that N = ceil(6*sigma + 1) with sigma being the desired standard deviation. Therefore, you would allocate a 3D matrix of size N x N x N with N = ceil(6*sigma + 1);.
Therefore, the code you would want to use to create a 3D Gaussian filter would be something like this:
% Example input
A = rand(3, 5, 6);
sigma = 0.5; % Example
% Find size of Gaussian filter
N = ceil(6*sigma + 1);
% Define grid of centered coordinates of size N x N x N
[X, Y, Z] = meshgrid(-N/2 : N/2);
% Compute Gaussian filter - note normalization step
B = exp(-(X.^2 + Y.^2 + Z.^2) / (2.0*sigma^2));
B = B / sum(B(:));
% Convolve
C = convn(A, B);
One final note is that if the filter you provide has any of its dimensions that are beyond the size of the input matrix A, you will get a matrix using the constraints of each nck value, but then the border elements will be zeroed due to zero-padding.

convert 3d matrix to 4d matrix using 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?

How to use logical conditions only for some dimensions in multidimensional arrays in MATLAB

Let us have a 4D matrix (tensor), output:
[X,Y,Z] = ndgrid(-50:55,-55:60,-50:60);
a = 1:4;
output = zeros([size(X),length(a)]);
Next, we determine the area inside the ellipsoid:
position = [0,0,0];
radius = [10,20,10];
test_func = #(X,Y,Z) ((X-position(1))/radius(1)).^2 ...
+ ((Y-position(2))/radius(2)).^2 ...
+ ((Z-position(3))/radius(3)).^2 <= 1;
condition = test_func(X,Y,Z);
I need to fill the matrix output inside the ellipsoid for the first 3 dimensions. But for the fourth dimension I need to fill a. I need to do something like this:
output(condition,:) = a;
But it does not work. How to do it? Any ideas please!
If I understand your question correctly, you have a 4D matrix where each temporal blob of pixels in 3D for each 4D slice is filled with a number... from 1 up to 4 where each number tells you which slice you're in.
You can cleverly use bsxfun and permute to help you accomplish this task:
output = bsxfun(#times, double(condition), permute(a, [1 4 3 2]));
This takes a bit of imagination to imagine how this works but it's quite simple. condition is a 3D array of logical values where each location in this 3D space is either 0 if it doesn't or 1 if it does belong to a point inside an ellipsoid. a is a row vector from 1 through 4 or however many elements you want this to end with. Let's call this N to be more general.
permute(a, [1 4 3 2]) shuffles the dimensions such that we create a 4D vector where we have 1 row, 1 column and 1 slice but we have 4 elements going into the fourth dimension.
By using bsxfun in this regard, it performs automatic broadcasting on two inputs where each dimension in the output array will match whichever of the two inputs had the largest value. The condition is that for each dimension independently, they should both match or one of them is a singleton dimension (i.e. 1).
Therefore for your particular example, condition will be 106 x 116 x 111 while the output of the permute operation will be 1 x 1 x 1 x N. condition is also technically 106 x 116 x 111 x 1 and using bsxfun, we would thus get an output array of size 106 x 116 x 111 x N. Performing the element-wise #times operation, the permuted vector a will thus broadcast itself over all dimensions where each 3D slice i will contain the value of i. The condition matrix will then duplicate itself over the fourth dimension so we have N copies of the condition matrix, and performing the element-wise multiply thus completes what you need. This is doable as the logical mask you created contains only 0s and 1s. By multiplying element-wise with this mask, only the values that are 1 will register a change. Specifically, if you multiply the values at these locations by any non-zero value, they will change to these non-zero values. Using this logic, you'd want to make these values a. It is important to note that I had to cast condition to double as bsxfun only allows two inputs of the same class / data type to be used.
To visually see that this is correct, I'll show scatter plots of each blob where the colour of each blob would denote what label in a it belongs to:
close all;
N = 4;
clrs = 'rgbm';
figure;
for ii = 1 : N
blob = output(:,:,:,ii);
subplot(2,2,ii);
plot3(X(blob == ii), Y(blob == ii), Z(blob == ii), [clrs(ii) '.']);
end
We get:
Notice that the spatial extent of each ellipsoid is the same but what is different are the colours assigned to each blob. I've made it such that the values for the first blob, or those assigned to a = 1 are red, those that are assigned to a = 2 are assigned to green, a = 3 to blue and finally a = 4 to magenta.
If you absolutely want to be sure that the coordinates of each blob are equal across all blobs, you can use find in each 3D blob individually and ensure that the non-zero indices are all equal:
inds = arrayfun(#(x) find(output(:,:,:,x)), a, 'un', 0);
all_equal = isequal(inds{:});
The code finds in each blob the column major indices of all non-zero locations in 3D. To know whether or not we got it right, each 3D blob should all contain the same non-zero column major indices. The arrayfun call goes through each 3D blob and returns a cell array where each cell element is the column major indices for a particular blob. We then pipe this into isequal to ensure that all of these column major indices arrays are equal. We get:
>> all_equal
all_equal =
1

MATLAB image patches around multiple coordinates (in vectors) without loops [duplicate]

I need to extract image patches of size s x s x 3 around specified 2D locations from an image (3 channels).
How can I do this efficiently without a for loop? I know I can extract one patch around (x,y) location as:
apatch = I(y-s/2:y+s/2, x-s/2:x+s/2, :)
How can I do this for many patches? I know I can use MATLAB's function blockproc but I can't specify the locations.
You can use im2col from the image processing toolbox to transform each pixel neighbourhood into a single column. The pixel neighbourhoods are selected such that each block is chose on a column-basis, which means that the blocks are constructed by traversing down the rows first, then proceeding to the next column and getting the neighbourhoods there.
You call im2col this way:
B = im2col(A, [M N]);
I'm assuming you'll want sliding / overlapping neighbourhoods and not distinct neighbourhoods, which are what is normally used when performing any kind of image filtering. A is your image and you want to find M x N pixel neighbourhoods transformed as columns. B would be the output where each neighbourhood is a single column and horizontally-tiled together. However, you'll probably want to handle the case where you want to grab pixel neighbourhoods along the borders of the image. In this case, you'll want to pad the image first. We're going to assume that M and N are odd to allow the padding to be easier. Specifically, you want to be sure that there are floor(M/2) rows padded on top of the image as well as the bottom as well as floor(N/2) columns padded to the left of the image as well as the right. As such, we should pad A first by using padarray. Let's assume that the border pixels will be replicated, which means that the padded rows and columns will simply be those grabbed from the top or bottom row, or the left and right column, depending on where we need to pad. Therefore:
Apad = padarray(A, floor([M N]/2), 'replicate');
For the next part, if you want to choose specify neighbourhoods, you can use sub2ind to convert your 2D co-ordinates into linear indices so you can select the right columns to get the right pixel blocks. However, because you have a colour image, you'll want to perform im2col on each colour channel. Unfortunately, im2col only works on grayscale images, and so you'd have to repeat this for each channel in your image.
As such, to get ready for patch sampling, do something like this:
B = arrayfun(#(x) im2col(Apad(:,:,x), [M N]), 1:size(A,3), 'uni', 0);
B = cat(3, B{:});
The above code will create a 3D version of im2col, where each 3D slice would be what im2col produces for each colour channel. Now, we can use sub2ind to convert your (x,y) co-ordinates into linear indices so that we can choose which pixel neighbourhoods we want. Therefore, assuming your positions are stored in vectors x and y, you would do something like this:
%// Generate linear indices
ind = sub2ind([size(A,1) size(A,2)], y, x);
%// Select neighbourhoods
%// Should be shaped as a MN x len(ind) x 3 matrix
neigh = B(:,ind,:);
%// Create cell arrays for each patch
patches = arrayfun(#(x) reshape(B(:,x,:), [M N 3]), 1:numel(ind), 'uni', 0);
patches will be a cell array where each element contains your desired patch at each location of (x,y) that you specify. Therefore, patches{1} would be the patch located at (x(1), y(1)), patches{2} would be the patch located at (x(2), y(2)), etc. For your copying and pasting pleasure, this is what we have:
%// Define image, M and N here
%//...
%//...
Apad = padarray(A, floor([M N]/2), 'replicate');
B = arrayfun(#(x) im2col(Apad(:,:,x), [M N]), 1:size(A,3), 'uni', 0);
B = cat(3, B{:});
ind = sub2ind([size(A,1) size(A,2)], y, x);
neigh = B(:,ind,:);
patches = arrayfun(#(x) reshape(neigh(:,x,:), [M N 3]), 1:numel(ind), 'uni', 0);
As unexpected as this may seem, but for me the naive for-loop is actually the fastest. This might depend on your version of MATLAB though, as with newer versions they keep on improving the JIT compiler.
Common data:
A = rand(30, 30, 3); % Image
I = [5,2,3,21,24]; % I = y
J = [3,7,5,20,22]; % J = x
s = 3; % Block size
Naive approach: (faster than im2col and arrayfun!)
Patches = cell(size(I));
steps = -(s-1)/2:(s-1)/2;
for k = 1:numel(Patches);
Patches{k} = A(I(k)+steps, ...
J(k)+steps, ...
:);
end
Approach using arrayfun: (slower than the loop)
steps = -(s-1)/2:(s-1)/2;
Patches = arrayfun(#(ii,jj) A(ii+steps,jj+steps,:), I, J, 'UniformOutput', false);

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) ) );