Getting all submatrices - matlab

I have got an N×M matrix m like:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
I want to get all submatrices of size P×Q (P,Q are odd) w/o employing a for-loop.
The result s should be a P×Q×((N-P+1)·(M-Q+1)) matrix.
E.g. if P=Q=3:
s(:,:,1) = [1 2 3; 5 6 7; 9 10 11]
s(:,:,2) = [2 3 4; 6 7 8; 10 11 12]
s(:,:,3) = [5 6 7; 9 10 11; 13 14 15]
s(:,:,4) = [6 7 8; 10 11 12; 14 15 16]

im2col can help you out here:
m =
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
>> P = 3; Q = 3;
>> columnized = im2col(m,[P Q],'sliding');
>> nMatrices = size(columnized,2);
>> s = reshape(columnized, [P Q nMatrices])
s(:,:,1) =
1 2 3
5 6 7
9 10 11
s(:,:,2) =
5 6 7
9 10 11
13 14 15
s(:,:,3) =
2 3 4
6 7 8
10 11 12
s(:,:,4) =
6 7 8
10 11 12
14 15 16
im2col with the 'sliding' option finds all the overlapping submatrices and returns each as a (P·Q)-element column vector in columnized. To turn these back into matrices, we reshape this (P·Q)×((N-P+1)·(M-Q+1)) matrix into a P×Q×((N-P+1)·(M-Q+1)) one.

Related

one-by-one matrix assignment MATLAB

I need to find the minimum values in each column of matrix "A", and then replace those min values with the values in last row of matrix "B" (which has same number of columns). Like I have these:
>> A = randi(10,10,5)
A =
3 5 9 5 8
7 6 4 10 2
8 4 1 7 4
4 7 2 8 2
7 5 8 7 5
3 7 10 10 1
5 7 8 5 7
8 3 8 2 3
6 10 2 1 10
3 7 6 7 2
>> B = randi(100,3,5)
B =
10 34 66 18 62
99 95 49 54 81
52 1 52 9 95
>> [M,I] = min(A)
M =
3 3 1 1 1
I =
1 8 3 9 6
And I want to replace the values of "M" with "B(end,:), so that:
A(1,1) = B(end,1);
A(8,2) = B(end,2);
A(3,3) = B(end,3);
A(9,4) = B(end,4);
A(6,5) = B(end,5);
I try "A(I) = B(end,:)" and "A(I(1,:)) = B(end,:)" but they do not work! Any ideas how I could do that? My real matrices are huge (1200x100000) so no way to do it by hand!
try this to replace the first min value:
A = [ 3 5 9 5 8;
7 6 4 10 2;
8 4 1 7 4;
4 7 2 8 2;
7 5 8 7 5;
3 7 10 10 1;
5 7 8 5 7;
8 3 8 2 3;
6 10 2 1 10;
3 7 6 7 2];
B =[ 10 34 66 18 62;
99 95 49 54 81;
52 1 52 9 95];
[M,I] = min(A)
A(sub2ind(size(A),I,1:size(A,2)))=B(end,:)
the output will be:
A =
52 5 9 5 8
7 6 4 10 2
8 4 52 7 4
4 7 2 8 2
7 5 8 7 5
3 7 10 10 95
5 7 8 5 7
8 1 8 2 3
6 10 2 9 10
3 7 6 7 2
However, when you have to replace all of the min values, use the code below instead
A = [ 3 5 9 5 8;
7 6 4 10 2;
8 4 1 7 4;
4 7 2 8 2;
7 5 8 7 5;
3 7 10 10 1;
5 7 8 5 7;
8 3 8 2 3;
6 10 2 1 10;
3 7 6 7 2];
B =[ 10 34 66 18 62;
99 95 49 54 81;
52 1 52 9 95];
M = min(A);
for i=1:size(A,2)
A(find(A(:,i) == M(i)),i)=B(end,i);
end;
A
the output is:
A =
52 5 9 5 8
7 6 4 10 2
8 4 52 7 4
4 7 2 8 2
7 5 8 7 5
52 7 10 10 95
5 7 8 5 7
8 1 8 2 3
6 10 2 9 10
52 7 6 7 2
You can acces you matrix by a single index, which looks like this:
Indeces =
1 6 11 16
2 7 12 17
3 8 13 18
4 9 14 19
5 10 15 20
Since you get the indeces for each individual column, you just need to increase it by the column number times the height of the matrix.
This should yield the correct result:
A( I + (0 : size(A,2)-1) * size(A,1) ) = B(end,:)

Reshaping vector to n-d matrix in row-wise order

I'm trying to convert a vector into a 3d matrix in a row-wise manner.
For example, my vector is:
a = 1:18;
and I'd like to convert this to a 2x3x3 matrix:
b(:,:,1) = [1 2 3; 4 5 6];
b(:,:,2) = [7 8 9; 10 11 12];
b(:,:,3) = [13 14 15; 16 17 18];
but the reshape function (i.e. reshape(a, 2,3,3)) arranges the elements in a column-wise fashion as:
val(:,:,1) =
1 3 5
2 4 6
val(:,:,2) =
7 9 11
8 10 12
val(:,:,3) =
13 15 17
14 16 18
How can I obtain the matrix b from vector a?
Use combination of reshape and permute.
b = permute(reshape(a,3,2,3),[2 1 3]);
b(:,:,1) =
1 2 3
4 5 6
b(:,:,2) =
7 8 9
10 11 12
b(:,:,3) =
13 14 15
16 17 18
I found a (or the) solution:
b = permute(reshape(reshape(a,3,[])',2,3,[]), [1,3,2])
b(:,:,1) =
1 2 3
4 5 6
b(:,:,2) =
7 8 9
10 11 12
b(:,:,3) =
13 14 15
16 17 18

Sorting every layer of 3D matrix by one column each

I have a 3D matrix. Say it is:A = randi(15,[4,3,2]). I want to sort the 2nd column of each layer in an ascending order, but the other columns simply stayed in their respective rows. How can I do that?
If the two layers are like this
val(:,:,1) =
6 12 13
10 14 8
15 8 2
4 3 14
val(:,:,2) =
10 1 8
2 15 12
14 11 1
1 6 11
Then I want a result like this
val(:,:,1) =
4 3 14
15 8 2
6 12 13
10 14 8
val(:,:,2) =
10 1 8
1 6 11
14 11 1
2 15 12
If you have the Image Processing Toolbox, using blockproc is one solution:
val(:,:,1) = [ ...
6 12 13
10 14 8
15 8 2
4 3 14]
val(:,:,2) = [ ...
10 1 8
2 15 12
14 11 1
1 6 11]
%// row indices to used for sorting
rowidx = 2;
[n,m,p] = size( val );
%// get a 2D matrix
val2D = reshape(val, n, [], 1)
%// sorting
out2D = blockproc(val2D,[n,m],#(x) sortrows(x.data,rowidx))
%// transform back to 3D
out3D = reshape(out2D, n, m, [])
Without the toolbox, maybe a little slower:
temp = arrayfun(#(x) sortrows(val(:,:,x),rowidx),1:size(val,3),'uni',0)
out3D = cat(3,temp{:})
out3D(:,:,1) =
4 3 14
15 8 2
6 12 13
10 14 8
out3D(:,:,2) =
10 1 8
1 6 11
14 11 1
2 15 12

Matlab - Finding values within a matrix

How can I find the row that have all the values from A into the matrix B and display the index of the rows using Matlab?
A= [2 5 6];
B=[1 2 4 9 10 15 27 30;
1 2 3 4 5 6 7 8;
1 2 3 5 6 9 22 101;
2 4 5 6 14 20 22 23]
Thanks
With bsxfun in 3D -
ind = find(all(any(bsxfun(#eq,B,permute(A,[1 3 2])),2),3))
With bsxfun again, but keeping it in 2D -
ind = find(sum(reshape(any(bsxfun(#eq,B(:),A(:).'),2),size(B)),2)==numel(A))
With ismember -
ind = find(sum(reshape(ismember(B(:),A(:)),size(B)),2)==numel(A))
With pdist2 from Statistics and Machine Learning Toolbox -
ind = find(sum(reshape(any(pdist2(B(:),A(:))==0,2),size(B)),2)==numel(A))
With knnsearch again from Statistics and Machine Learning Toolbox-
[~,dists] = knnsearch(A(:),B(:))
ind = find(sum(reshape(dists==0,size(B)),2)==numel(A))
Sample run -
A =
2 5 6
B =
1 2 4 9 10 15 27 30
1 2 3 4 5 6 7 8
1 2 3 5 6 9 22 101
2 4 5 6 14 20 22 23
ind =
2
3
4

Matlab filter matrix

My data matrix is large: smt like 180:3000 size.
Each element value is between 0 to 255;
I have to find areas in this matrix where average value is higher than some threshold (lets call it 'P'). And reset each element in these areas to '0'. Another words filter my matrix.
I have width and heigth of filter area.
So I need to loop over data matrix to find appropriate areas (As many as exist).
EDIT:
Please, see an example:
4 6 7 5 6 6 7
10 8 9 8 9 10 9
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 5 5 5 5 5
4 5 5 5 5 5 5
10 12 12 12 13 10 11
14 15 15 16 14 15 15
13 15 15 15 14 14 13
This is given matrix. Lets try to find areas (2, 3) of size where average value is > 15.
So the result will be:
4 6 7 5 6 6 7
10 8 9 8 9 10 9
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 5 5 5 5 5
4 5 5 5 5 5 5
10 12 12 12 13 10 11
14 0 0 0 14 15 15
13 0 0 0 14 14 13
Please, look at bottom of matrix
Please, give me some tips how it is possible to loop throw.
Thank you very much.
One way of doint this is as follows:
% example A with more areas of mean greater than 15
% there are four such areas as shown here: http://i.imgur.com/V6m0NfL.jpg
A = [16 16 16 5 16 16 16
16 16 16 8 16 16 16
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 15.1 15 15 5 5
4 5 15 15 15 5 5
10 12 12 12 13 10 11
14 15 15 16 14 15 15
13 15 15 15 14 14 13];
% filter size
[n,m] = deal(2,3);
% filter center
center = floor(([n,m]+1)/2);
% find where we have areas greater than 15
B = nlfilter(A, [n,m], #(b) mean(b(:)) > 15);
% get coordinates of areas with mean > 15
[rows,cols] = find(B);
% zero out elements in all found areas
for i = 1:size(rows,1)
% calculate starting coordinates for the area to be set to 0
row = rows(i) - center(1) + 1;
col = cols(i) - center(2) + 1;
A(row:row+n-1 , col:col+m-1) = 0;
end
Results in:
A =
0 0 0 5 0 0 0
0 0 0 8 0 0 0
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 0 0 0 5 5
4 5 0 0 0 5 5
10 12 12 12 13 10 11
14 0 0 0 14 15 15
13 0 0 0 14 14 13
try this
a = input_matrix;
ii = 2 ; jj = 3;
threshold = 15;
x = ones(ii,jj)/(ii*jj);
%\\create matrix temp2 with average value of block a(i:i+ii-1,j:j+jj-1) at temp2(i,j)
temp1 = conv2(a,x,'full');
temp2 = temp1(ii:end-ii+1,jj:end-jj+1);
%\\find row and column indices of temp2 with value > threshold
[row_ col_] = find(temp2>threshold);
out = a;
%\\assign zero value to the corresponding blocks
for iii = 1:length(row_)
out(row_(iii):row_(iii)+ii-1,col_(iii):col_(iii)+jj-1) = 0;
end