Matlab - Sum of surrounding elements - matlab

I want to calculate the sum of the elements surrounding a given element in a matrix. So far, I have written these lines of code:
for i=1:m,
rij(1:n)=0
for j=1:n,
alive = tijdelijk(i-1,j)+tijdelijk(i+1,j)+tijdelijk(i-1,j-1)+tijdelijk(i+1,j-1)+tijdelijk(i,j+1)+tijdelijk(i,j-1)+tijdelijk(i-1,j+1)+tijdelijk(i+1,j+1)
This results in an error because, for example, i-1 becomes zero for i=1. Anyone got an idea how to do this without getting this error?

You can sum the elements via filtering. conv2 can be used for this manner.
Let me give an example. I create a sample matrix
>> A = reshape(1:20, 4, 5)
A =
1 5 9 13 17
2 6 10 14 18
3 7 11 15 19
4 8 12 16 20
Then, I create a filter. The filter is like a mask where you put the center on the current cell and the locations corresponding to the 1's on the filter are summed. For eight-connected neighbor case, the filter should be as follows:
>> B = [1 1 1; 1 0 1; 1 1 1]
B =
1 1 1
1 0 1
1 1 1
Then, you simply convolve the matrix with this small matrix.
>> conv2(A, B, 'same')
ans =
13 28 48 68 45
22 48 80 112 78
27 56 88 120 83
18 37 57 77 50
If you want four-connected neighbors, you can make the corners of your filter 0. Similarly, you can design any filter for your purpose, such as for averaging all neighbors instead of summing them.
For details, please see the convolution article in Wikipedia.

Two possibilities : change the limits of the loops to i=k:(m-k) and j=k:(n-k) or use blkproc
ex :
compute the 2-D DCT of each 8-by-8 block
I = imread('cameraman.tif');
fun = #dct2;
J = blkproc(I,[8 8],fun);
imagesc(J), colormap(hot)

There are lots of things you can do at the edges. Which you do depends very specifically on your problem and is different from usage case to usage case. Typical things to do:
If (i-1) or (i+1) is out of range, then just ignore that element. This is equivalent to zero padding the matrix with zeros around the outside and adjusting the loop limits accordingly
Wrap around the edges. In other words, for an MxN matrix, if (i-1) takes you to 0 then instead of taking element (i-1, j) = (0, j) you take element (M, j).
Since your code mentions "your teacher" I'd guess that you can ask what should happen at the edges (or working it out in a sensible manner may well be part of the task!!).

Related

Weighted Random number?

How can I randomize and generate numbers from 0-50 in matrix of 5x5 with SUM or each row printed on the right side?
+
is there any way to give weight to individual numbers before generating the numbers?
Please help
Thanks!
To generate a random matrix of integers between 0 and 50 (sampled with replacement) you could use
M = randint(5,5,[0,50])
To print the matrix with the sum of each row execute the following command
[M sum(M,2)]
To use a different distribution there are a number of techniques but one of the easiest is to use the datasample function from the Statistics and Machine Learning toolbox.
% sample from a truncated Normal distribution. No need to normalize
x = 0:50;
weights = exp(-0.5*(x-25).^2 / 5^2);
M = reshape(datasample(x,25,'Weights',weights),[5,5])
Edit:
Based on your comment you want to perform random sampling without replacement. You can perform such a random sampling without replacement if the weights are non-negative integers by simulating the classic ball-urn experiment.
First create an array containing the appropriate number of each value.
Example: If we have the values 0,1,2,3,4 with the following weights
w(0) = 2
w(1) = 3
w(2) = 5
w(3) = 4
w(4) = 1
Then we would first create the urn array
>> urn = [0 0 1 1 1 2 2 2 2 2 3 3 3 3 4];
then, we would shuffle the urn using randperm
>> urn_shuffled = urn(randperm(numel(urn)))
urn_shuffled =
2 0 4 3 0 3 2 2 3 3 1 2 1 2 1
To pick 5 elements without replacement we would simple select the first 5 elements of urn_shuffled.
Rather than typing out the entire urn array, we can construct it programatically given an array of weights for each value. For example
weight = [2 3 5 4 1];
urn = []
v = 0
for w = weight
urn = [urn repmat(v,1,w)];
v = v + 1;
end
In your case, the urn will contain many elements. Once you shuffle you would select the first 25 elements and reshape them into a matrix.
>> M = reshape(urn_shuffled(1:25),5,5)
To draw random integer uniformly distributed numbers, you can use the randi function:
>> randi(50,[5,5])
ans =
34 48 13 28 13
33 18 26 7 41
9 30 35 8 13
6 12 45 13 47
25 38 48 43 18
Printing the sum of each row can be done by using the sum function with 2 as the dimension argument:
>> sum(ans,2)
ans =
136
125
95
123
172
For weighting the various random numbers, see this question.

Ranking two vectors of numbers relative to each other in MATLAB

I have two set of numbers and want to compare and rank them relative to each other in MATLAB.
The data is:
x = [3 7 8 25 33 52 64 65 78 79 91 93];
y = [7 10 12 27 30 33 57 62 80 83 85 90];
I started with the for/if/else commands and got stuck in the middle.
In other words, I want to get the answer through MATLAB how many times the numbers in the first group (x) are bigger than the ones in the second group (y).
I got started with sorting etc.
n1 = length(data1);
n2 = length(data2);
xs = sort(x);
ys = sort(y);
r1 = zeros(1,n1);
r2 = zeros(1,n2);
I am open to use other commands than this kind of sorting and for/if/else, it doesn't really matter, just need some help in the right direction.
I am not entirely sure I understand what you're trying to do there. Is it safe to assume that the two vectors will be of the same size?
You could simply do an element wise division of the 2 sorted vectors and get the statistics from there.
For example:
div = xs./ys;
max_div = max(div)
mean_div = mean(div)
This is equivalent to running a for loop and dividing each element in the xs array by each element in the ys array for that corresponding index. The 'max' and 'mean' are obviously the largest quotient and the mean quotient.
In MATLAB, to find how many times each of the numbers in vector x are bigger than numbers in vector y:
sum(x > y.')
This uses the transpose of y to create a size(x) by size(y) matrix with a 1 when a number in x is greater than a number in y, then sums each column.
For your data, the result is the following vector, with an item for each number in x:
[0 0 1 3 5 6 8 8 8 8 12 12]
The vectors x and y don't have to be sorted. If you need the total number of times, just apply sum again to the result.

how to find the middle elements of sub matrices in a matrix

I have a matrix and i want to consider it has 4 sub matrices which are placed together. How can I find the middle element of each sub matrix when they are together?
consider the matrix below. It is built by 4 sub matrices.
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
25 26 27 28 29 30
31 32 33 34 35 36
I want to get their middle elements so i could have:
8, 11, 26, 29
From what I have understood this might work for you and this is a demo, so use your own parameters -
Code
%%// Input matrix
A = rand(44,44);
%%/ Number of submatrices needed
num_submat = 16;%%// 4 for your example case
%%/ Number of submatrices along row and column
num_submat1= sqrt(num_submat);
%%// Middle element indices along each direction
v1 = floor(size(A,2)/(2*num_submat1))+1:size(A,2)/(num_submat1):size(A,2);
%%// Middle elements
middle_ele = A(v1,v1)
It is always helpful to know that matrix indexing in matlab goes columnwise eg,
indOrd = [1,4,7;2,5,8;3,6,9]
where the number is the index order and not related to your example. indOrd(4) would return 4. Try to use this to find the index locations.
Assuming that each submatrix has odd size 2n+1, the coordinates of the center of one submatrix alone are [n+1, n+1]. If your have a square with M*M submatrices (M=2 in your case), the coordinates are [n+1+i*(2*n+1), n+1+j*(2*n+1)], i and j taken independently in the range 0:M-1.
Turning back to Matlab, it is now quite easy to generate all indices of the centers of the submatrices grouped in the matrix A:
n = floor(size(A,1)/(2*M));
xc = n+1+reshape(repmat(0:M-1,M,1),[],1);
yc = n+1+reshape(repmat((0:M-1)',1,M),[],1);
centers = A(yc, xc);
For even-sized submatrix, you have to choose which element is the center, the modification is quite easy to do then.

Finding index of vector from its original matrix

I have a matrix of 2d lets assume the values of the matrix
a =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
17 24 1 8 15
11 18 25 2 9
This matrix is going to be divided into three different matrices randomly let say
b =
17 24 1 8 15
23 5 7 14 16
c =
4 6 13 20 22
11 18 25 2 9
d =
10 12 19 21 3
17 24 1 8 15
How can i know the index of the vectors in matrix d for example in the original matrix a,note that the values of the matrix can be duplicated.
for example if i want to know the index of {10 12 19 21 3} in matrix a?
or the index of {17 24 1 8 15} in matrix a,but for this one should return only on index value?
I would appreciate it so much if you can help me with this. Thank you in advance
You can use ismember with the 'rows' option. For example:
tf = ismember(a, c, 'rows')
Should produce:
tf =
0
0
1
0
0
1
To get the indices of the rows, you can apply find on the result of ismember (note that it's redundant if you're planning to use this vector for matrix indexing). Here find(tf) return the vector [3; 6].
If you want to know the number of the row in matrix a that matches a single vector, you either use the method explained and apply find, or use the second output parameter of ismember. For example:
[tf, loc] = ismember(a, [10 12 19 21 3], 'rows')
returns loc = 4 for your example. Note that here a is the second parameter, so that the output variable loc would hold a meaningful result.
Handling floating-point numbers
If your data contains floating point numbers, The ismember approach is going to fail because floating-point comparisons are inaccurate. Here's a shorter variant of Amro's solution:
x = reshape(c', size(c, 2), 1, []);
tf = any(all(abs(bsxfun(#minus, a', x)) < eps), 3)';
Essentially this is a one-liner, but I've split it into two commands for clarity:
x is the target rows to be searched, concatenated along the third dimension.
bsxfun subtracts each row in turn from all rows of a, and the magnitude of the result is compared to some small threshold value (e.g eps). If all elements in a row fall below it, mark this row as "1".
It depends on how you build those divided matrices. For example:
a = magic(5);
d = a([2 1 2 3],:);
then the matching rows are obviously: 2 1 2 3
EDIT:
Let me expand on the idea of using ismember shown by #EitanT to handle floating-point comparisons:
tf = any(cell2mat(arrayfun(#(i) all(abs(bsxfun(#minus, a, d(i,:)))<1e-9,2), ...
1:size(d,1), 'UniformOutput',false)), 2)
not pretty but works :) This would be necessary for comparisons such as: 0.1*3 == 0.3
(basically it compares each row of d against all rows of a using an absolute difference)

Physical significance of the rotation of the filter matrix in filter2 function

While using MATLAB 2D filter funcion filter2(B,X) and convolution function conv(X,B,''), I see that the filter2 function is essentially 2D convolution but with a rotation by 180 degrees of the filter coefficients matrix. In terms of the outputs of filter2 and conv2, I see that the below relation holds true:
output matrix of filter2 = each element negated of output of conv2
EDIT: I was incorrect; the above relation does not hold true in general, but I saw it for a few cases. In general, the two output matrices are unrelated, due to the fact that 2 entirely different kernels are obtained in both which are used for convolution.
I understand how 2D convolution is performed. What I want to understand is the implication of this in image processing terms. How do I visualize what is happening here? What does it mean to rotate a filter coefficient matrix by 180 degrees?
I'll start with a very brief discussion of convolution, using the following image from Wikipedia:
As illustrated, convolving two 1-D functions involves reflecting one of them (i.e. the convolution kernel), sliding the two functions over one another, and computing the integral of their product.
When convolving 2-D matrices, the convolution kernel is reflected in both dimensions, and then the sum of the products is computed for every unique overlapping combination with the other matrix. This reflection of the kernel's dimensions is an inherent step of the convolution.
However, when performing filtering we like to think of the filtering matrix as though it were a "stencil" that is directly laid as is (i.e. with no reflections) over the matrix to be filtered. In other words, we want to perform an equivalent operation as a convolution, but without reflecting the dimensions of the filtering matrix. In order to cancel the reflection performed during the convolution, we can therefore add an additional reflection of the dimensions of the filter matrix before the convolution is performed.
Now, for any given 2-D matrix A, you can prove to yourself that flipping both dimensions is equivalent to rotating the matrix 180 degrees by using the functions FLIPDIM and ROT90 in MATLAB:
A = rand(5); %# A 5-by-5 matrix of random values
isequal(flipdim(flipdim(A,1),2),rot90(A,2)) %# Will return 1 (i.e. true)
This is why filter2(f,A) is equivalent to conv2(A,rot90(f,2),'same'). To illustrate further how there are different perceptions of filter matrices versus convolution kernels, we can look at what happens when we apply FILTER2 and CONV2 to the same set of matrices f and A, defined as follows:
>> f = [1 0 0; 0 1 0; 1 0 0] %# A 3-by-3 filter/kernel
f =
1 0 0
0 1 0
1 0 0
>> A = magic(5) %# A 5-by-5 matrix
A =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
Now, when performing B = filter2(f,A); the computation of output element B(2,2) can be visualized by lining up the center element of the filter with A(2,2) and multiplying overlapping elements:
17*1 24*0 1*0 8 15
23*0 5*1 7*0 14 16
4*1 6*0 13*0 20 22
10 12 19 21 3
11 18 25 2 9
Since elements outside the filter matrix are ignored, we can see that the sum of the products will be 17*1 + 4*1 + 5*1 = 26. Notice that here we are simply laying f on top of A like a "stencil", which is how filter matrices are perceived to operate on a matrix.
When we perform B = conv2(A,f,'same');, the computation of output element B(2,2) instead looks like this:
17*0 24*0 1*1 8 15
23*0 5*1 7*0 14 16
4*0 6*0 13*1 20 22
10 12 19 21 3
11 18 25 2 9
and the sum of the products will instead be 5*1 + 1*1 + 13*1 = 19. Notice that when f is taken to be a convolution kernel, we have to flip its dimensions before laying it on top of A.