m = [0 65 34 0; 0 55 8 19; 89 0 0 10]
m_padded = padarray(m,[4,4],0,'both')
I just have m_padded, and I'm trying to find a function that creates m? I thought of finding the indexes with find and add zeros to the borders, but how can I do that efficiently?
Use find to extract row and column subscripts of m in m_padded. Now use min and max to find the starting and ending subscripts respectively of rows and columns of m in m_padded. Use these subscripts to generate indices to extract m.
[r, c] = find(m_padded);
unpadded_m = m_padded(min(r):max(r), min(c):max(c));
The above code is applicable for padding done with any size and in any direction; be it pre, post, or both.
Related
I have a vector of certain size and I want to reshape it into a square matrix. Here is an example: Let's say the vector is of size 784. Then I would create a matrix of size 28x28. In Matlab I would do it with the following command:
reshape(x,28,28)
Of course it can be possible that it is not possible to have an exact square matrix. In this case the matrix should as squarish as possible.
How can I do this calculation? That means how can I calculate the values a and b in reshape(x,a,b)?
Start with a equal to the square root of numel(x) rounded down. If that number doesn't divide numel(x), subtract 1 and try again. That way you end with a equal to the closest integer to sqrt(x) (from below) that divides numel(x). b would then be numel(x)/a, but you can simply use [] as the third argument to reshape:
a = floor(sqrt(numel(x)));
while mod(x,a)
a = a-1;
end
result = reshape(x,a,[]);
Example:
x = 1:20;
gives
result =
1 5 9 13 17
2 6 10 14 18
3 7 11 15 19
4 8 12 16 20
One possible approach:
x = rand(1, 784);
divisors = find(rem(numel(x), 1:numel(x)) == 0);
[~, idx] = min(abs(divisors - sqrt(numel(x))));
x = reshape(x, divisors(idx), numel(x) / divisors(idx));
Let me explain:
Suppose you have a vector named x:
x = rand(1, 784);
First, you find the divisors of the size of x:
divisors = find(rem(numel(x), 1:numel(x)) == 0);
Then, you proceed to choose the divisor which is closest to the square root of x's size:
[~, idx] = min(abs(divisors - sqrt(numel(x))));
Finally, you reshape x using that divisor (and the corresponding multiple):
x = reshape(x, divisors(idx), numel(x) / divisors(idx));
It is not a simple problem to find closest factors of an integer. You need to use the MATLAB answers to the question Input an integer, find the two closest integers which, when multiplied, equal the input. From that question if you use the answer that provides the function findIntegerFactorsCloseToSquarRoot, you can use the following code to reshape.
[a, b] = findIntegerFactorsCloseToSquarRoot(numel(x));
reshape(x, a, b);
I suggest you to first check whether the number is prime or not by isprime(784).
Then you can use prime_factors = factor(784) to get the integer factorization of the number. (Depending on the MATLAB version you may use ifactor(784))
The rest needs just a little more work on prime_factors.
I have 3 vectors, v1, v2, v3. What I want to get is the difference between every possible pair of them, that is, v1-v2, v1-v3, v2-v3. How can I do this without looping in matlab?
Thank you.
Just use nchoosek to generate the combinations first and then use them to index into your array of row-vectors:
Test case:
numVectors = 3;
dim = 5;
Vs = rand(numVectors, dim);
Actual computation:
combs = nchoosek(1:size(Vs,1), 2);
differences = Vs(combs(:,1),:) - Vs(combs(:,2),:);
The above creates 3 random row vectors of dimension 5. So in your case, you may want to replace the creation of the random matrix with Vs = [v1; v2; v3]; if your vectors are row vectors; or transpose the vectors using Vs = [v1, v2, v3].'; if your data are column vectors.
Using bsxfun:
clear
clc
%// Sample vectors.
v1 = [1 2];
v2 = [10 20];
v3 = [0 0];
Out = bsxfun(#minus,[v1 v2 v3], [v1 v2 v3].')
Out =
0 1 9 19 -1 -1
-1 0 8 18 -2 -2
-9 -8 0 10 -10 -10
-19 -18 -10 0 -20 -20
1 2 10 20 0 0
1 2 10 20 0 0
Reasoning: Each difference is computed starting from the 1st element of the 1st vector until the 2nd element of the last vector.
The 1st column contains all the differences for the 1st element of the 1st vector, i.e. (1 -1), (1-2), (1-10), (1 - 20), (1 - 0), (1 - 0).
Then 2nd column, same thing but this time with the 2: (2 - 1), (2 - 2), (2 - 10), and so on.
Sorry if my explanations are unclear haha I don't know the right terms in english. Please ask for more details.
Code
%// Concatenate all vectors to form a 2D array
V = cat(2,v1(:),v2(:),v3(:),v4(:),v5(:))
N = size(V,2) %// number of vectors
%// Find all IDs of all combinations as x,y
[y,x] = find(bsxfun(#gt,[1:N]',[1:N])) %//'
%// OR [y,x] = find(tril(true(size(V,2)),-1))
%// Use matrix indxeing to collect vector data for all combinations with those
%// x-y IDs from V. Then, perform subtractions across them for final output
diff_array = V(:,x) - V(:,y)
Few points about the code
bsxfun with find gets us the IDs for forming pairwise combinations.
We use those IDs to index into the 2D concatenated array and perform subtractions between them to get the final output.
Bonus Stuff
If you look closely into the part where it finds the IDs of all combinations, that is basically nchoosek(1:..,2).
So, basically one can have alternatives to nchoosek(1:N,2) as:
[Y,X] = find(bsxfun(#gt,[1:N]',[1:N]))
[y,x] = find(tril(true(N),-1))
with [X Y] forming those pairwise combinations and might be interesting to benchmark them!
I am trying to find the Extremum of a 3-dim matrix along the 2nd dimension.
I started with
[~,index] = max(abs(mat),[],2), but I don't know how to advance from here. How is the index vector to be used together with the original matrix. Or is there a completely different solution to this problem?
To illustrate the task assume the following matrix:
mat(:,:,1) =
23 8 -4
-1 -26 46
mat(:,:,2) =
5 -27 12
2 -1 18
mat(:,:,3) =
-10 49 39
-13 -46 41
mat(:,:,4) =
30 -24 18
-40 -16 -36
The expected result would then be
ext(:,:,1) =
23
-46
ext(:,:,2) =
-27
18
ext(:,:,3) =
49
-46
ext(:,:,4) =
30
-40
I don't know how to use the index vector with mat to get the desired result ext.
1) If you want to find a maximum just along, let's say, 2d dimension, your variable index will be a matrix having dimensions (N,1,M), where N and M are number of elements of your matrix in the first and third dimensions respectively. In order to remove dummy dimensions, there is function squeeze() exist: index=squeeze(index) After that size(index) gives N,M
2) Depending on your problem, you probably need matlab function ind2sub(). First, you take a slice of your matrix, than find its maximum with linear indexing, and than you can restore your indicies with int2sub(). Here is an example for a 2D matrix:
M = randn(5,5);
[C,I] = max(M(:));
[index1,index2] = ind2sub(size(M),I);
Same method allows to find the absolute maximal element in whole 3D matrix.
Use ndgrid to generate the values along dimensions 1 and 3, and then sub2ind to combine the three indices into a linear index:
[~, jj] = max(abs(mat),[],2); %// jj: returned by max
[ii, ~, kk] = ndgrid(1:size(mat,1),1,1:size(mat,3)); %// ii, kk: all combinations
result = mat(sub2ind(size(mat), ii, jj, kk));
A fancier, one-line alternative:
result = max(complex(mat),[],2);
This works because, acccording to max documentation,
For complex input A, max returns the complex number with the largest complex modulus (magnitude), computed with max(abs(A)).
In matlab, after meeting a specific criterion, I used to return back the pixel itself and store it in the vector pixels as follows:
pixels(index) = y(i,j);
Now, I would like to return the location of those pixels. Should I do the following?
pixels(index) = i,j;
EDIT
If I want to then set those indexes to the value 1, I do the following, right?
for i=1:m
for j=1:n
y(i,j)=1
end
end
Thanks.
It is extremely inefficient to do so in a nested loop in Matlab.
Using sub2ind can help you do so much faster:
y( sub2ind( size(y), i, j ) ) = 1;
EDIT - sub2ind
What sub2ind does?
Suppose you have a matrix M of size [4 6]:
M = [ 1 5 9 13 17 21
2 6 10 14 18 22
3 7 11 15 19 23
4 8 12 16 20 24 ];
You wish to access two elements: the one at the first row and second column, and another at the fourth row and the fifth column.
In that case you have the rows you wish to access r = [ 1 4 ] and the columns you wish to access c = [ 2 5 ]. However, if you try and access
>> M( r, c )
This is a 2x2 matrix
ans =
5 17
8 20
And not the two elements you were looking for (which are 5 and 20).
What sub2ind does is convert the row/column indices you have into linear indices
>> sub2ind( size(M), r, c )
ans =
5 20
which happens to be the linear indices of the requested entries.
You can think of linear indices as the single index required to access an element in a matrix in the case that the matrix was converted to a vector stacking its columns one after the other.
A few comments:
Matlab has a few ways of indexing matrices: by row / column indices (like i and j in your question). By linear indices (like index in your question). However, the more efficient way is to use logical indexing: that is, using a matrix of the same size as y with true for the entries you wish to set / get.
So, in your example, if you could get such a logical matrix instead of index or i and j it would have been better.
Matlab has many advantages over other programing languages. One of them is its ability to perform vector/matrix operations extremely efficient. Resorting to loops, or worse, nested loops, is something that should be avoided in Matlab.
It is not a good practice to use i and j as variables in Matlab.
If you want to find the occurrence of a value y(i,j) simply evaluate
idx = (pixels == y(i,j));
Depending on your variables you can then probably do
index(idx) = 1;
How can I interpolate a vector in MATLAB?
For example, I have the following matrix:
M=
1 10
2 20
3 30
4 40
The first column of M denotes the independent parameter of x coordinate while the second column of M denotes the output or y coordinate.
I also have the following input vector:
a =
2.3
2.1
3.5
For each value of a, I wish to determine what the output interpolated result would be. In this case, given a, I wish to return
23
21
35
Here's the answer to the question after the edit, i.e. "how to interpolate"
You want to use interp1
M = [1 10;2 20;3 30;4 40];
a = [2.3;2.1;3.5;1.2];
interpolatedVector = interp1(M(:,1),M(:,2),a)
interpolatedVector =
23
21
35
12
Here's the answer to the question "find the two closest entries in a vector", i.e. the original question before the edit.
x=[1,2,3,4,5]'; %'#
a =3.3;
%# sort the absolute difference
[~,idx] = sort(abs(x-a));
%# find the two closest entries
twoClosestIdx = idx(1:2);
%# turn it into a logical array
%# if linear indices aren't good enough
twoClosestIdxLogical = false(size(x));
twoClosestIdxLogical(twoClosestIdx) = true;
twoClosestIdxLogical =
0
0
1
1
0