I want to create a new table extracting x rows every n rows from my table. For example if my table is:
1 2
3 4
5 6
7 8
9 10
11 12
13 14
15 16
17 18
19 20
21 22
I want something like:
1 2
3 4
11 12
13 14
21 22
Here is an easy way by using ismember and mod to categorize the rows
n = 5;
x = 2;
b = a(logical(ismember(mod(0:size(a)-1,n),0:x-1)),:);
such that
>> b
b =
1 2
3 4
11 12
13 14
21 22
Data
a = [1 2
3 4
5 6
7 8
9 10
11 12
13 14
15 16
17 18
19 20
21 22];
I want to use reshape.
v=[1:20 ;2:2:40 ;3:3:60 ;4:4:80];
Using reshape(v,4,4,5) gives output:
ans(:,:,1) =
1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16
ans(:,:,2) =
17 2 10 18
18 4 12 20
19 6 14 22
20 8 16 24
And so on. But I desire
ans(:,:,1)=
1 2 3 4
2 4 6 8
3 6 9 12
4 8 12 16
ans(:,:,2)=
5 10 15 20
6 12 18 24
7 14 21 28
8 16 24 32
reshape(v',4,4,5) didn't work for me either
You are on the right track with the reshape function. You just need to transpose your 3D slices using permute. i.e.
permute(reshape(v,4,4,[]),[2 1 3])
I am reading this:
https://uk.mathworks.com/help/images/imfilter-boundary-padding-options.html
And I am trying to understand how it will work for 5x5, or 7x7 kernels. Let's say in a 5x5 kernel you will have an extra row and column, on the top and right side of the kernel compared to the one in the image in the link. What value will that take ? Just the closest one it can find ? And how about diagonal values (the ones in the corners) ?
From the documentation for the 'replicate' option in imfilter,
Input array values outside the bounds of the array are assumed to equal the nearest array border value.
You can actually see the exact array that imfilter uses by calling padarray with the proper arguments. Say we have a 5x5 array:
im = reshape(1:25, 5, 5)
im =
1 6 11 16 21
2 7 12 17 22
3 8 13 18 23
4 9 14 19 24
5 10 15 20 25
We can pad this array by 2 on each side (the equivalent of using a 5x5 kernel):
padarray(im, [2 2], 'replicate')
ans =
1 1 1 6 11 16 21 21 21
1 1 1 6 11 16 21 21 21
1 1 1 6 11 16 21 21 21
2 2 2 7 12 17 22 22 22
3 3 3 8 13 18 23 23 23
4 4 4 9 14 19 24 24 24
5 5 5 10 15 20 25 25 25
5 5 5 10 15 20 25 25 25
5 5 5 10 15 20 25 25 25
Spacing out the rows/columns so you can see the original array more easily:
1 1 1 6 11 16 21 21 21
1 1 1 6 11 16 21 21 21
1 1 1 6 11 16 21 21 21
2 2 2 7 12 17 22 22 22
3 3 3 8 13 18 23 23 23
4 4 4 9 14 19 24 24 24
5 5 5 10 15 20 25 25 25
5 5 5 10 15 20 25 25 25
5 5 5 10 15 20 25 25 25
You can also verify this by creating a kernel with a single 1 value in one of the corners:
im = reshape(1:25, 5, 5)
im =
1 6 11 16 21
2 7 12 17 22
3 8 13 18 23
4 9 14 19 24
5 10 15 20 25
k = zeros(5); k(1,1) = 1
k =
1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
imfilter(im, k, 'replicate')
ans =
1 1 1 6 11
1 1 1 6 11
1 1 1 6 11
2 2 2 7 12
3 3 3 8 13
Naturally, this only shows the top-left 5x5 subarray of the 9x9 padded array, but by repeating the process with the 1 in different corners you can see the whole array.
In MATLAB, we can use im2col and col2im to transform from columns to blocks and back, for example
>> A = floor(30*rand(4,6))
A =
8 5 2 13 15 11
22 11 27 13 24 24
5 18 23 9 23 15
20 23 14 15 19 10
>> B = im2col(A,[2 2],'distinct')
B =
8 5 2 23 15 23
22 20 27 14 24 19
5 18 13 9 11 15
11 23 13 15 24 10
>> col2im(B,[2 2],[4,6],'distinct')
ans =
8 5 2 13 15 11
22 11 27 13 24 24
5 18 23 9 23 15
20 23 14 15 19 10
my question is that: after using im2col with sliding mode
>> B = im2col(A,[2 2],'sliding')
B =
8 22 5 5 11 18 2 27 23 13 13 9 15 24 23
22 5 20 11 18 23 27 23 14 13 9 15 24 23 19
5 11 18 2 27 23 13 13 9 15 24 23 11 24 15
11 18 23 27 23 14 13 9 15 24 23 19 24 15 10
I wish to get a 4-by-6 matrix C from B(without knowing A) that the value at each site equals the original value multiple the times of sampling.
In other word, C(1,1)=A(1,1), C(1,2)=A(1,2)*2, C(2,2) = A(2,2)*4
Though we can easily implement with a for-loop, but the efficiency is critically low. So how to vectorize the implementation?
If I'm understanding correctly, you're desired output is
C = [ 8 10 4 26 30 11
44 44 108 52 96 48
10 72 92 36 92 30
20 46 28 30 38 10 ]
which I got by computing C = A.*S where
S = [ 1 2 2 2 2 1
2 4 4 4 4 2
2 4 4 4 4 2
1 2 2 2 2 1 ]_
The entries in S represent how many sliding blocks each entry is a member of.
I believe your question boils down to how to construct the matrix S.
Solution:
S = min(min(1:M,M:-1:1),x)'*min(min(1:N,N:-1:1),y)
C = A.*S
where A is size M-by-N, and your sliding block is size x-by-y.
Explanation:
In the given example, M=4, N=6, x=2, and y=2.
Notice the solution S can be written as the outer product of two vectors:
S = [1;2;2;1] * [1,2,2,2,2,1]
We construct each of these two vectors using the values of M,N,x,y:
min(1:M,M:-1:1)' == min(1:4,4:-1:1)'
== min([1,2,3,4], [4,3,2,1])'
== [1,2,2,1]'
== [1;2;2;1]
In this case, the extra min(...,x) does nothing since all entries are already <=x.
min(1:N,N:-1:1) == min(1:6,6:-1:1)
== min([1,2,3,4,5,6],[6,5,4,3,2,1])
== [1,2,3,3,2,1]
This time the extra min(...,y) does matter.
min(min(1:N,N:-1:1),y) == min([1,2,3,3,2,1],y)
== min([1,2,3,3,2,1],2)
== [1,2,2,2,2,1]
A simple MATLAB-problem:
coordinates=[1 6 ;9 20];
coordinates =
1 6
9 20
What i now want to have is:
idxList=[1 2 3 4 5 6 9 10 11 12 13 14 15 16 17 18 19 20];
idxList =
1 2 3 4 5 6 9 10 11 12 13 14 15 16 17 18 19 20
How i have to make that?
Here's one way:
>> cell2mat(cellfun(#(x) x(1):x(2), num2cell(coordinates, 2), 'UniformOutput', 0)')
ans =
1 2 3 4 5 6 9 10 11 12 13 14 15 16 17 18 19 20