Implementing convolution as a matrix multiplication - matlab

Pithy: Help with Matlab script that takes ImageData array and Convolution weights from Caffe and returns convolution. Please.
I am trying to recreate a convolution generated by Caffe in Matlab.
Let's make the following definitions
W**2 = Size of input
F**2 = Size of filter
P = Size of padding
S = Stride
K = Number of filters
The following text describes how to generalize the convolution as a matrix multiplication:
The local regions in the input image are stretched out into columns in an operation commonly called im2col. For example, if the input is [227x227x3] and it is to be convolved with 11x11x3 filters at stride 4, then we would take [11x11x3] blocks of pixels in the input and stretch each block into a column vector of size 11*11*3 = 363. Iterating this process in the input at stride of 4 gives (227-11)/4+1 = 55 locations along both width and height, leading to an output matrix X_col of im2col of size [363 x 3025], where every column is a stretched out receptive field and there are 55*55 = 3025 of them in total. Note that since the receptive fields overlap, every number in the input volume may be duplicated in multiple distinct columns.
From this, one could draw the conclusion that the im2col function call would look something like this:
input = im2col( input, [3*F*F, ((W-F)/S+1)**2)])
However, if I use the following parameter-values
W = 5
F = 3
P = 1
S = 2
K = 2
I get the following dimensions
>> size(input)
ans =
1 3 5 5
>> size(output)
ans =
1 2 3 3
>> size(filter)
ans =
2 3 3 3
And if I use the im2col function call from above, I end up with an empty matrix.
If I change the stride to 1 in the above example, the size of the input, the output and the filter remains the same. If I use Matlab's 'convn' command, the size is not the same as the actual output from Caffe.
>> size(convn(input,filter))
ans =
2 5 7 7
What would be the general way to resize your array for matrix multiplication?

You are using the second argument to im2col wrong, see the documentation.
You should give it the size of the filter window that you are trying to slide over the image, i.e.:
cols = im2col( input, [F, F])

Related

Construct single column matrix from the rows of another matrix with multiple columns in Matlab [duplicate]

This question already has answers here:
rgb to ycbcr conversion in matlab
(2 answers)
Closed 4 years ago.
I'm learning about image processing, and currently translating between RGB and YCbCr.
Basically, I have a nxmx3 matrix, which represents the brightness of each colour (RGB), and the operation to change this to Y,Cb, and Cr would be something like this:
for each row, index, in RGBMatrix:
y[index] = row[0] + row[1] + row[2]
So each row of y has one value, and that value is based on the values in the same in RGBMatrix.
I've tried the following in MATLAB:
function [y,Cb, Cr] = rgbToYCbCr(r,g,b)
signalSize = size(r);
y = zeros(signalSize);
for i = 1:signalSize(1)
for j = 1:signalSize(2)
y(i,j,1) = (0.299 * r(i,j,1)) + (0.587 * g(i,j,2)) + (0.114 * b(i,j,3));
end
end
end
However, this does not give me the results that I want as y now has the same dimensions as the RGBMatrix, when instead it should be 1 column.
How can I do this efficiently in MATLAB?
I know there is an inbuilt function for RGB to YCbCr, but for the sake of learning I'd like to implement it myself.
Example:
RGB Matrix:
R G B
[[0.5,0.5,0.5],
[0.2,0.1,0.6],
[0.1,0.4,0.7]]
Y Matrix:
[[0.5+0.5+0.5],
[-0.2-0.1+0.6],
[0.1+0.4-0.7]]
or
[[1.5],
[0.3],
[-0.2]]
Ignore the fact that values aren't realistic, what I'm more concerned about is carrying out an operation per row like I've described in Matlab without using the (typically) slower iterative way (with a for loop).
In reality I have a 1080x768x3 array. Each element in the 1080x768 dimension has a value for each colour (R,G,B) and I want to convert this to (Y,Cb,Cr) eventually.
If you have an RGB image, Imgrgb that is NxMx3 in size, do:
Imgrgb= imread('peppers.png'); % A sample RGB image
% make sure you have a double image range [0-1], you may not need this.
Imgrgb=im2double(Imgrgb);
r=Imgrgb(:,:,1);
g=Imgrgb(:,:,2);
b=Imgrgb(:,:,3);
y = (0.299 * r) + (0.587 * g) + (0.114 * b);
Cb=
Cr=
% concatenate result:
ImgYCbCr=cat(3,y,Cb,Cr);
And y shoudl be NxM, the same as r,g, and b. Do the same for the other 2 values with their corresponding equation.
If your matrix is like:
A =
1 3 5
2 4 6
then you may "flatten" it to a vector like:
>>Av = A(:)
Av =
1
2
3
4
5
6
I.e. it takes the values from the matrix in a row order and converts to a vector.
To convert it back to a matrix you may use the reshape function
>> reshape(Av,[2 3])
ans =
1 3 5
2 4 6
The A(:) method is equivalent to reshape(A,[numel(A) 1])

Split matrix into non-overlapping submatrices

I have an image of any size that I need to split into non-overlapping regions of 15x15 pixels. Previously I looked this up and used the following code:
newIm = rand(size(im2, 1),size(im2, 2));
subIm = mat2cell(newIm, 15*ones(size(newIm,1)/15,1), 15*ones(size(newIm,2)/15,1));
My problem is that I may not always be able to split the matrix into nice 15x15 regions. How can I fix this? Also, can you explain what exactly happens? I'd like to understand Matlab better for future use!
If you use the above code with a size not perfectly divisible by 15 (say 160), you will get the following error in MATLAB:
Input arguments, D1 through D2, must sum to each dimension of the input matrix size, [160 160].'
So you have to make your second and third input arguments of mat2cell sum to 160. Then you are done.
Code taken from here
blockSize=[15 15];
wholeBlockRows = floor(size(newIm,1)/ blockSize(1));
blockVectorR = [blockSize(1) * ones(1, wholeBlockRows), rem(size(newIm,1), blockSize(1))];
wholeBlockCols = floor(size(newIm,2)/ blockSize(2));
blockVectorC = [blockSize(2) * ones(1, wholeBlockCols), rem(size(newIm,2), blockSize(2))];
% sum of blockVectorR and blockVectorC will be equal to size(newIm,1) and
% size(newIm,2) respectively.
ca = mat2cell(newIm, blockVectorR, blockVectorC, size(newIm,3));
In your output cell array, you will see sub-images in the last row and column where either rows or columns (or both) are equal to: rem(size(newIm,1), blockSize(1)) or (and) rem(size(newIm,2), blockSize(2))

Matlab complex matrix magnitude

I have a matrix S something like:
1 4 7
2 5 8
3 6 9
Then I make a=complex(S{2},S{3}) and wanted to find the abs(a);. This is not possible in MATLAB as a is not an integer - it is a matrix. How can I get the magnitude of each row of matrix a?
PS: the matrix is read from a text file using textscan() as S = textscan(fileID,'%d %d %d', 'delimiter','\t');.
Second question:
Assuming again hav the following S matrix.
1 4 7 2 1
2 5 8 3 4
3 6 9 6 8
Now I wanted to arrange them in such way that column 2,3 and 4,5 alternate like this:
4 2
7 1
5 3
8 4
6 6
9 8
How can I do that without using a loop?
Thanks.
Going with my assumption in the comments, I'm going to assume that the second column consists of your real component of your matrix while the third column consists of your imaginary components. Your matrix S is actually a cell array of elements. You don't need to use complex then abs. You can simply take each of the columns, individually square them, add them together and take the square root. What I would do is convert the cell array into a 2D matrix, cast it to double to allow for floating point precision when finding the magnitude, and do what I just did above. This is necessary because abs and sqrt will only work for floating-point numbers. Your elements in S are already int32 due to the %d delimiter from textread. In other words:
Smat = double(cell2mat(S));
realComp = Smat(:,2);
imagComp = Smat(:,3);
mag = sqrt(realComp.^2 + imagComp.^2);
mag will thus return the magnitude of each row for you, assuming that the second column is the real component and the third component is the imaginary component as we specified.
However, if you're dead set on using complex and abs, you can do it like so:
Smat = double(cell2mat(S));
imagNumbers = complex(Smat(:,2), Smat(:,3));
mag = abs(imagNumbers);
This should still give you the same results as we talked about above.
Edit
Seeing your edit in your post above, we can achieve that quite easily by subsetting the matrix, then applying reshape to each part of the matrix you want. In other words:
Smat = double(cell2mat(S));
realMat = Smat(:,2:3); %// Grab second and third columns
imagMat = Smat(:,4:5); %// Grab fourth and fifth columns
realCol = reshape(realMat.', [], 1); % // Form the columns like you specified
imagCol = reshape(imagMat.', [], 1);
finalMatrix = [realCol imagCol];
finalMatrix should contain those two columns that you specified above in a single matrix.

Combination of two convolution filters

What is one filter matrix equivalent to applying [1 1 1] twice on an image using imfilter with parameter 'full'? Would it still be a 1x3 matrix?
convolution is associative, which means (f*g)*h = f*(g*h). So instead of
r = conv(conv(x, [1,1,1]), [1,1,1])
you can precompute the convolution of the two filters and then apply it to each image only once:
tmp_filter = conv([1,1,1], [1,1,1]);
...
r1 = conv(x1, tmp_filter)
r2 = conv(x2, tmp_filter)
where the new filter is [1 2 3 2 1], which however is not of the same size of the original filter.
The full parameter tells the filter function to return an image of the same size of the filtered image. You can apply the same filter any amount of times, but if you use full every time, the size should not change.

What kind of matrix is in Matlab: "W = ones(1:numEntries); "?

One simple question..
Let's suppose in Matlab we have a variable: numEntries = 8
I know "ones" is used to create "1's matrixes" but what's the result of the following?
W = ones(1:numEntries);
And,if possible,where I can find a good reference about matrixes in Matlab? I looked in official documentation but it is not so clear to me.
Thank you very much
ones creates a matrix of ones. ones works for any number of dimensions, however if you specify only one argument, you'll get a square matrix of ones of that size. Otherwise, you'll get a N-dimensional matrix of ones, N being the number of arguments you give to ones.
If numEntries is 8, 1:numEntries creates a 1x8 vector 1 2 3 4 5 6 7 8. This vector being given as input to ones, you'll get a 8-dimensional matrix of ones, in which the size of 1st dimension (vertical) is 1, the size of 2nd dimension (horizontal) is 2, the size of third dimension is 3, and so on, until the 8th dimension, that has size of 8.
numEntries = 8;
W = ones(1:numEntries);
% To check sizes of each dimension of W:
size(W)
ans =
1 2 3 4 5 6 7 8
% To calculate the total number of elements in W:
prod(size(W))
ans =
40320
% Edit: to get the number of elements in W, numel(W) is faster than prod(size(W)) :
numel(W)
ans =
40320
It's an N-D (N-dimensional) array where N = numEntries.
More specifically, it's a N-D array of size 1 x 2 x ... x N filled with all ones.