using Mean Square Error to create an index matrix matlab - matlab

The Mean Square Error(MSE), is a method used to define the difference in between two blocks, and can be calculated as follow:
a and b two blocks equal size
MSE = sqrt(sum(sum((a-b).^2)))/size(a or b)
If the MSE is less than a given threshold, than the two blocks are not diffrent.
Given two matrix A and B, the purpose is to divide the two matrix to blocks of a given size, then extract the first block from A and let it be a, then search for a block b from B where the Mean Square Error between a and b is less then a given threshold, then return the position of the block b from the matrix B. and so on. and here is an example:
Given two matrix A and B where:
A= [1 1 4 4 2 2
1 1 4 4 2 2
2 2 9 9 5 5
2 2 9 9 5 5
3 3 4 4 9 9
3 3 4 4 9 9];
B = [ 2 2 4 4 9 9
2 2 4 4 9 9];
the threshold is 2
The first block a obtained from the matrix A is:
1 1
1 1
The block b obtained from the matrix B that MSR between a and b is less than the threshold is:
2 2
2 2
Therefore we return the position of the block b in the matrix B which is 1
The second block a obtained from the matrix A is:
4 4
4 4
The block b obtained from the matrix B where MSR between a and b is less than threshold is:
4 4
4 4
Therefore we return the position of the block b in the matrix B which is 2. and so on.
The final result should be as follow
RES= [1 2 1
1 3 2
1 2 3];
Is there a faster way?

Here's a vectorized approach with bsxfun.
First define data:
A = [1 1 4 4 2 2
1 1 4 4 2 2
2 2 9 9 5 5
2 2 9 9 5 5
3 3 4 4 9 9
3 3 4 4 9 9]; %// data: A
B = [2 2 4 4 9 9
2 2 4 4 9 9]; %// data: B
m = 2; %// number of rows per block
n = 2; %// number of cols per block
Then apply the following steps:
Reshape matrices so that each block is a row (inspired by this great answer).
Compute the MSE for all pairs of blocks.
Find the argmin of the MSE with respect to blocks of B (for each block of A). Note that if there are several minimizing blocks in B this finds the first.
Reshape result into a matrix.
Code:
A2 = reshape(permute(reshape(A, size(A, 1), n, []), [2 1 3]), n*m, []); %// step 1
B2 = reshape(permute(reshape(B, size(B, 1), n, []), [2 1 3]), n*m, []);
mse = squeeze(sum(bsxfun(#minus, A2, permute(B2,[1 3 2])).^2, 1)); %// step 2
[~, result] = min(mse, [], 2); %// step 3
result = reshape(result, size(A,1)/m, size(A,2)/n); %// step 4

Related

Auto-fill matrix without row-repetitions

I have a series of numbers:
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5]
which I want to randomely fill into a 3x5 matrix without having the same number in the same row.
How can I do this in matlab? Potentially I could randomize the test vector and fill it into the 5x3 matrix but I don't know how to do this without getting the same number in the same row.
If you want to fill a 3-by-5 matrix with all of the values in test, making sure each row has no repeated values, you can do this very succinctly by using toeplitz to first generate an index matrix, then randomly permute the dimensions with randperm:
index = toeplitz(1:3, [3 5:-1:2]);
index = index(randperm(3), randperm(5));
And a sample index:
index =
1 5 4 2 3
4 3 2 5 1
5 4 3 1 2
If your values in test are the numbers 1 through 5, this should be all you need to do. If test could be any vector with with 5 different numbers, three of each, then you can get the unique values of your test vector and index them with index. This solution will generalize to any test vector:
test = [3 3 3 7 7 7 5 5 5 9 9 9 4 4 4]; % Sample data
uniqueValues = unique(test); % Get the unique values [3 4 5 7 9]
M = uniqueValues(index); % Use index as generated above
And the result will be guaranteed to be a reordered version of what's in test:
M =
3 9 7 4 5
7 5 4 9 3
9 7 5 3 4
You can take the unique matrix of test and pick any three elements out of it and fill in the required 5X3 matrix.
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5] ;
test_unique = unique(test) ;
A = zeros(5,3) ;
for i = 1:size(A,1)
A(i,:) = randsample(test_unique,3) ;
end
randsample needs a statistics toolbox, if you doesn't have it, you may use randperm as shown below.
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5] ;
test_unique = unique(test) ;
A = zeros(5,3) ;
for i = 1:size(A,1)
A(i,:) = test_unique(randperm(length(test_unique),3)) ;
end
If you want 3X5 matrix:
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5] ;
test_unique = unique(test) ;
A = zeros(3,5) ;
for i = 1:size(A,1)
A(i,:) = randsample(test_unique,5) ;
end
Here is a brute-force way of doing it
% data
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5];
% randomly permute the indices
indices = randperm(numel(test));
% create a random matrix
matrix = reshape(test(indices), 5, 3);
% while number of unique elements in any of the rows is other than 3
while any(arrayfun(#(x) numel(unique(matrix(x,:))), (1:size(matrix,1)).')~=3)
% keep generating random matrices
indices = randperm(numel(test));
matrix = reshape(test(indices), 5, 3);
end;
% here is the result
result=matrix;
EDIT : If you want 3x5 like you mentioned in your comment, it is a lot easier. Just one line below.
[~, result] = sort(rand(3,5),2);

Create tensor from n matrix of same size

I have a tensor stored in a file (each line of file is a matrix). In Matlab, I would like to read each line and then create a tensor of size
number of lines * size(matrix at each line)
I am just wondering how to create a tensor from n matrix of same size?
You can use cat instruction, for creating a tensor.
See http://www.mathworks.com/help/matlab/ref/cat.html
Example:
Suppose you have 3 matrices: R, G, and B, size 100x100 each.
Use: RGB = cat(3, R, G, B);
Now RGB is 100x100x3 tensor.
You can also use the following example:
%Initialize tensor with dimensions 3x4x5
T = zeros(3, 4, 5);
%Fill T with random 3x4 "plain" matrices:
for i = size(T, 5);
A = rand(3, 4);
T(:, :, i) = A;
end
Reading lines, converting to matrices using reshape, and place matrices in a tensor:
Suppose you have a text file were each line is a matrix.
Suppose you know matrix size, and number of matrices, and you want to create a tensor.
I created the following example file called rows.txt.
1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5 5 5 5
The following code, initialize a 3x4x5 tensor, read a line, convert it to matrix, and insert to the tensor:
%Initialize tensor with dimensions 3x4x5
T = zeros(3, 4, 5);
f = fopen('rows.txt', 'r');
for i = 1:5
R = fscanf(f, '%f\n', [1, 3*4]); %Read row from file into row vector R.
A = reshape(R, [3, 4]); %Reshape R to 3x4 matrix.
T(:, :, i) = A;
end
fclose(f);
Result:
T(:,:,1) =
1 1 1 1
1 1 1 1
1 1 1 1
T(:,:,2) =
2 2 2 2
2 2 2 2
2 2 2 2
T(:,:,3) =
3 3 3 3
3 3 3 3
3 3 3 3
T(:,:,4) =
4 4 4 4
4 4 4 4
4 4 4 4
T(:,:,5) =
5 5 5 5
5 5 5 5
5 5 5 5
Another alternative:
Read entire text file into a vector, and use reshape to convert it to a tensor:
f = fopen('rows.txt', 'r');
%Read entire file into vector A.
A = fscanf(f, '%f');
%Reshape vector A into 3x4x5 tensor.
T = reshape(A, [3, 4, 5]);
fclose(f);

Symmetrically extending a matrix

How can I extend a matrix in MATLAB by symmetrically replicating the boundary values? For example, if X is my matrix, extended matrix Xextsym should look like the following:
X =
1 2 3
4 5 6
Xextsym =
5 4 4 5 6 6 5
2 1 1 2 3 3 2
2 1 1 2 3 3 2
5 4 4 5 6 6 5
5 4 4 5 6 6 5
2 1 1 2 3 3 2
I'm aware that a function called wextend exists in the Wavelet Toolbox for this task exactly, but I don't have it.
Here is a function that extends a given matrix A by symmetric reflection, adding w element in each of four directions. Usage example:
symextend([1 2 3; 4 5 6], 2)
returns the extended matrix in your question.
function R = symextend(A, w)
[m, n] = size(A);
B = [A A(:, n:-1:1); A(m:-1:1, :) A(m:-1:1, n:-1:1)];
repm = 2*ceil(0.5+0.5*w/m);
repn = 2*ceil(0.5+0.5*w/n);
C = repmat(B, repm, repn);
R = C(m*repm + 1 - w : m*repm + m + w, n*repn + 1 - w : n*repn + n + w)
end
Idea: first reflect A once in each direction (this produces B), then repeat B with repmat, obtaining C. Finally, a suitable piece is carved out of C. The tricky parts are counting how many times to repeat, and which part to carve out.

what is the meaning of a(b) in matlab ? where a and b are matrix [duplicate]

This question already has answers here:
Got confused with a vector indexed by a matrix, in Matlab
(2 answers)
Closed 8 years ago.
Suppose:
a =
1 2 3
4 5 6
2 3 4
and
b =
1 3 2
6 4 8
In MATLABa(b) gives:
>> a(b)
ans =
1 2 4
3 2 6
What is the reason for this output?
when you have a matrix a:
a =
1 2 3
4 5 6
7 8 9
and b:
b =
1 3 4
3 2 6
then a(b) is a way of adressing items in a and gives you:
>> a(b)
ans =
1 7 2
7 4 8
to understand this you have to think of a als a single column vector
>> a(:)
ans =
1
4
7
2
5
8
3
6
9
now the first row of b (1 3 4) addresses elements in this vector so the first, the 3rd and the forth element of that single column vector which are 1 7 and 2 are adressed. Next the secound row of b is used as adresses for a secound line in the output so the 3rd, the 2nd and the 6th elements are taken from a, those are 7 4 and 8.
It's just a kind of matrix indexing.
Matrix indexes numeration in 'a' matrix is:
1 4 7
2 5 8
3 6 9
This is a possible duplicate to this post where I gave an answer: Got confused with a vector indexed by a matrix, in Matlab
However, I would like to duplicate my answer here as I think it is informative.
That's a very standard MATLAB operation that you're doing. When you have a vector or a matrix, you can provide another vector or matrix in order to access specific values. Accessing values in MATLAB is not just limited to single indices (i.e. A(1), A(2) and so on).
For example, let's say we had a vector a = [1 2 3 4]. Let's also say we had b as a matrix such that it was b = [1 2 3; 1 2 3; 1 2 3]. By doing a(b) to access the vector, what you are essentially doing is a lookup. The output is basically the same size as b, and you are creating a matrix where there are 3 rows, and each element accesses the first, second and third element. Not only can you do this for a vector, but you can do this for a matrix as well.
Bear in mind that when you're doing this for a matrix, you access the elements in column major format. For example, supposing we had this matrix:
A = [1 2
3 4
5 6
7 8]
A(1) would be 1, A(2) would be 3, A(3) would be 5 and so on. You would start with the first column, and increasing indices will traverse down the first column. Once you hit the 5th index, it skips over to the next column. So A(5) would be 2, A(6) would be 4 and so on.
Here are some examples to further your understanding. Let's define a matrix A such that:
A = [5 1 3
7 8 0
4 6 2]
Here is some MATLAB code to strengthen your understanding for this kind of indexing:
A = [5 1 3; 7 8 0; 4 6 2]; % 3 x 3 matrix
B = [1 2 3 4];
C = A(B); % C should give [5 7 4 1]
D = [5 6 7; 1 2 3; 4 5 6];
E = A(D); % E should give [8 6 3; 5 7 4; 1 8 6]
F = [9 8; 7 6; 1 2];
G = A(F); % G should give [2 0; 3 6; 5 7]
As such, the output when you access elements this way is whatever the size of the vector or matrix that you specify as the argument.
In order to be complete, let's do this for a vector:
V = [-1 9 7 3 0 5]; % A 6 x 1 vector
B = [1 2 3 4];
C = V(B); % C should give [-1 9 7 3]
D = [1 3 5 2];
E = V(D); % E should give [-1 7 0 9]
F = [1 2; 4 5; 6 3];
G = V(F); % G should give [-1 9; 3 0; 5 7]
NB: You have to make sure that you are not providing indexes that would make the accessing out of bounds. For example if you tried to specify the index of 5 in your example, it would give you an error. Also, if you tried anything bigger than 9 in my example, it would also give you an error. There are 9 elements in that 3 x 3 matrix, so specifying a column major index of anything bigger than 9 will give you an out of bounds error.

Construct columns from submatrices in Matlab

In Matlab, I'm trying to transform a matrix A to another matrix B such that B's columns are made up of square submatrices of A. For example, if A is:
A = [1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4];
I'd like B to be:
B = [1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4]
A could be, say 16-by-16, and constructing B from 4-by-4 squares would result in B being 4-by-64.
Is there an efficient way to do this using reshape in combination with some other commands? Or some other approach? I am currently iterating in a loop, which is very slow with a large number of large source matrices.
Assume your matrix is a bit more general, and made of 3x2 blocks:
A = [1 1 2 2
1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4
3 3 4 4
5 5 6 6
5 5 6 6
5 5 6 6];
b = [3 2];
szA = size(A);
Transpose, reshape, permute, reshape.
nb = prod(szA./b); % Number of blocks
nelb = prod(b); % Number of elements per block
out1 = reshape(permute(reshape(A',szA(2),b(1),szA(1)/b(1)),[2,1,3]),nelb,nb)
Alternatively, slower and memory intensive but more readable:
d1 = repmat(b(1),1,szA(1)/b(1));
d2 = repmat(b(2),1,szA(2)/b(2));
out = reshape(mat2cell(A,d1,d2)',1,nelb);
out = reshape([out{:}],nelb,nb)
Now, if the blocks are square, simply set b = [2,2] or b = [3,3], etc..., or simplify the general formulation removing indexing of b and prod.