Matlab : Sliding window using a matrix - arrays

I need some information on how to program the sliding window of matrix.
I have a diagonal matrix B defined below by:
I would like to deduce from the given matrix B and the size of the window W the different matrix for t ranging from 1 to the size L of the matrix.
Note: Each window has the same width and height. And the window moves on the diagonal.
Example: We have a matrix with size 5 by 8 and the size of the window is 3 by 4 and moves on the diagonal. The matrix B of the example is:
My code:
% Sliding window matrix
B = [ 1 1 0 0 0 0 0 0
2 2 1 1 0 0 0 0
0 0 2 2 1 1 0 0
0 0 0 0 2 2 1 1
0 0 0 0 0 0 2 2]; % Matrix B
W = 4; % Size of the window wanted here is 4
n = size(B,2) - W + 1;
X = zeros(size(B,1),W*n);
k = W-1:-1:0;
for i = 1:n
window = B(:,i:i+W-1)';
X(:,i*W - k) = B(:,i:i+W-1);
end
window;
With W = 4 and n of the for loop set to 1 I get:
window = [1 2 0 0 0
1 2 0 0 0
0 1 2 0 0
0 1 2 0 0];
Whereas I should get:
window = [1 1 0 0
2 2 1 1
0 0 2 2];
With my code I don't get exactly the different sub-matrix obtained by sliding window.
I would like my program to be able, depending on the matrix B and the choice of dimensions of my window, to return the diagonal matrix representing the window and shift one step to also recover the next diagonal matrix which is identical to the previous one, and so on until the end.
Any suggestions?

You need to specify window dimensions separately. Try this:
B = [ 1 1 0 0 0 0 0 0
2 2 1 1 0 0 0 0
0 0 2 2 1 1 0 0
0 0 0 0 2 2 1 1
0 0 0 0 0 0 2 2];
[bh, bw] = size(B); % matrix size
wh = 3; % window height
ww = 4; % window width
sx = 2; % sliding step length along 2nd dim
sy = 1; % sliding step length along 1st dim
wx = 1:sx:(bw-ww+1); % window left
wy = 1:sy:(bh-wh+1); % window top
n = min(numel(wx), numel(wy)); % number of windows which fit in matrix
for ii = 1:n
X = B((1:wh)+wy(ii)-1, (1:ww)+wx(ii)-1)
end
Note that the sliding window, as it is described in your question, does not necessarily visit the entire matrix diagonal. Unless you calculate the sx and sy based on the dimensions of the matrix.
B = randi(3, [8 13])
[bh, bw] = size(B); % matrix size
wh = 3; % window height
ww = 4; % window width
sx = 3; % slideing step length along 2nd dim
sy = 1; % slideing step length along 1st dim

Related

How to unfold a Matrix on Matlab?

I have a given matrix H and I would like to unfold (expand) it to find a matrix B by following the method below :
Let H be a matrix of dimension m × n. Let x = gcd (m,n)
The matrix H is cut in two parts.
The cutting pattern being such that :
The "diagonal cut" is made by alternately moving c = n/x units to the right (we move c units to the right several times).
We alternately move c-b = m/x units down (i.e. b = (n-m)/x) (we move b units down several times).
After applying this "diagonal cut" of the matrix, we copy and paste the two parts repeatedly to obtain the matrix B.
Exemple : Let the matrix H of dimension m × n = 5 × 10 defined by :
1 0 1 1 1 0 1 1 0 0
0 1 1 0 0 1 1 0 1 1
1 1 0 1 1 1 0 1 0 0
0 1 1 0 1 0 1 0 1 1
1 0 0 1 0 1 0 1 1 1
Let's calculate x = gcd (m,n) = gcd (5,10) = 5,
Alternatively move to the right : c = n/x = 10/5 = 2,
Alternatively move down : b = (n-m)/x = (10-5)/5 = 1.
Diagonal cutting diagram : The matrix H is cut in two parts.
The cutting pattern is such that :
We move c = 2 units to the right several times c = 2 units to the right,
We repeatedly move c - b = 1 unit downwards.
We get :
After applying this "diagonal cut" of the matrix, we copy and paste the two parts repeatedly to obtain the matrix :
Remark : In the matrices X, X1 and X2 the dashes are zeros.
The resulting matrix B is (L is factor) :
Any suggestions?
This can be done by creating a logical mask with the cutting pattern, and then element-wise multiplying the input by the mask and by its negation. Repeating by L can be done with blkdiag.
H = [1 0 1 1 1 0 1 1 0 0
0 1 1 0 0 1 1 0 1 1
1 1 0 1 1 1 0 1 0 0
0 1 1 0 1 0 1 0 1 1
1 0 0 1 0 1 0 1 1 1];
L = 2;
[m, n] = size(H);
x = gcd(m, n);
c = n / x;
b = (n-m)/x;
mask = repelem(tril(true(m/b)), b, c);
A = [H.*mask; H.*~mask];
A = repmat({A}, L, 1);
B = blkdiag(A{:});

Matlab array that decreases from the center

I've been trying to make a 2-dimensional array that has the largest number in the center, and numbers around it decrement by one like this:
[0 0 0 0 0 0 0;
0 1 1 1 1 1 0;
0 1 2 2 2 1 0;
0 1 2 3 2 1 0;
0 1 2 2 2 1 0;
0 1 1 1 1 1 0;
0 0 0 0 0 0 0]
Any help?
This is easy using implicit expansion:
M = 7; % desired size. Assumed to be odd
t = [0:(M-1)/2 (M-3)/2:-1:0].';
result = min(t, t.');
Alternatively, you can use the gallery function with the 'minij' option to produce one quadrant of the result, and then extend symmetrically:
M = 7; % desired size. Assumed to be odd
result = gallery('minij',(M+1)/2)-1;
result = [result result(:,end-1:-1:1)];
result = [result; result(end-1:-1:1,:)];
Another approach, using padarray from the Image Processing toolbox:
result = 0;
for k = 1:(M-1)/2;
result = padarray(result+1, [1 1]);
end

Create a matrix with a diagonal and left-diagonal of all 1s in MATLAB

I would like to create a square matrix of size n x n where the diagonal elements as well as the left-diagonal are all equal to 1. The rest of the elements are equal to 0.
For example, this would be the expected result if the matrix was 5 x 5:
1 0 0 0 0
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
How could I do this in MATLAB?
Trivial using the tril function:
tril(ones(n),0) - tril(ones(n),-2)
And if you wanted a thicker line of 1s just adjust that -2:
n = 10;
m = 4;
tril(ones(n),0) - tril(ones(n),-m)
If you prefer to use diag like excaza suggested then try
diag(ones(n,1)) + diag(ones(n-1,1),-1)
but you can't control the 'thickness' of the stripe this way. However, for a thickness of 2, it might perform better. You'd have to test it though.
You can also use spdiags too to create that matrix:
n = 5;
v = ones(n,1);
d = full(spdiags([v v], [-1 0], n, n));
We get:
>> d
d =
1 0 0 0 0
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
The first two lines define the desired size of the matrix, assuming a square n x n as well as a vector of all ones that is of length n x 1. We then call spdiags to define where along the diagonal of this matrix this vector will be populating. We want to define the main diagonal to have all ones as well as the diagonal to the left of the main diagonal, or -1 away from the main diagonal. spdiags will adjust the total number of elements for the diagonal away from the main to compensate.
We also ensure that the output is of size n x n, but this matrix is actually sparse . We need to convert the matrix to full to complete the result.,
With a bit of indices juggling, you can also do this:
N = 5;
ind = repelem(1:N, 2); % [1 1 2 2 3 3 ... N N]
M = full(sparse(ind(2:end), ind(1:end-1), 1))
Simple approach using linear indexing:
n = 5;
M = eye(n);
M(2:n+1:end) = 1;
This can also be done with bsxfun:
n = 5; %// matrix size
d = [0 -1]; %// diagonals you want set to 1
M = double(ismember(bsxfun(#minus, 1:n, (1:n).'), d));
For example, to obtain a 5x5 matrix with the main diagonal and the two diagonals below set to 1, define n=5 and d = [0 -1 -2], which gives
M =
1 0 0 0 0
1 1 0 0 0
1 1 1 0 0
0 1 1 1 0
0 0 1 1 1

Select n elements in matrix left-wise based on certain value

I have a logical matrix A, and I would like to select all the elements to the left of each of my 1s values given a fixed distant. Let's say my distance is 4, I would like to (for instance) replace with a fixed value (saying 2) all the 4 cells at the left of each 1 in A.
A= [0 0 0 0 0 1 0
0 1 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 1 0 1]
B= [0 2 2 2 2 1 0
2 1 0 0 0 0 0
0 0 0 0 0 0 0
2 2 2 2 2 2 1]
In B is what I would like to have, considering also overwrting (last row in B), and cases where there is only 1 value at the left of my 1 and not 4 as the fixed searching distance (second row).
How about this lovely one-liner?
n = 3;
const = 5;
A = [0 0 0 0 0 1 0;
0 1 0 0 0 0 0;
0 0 0 0 0 0 0;
0 0 0 0 1 0 1]
A(bsxfun(#ne,fliplr(filter(ones(1,1+n),1,fliplr(A),[],2)),A)) = const
results in:
A =
0 0 5 5 5 1 0
5 1 0 0 0 0 0
0 0 0 0 0 0 0
0 5 5 5 5 5 1
here some explanations:
Am = fliplr(A); %// mirrored input required
Bm = filter(ones(1,1+n),1,Am,[],2); %// moving average filter for 2nd dimension
B = fliplr(Bm); %// back mirrored
mask = bsxfun(#ne,B,A) %// mask for constants
A(mask) = const
Here is a simple solution you could have come up with:
w=4; % Window size
v=2; % Desired value
B = A;
for r=1:size(A,1) % Go over all rows
for c=2:size(A,2) % Go over all columns
if A(r,c)==1 % If we encounter a 1
B(r,max(1,c-w):c-1)=v; % Set the four spots before this point to your value (if possible)
end
end
end
d = 4; %// distance
v = 2; %// value
A = fliplr(A).'; %'// flip matrix, and transpose to work along rows.
ind = logical( cumsum(A) ...
- [ zeros(size(A,1)-d+2,size(A,2)); cumsum(A(1:end-d-1,:)) ] - A );
A(ind) = v;
A = fliplr(A.');
Result:
A =
0 2 2 2 2 1 0
2 1 0 0 0 0 0
0 0 0 0 0 0 0
2 2 2 2 2 2 1
Approach #1 One-liner using imdilate available with Image Processing Toolbox -
A(imdilate(A,[ones(1,4) zeros(1,4+1)])==1)=2
Explanation
Step #1: Create a morphological structuring element to be used with imdilate -
morph_strel = [ones(1,4) zeros(1,4+1)]
This basically represents a window extending n places to the left with ones and n places to the right including the origin with zeros.
Step #2: Use imdilate that will modify A such that we would have 1 at all four places to the left of each 1 in A -
imdilate_result = imdilate(A,morph_strel)
Step #3: Select all four indices for each 1 of A and set them to 2 -
A(imdilate_result==1)=2
Thus, one can write a general form for this approach as -
A(imdilate(A,[ones(1,window_length) zeros(1,window_length+1)])==1)=new_value
where window_length would be 4 and new_value would be 2 for the given data.
Approach #2 Using bsxfun-
%// Paramters
window_length = 4;
new_value = 2;
B = A' %//'
[r,c] = find(B)
extents = bsxfun(#plus,r,-window_length:-1)
valid_ind1 = extents>0
jump_factor = (c-1)*size(B,1)
extents_valid = extents.*valid_ind1
B(nonzeros(bsxfun(#plus,extents_valid,jump_factor).*valid_ind1))=new_value
B = B' %// B is the desired output

How to resize / expand a matrix by adding zeros?

How is it possible to expand a quadratic - let's say NxN - matrix to a bigger on like a (N+k)x(N+k) matrix?
It's really all about resizing the matrix and filling the missing rows/columns with zeros such that not dimension mismatch occurs.
No need to do it more difficult than it is. MATLAB automatically pads with zeros if you assign something to an element outside of the original size:
n = 4;
A = [1 2; 3 4];
A(n,n) = 0;
A =
1 2 0 0
3 4 0 0
0 0 0 0
0 0 0 0
you can add zeros to a matrix using padarray... For example:
A = [1 2; 3 4];
B = padarray(A,[2 2],'post')
B =
1 2 0 0
3 4 0 0
0 0 0 0
0 0 0 0
Or, if you don't have the image processing toolbox, you can use matrix indexing:
B = zeros(size(A)+k, class(A));
B(k:end-k+1,k:end-k+1) = A;

Resources