How to rearrange matrix column into block using for loop? - matlab

I am working on a project where i have used a image whose size is (512x512)then i have divided the whole image by 8 so that there will be 64x64 block then i have rearranged each 8x8 image patch into a single column and my new size is 64x4069.
Now i want to get back the original size i.e 512x512,please help me how to get back it using for loop instead of 'col2im'
a=imread('lena.png');
b=double(a);
[m,n] = size(b);
bl=8;
br=m/bl;
bc=n/bl;
out = zeros(size(reshape(b,bl*bl,[])));
count = 1;
for i = 1:br
for j= 1:bc
block = b((j-1)*bl + 1:(j-1)*bl + bl, (i-1)*bl + 1:(i-1)*bl + bl);
out(:,count) = block(:);
count = count + 1;
end
end

This is basically your script written backwards. Some assumptions have to be made, because not every rectangular matrix can arise from the process you described, and also because the dimensions of the original matrix cannot be uniquely determined from the set of blocks. So, I assume that the original matrix was a square one, and the blocks were squares as well.
By the way, in your code you use j in the formula for row indices and i for columns; I assumed this was a mistake, and amended it below.
out = kron((0:3)', 1:16); % for testing; you would have a 64x4096 matrix here
[m,n] = size(out);
osize = sqrt(n*m);
bl = sqrt(m);
br = osize/bl;
bc = br;
original = zeros(osize);
count = 1;
for i = 1:br
for j = 1:bc
block = zeros(bl);
block(:) = out(:,count);
original(1+(i-1)*bl : i*bl, 1+(j-1)*bl : j*bl) = block;
count = count + 1;
end
end
Input for testing:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32
3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48
Output:
0 2 0 4 0 6 0 8
1 3 2 6 3 9 4 12
0 10 0 12 0 14 0 16
5 15 6 18 7 21 8 24
0 18 0 20 0 22 0 24
9 27 10 30 11 33 12 36
0 26 0 28 0 30 0 32
13 39 14 42 15 45 16 48

Related

How to get list of neighbors with distance N from index in matrix? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I have a matrix like this:
35 1 6 26 19 24
3 32 7 21 23 25
31 9 2 22 27 20
8 28 33 17 10 15
30 5 34 12 14 16
4 36 29 13 18 11
I want a list of neighbors with distance 3 for each cell. For example,
the list of neighbors with distance 3 for (1, 1) is:
[8, 28, 33, 17, 26, 21, 22, 17]
Visual explanation:
[35] 1 6 |26| 19 24
3 32 7 |21| 23 25
31 9 2 |22| 27 20
-------------------
8 28 33 |17| 10 15
-------------------
30 5 34 12 14 16
4 36 29 13 18 11
The list of neighbors with distance 3 for (3, 3) is
[4, 36, 29, 13, 18, 11, 24, 25, 20, 15, 16]
Visual explanation:
35 1 6 26 19 |24|
3 32 7 21 23 |25|
31 9 [2] 22 27 |20|
8 28 33 17 10 |15|
30 5 34 12 14 |16|
------------------------
4 36 29 13 18 |11|
------------------------
Generate an all-zero "index matrix" idx with the same size of your matrix A, and set the "seed" to 1:
A = [ ...
35 1 6 26 19 24; ...
3 32 7 21 23 25; ...
31 9 2 22 27 20; ...
8 28 33 17 10 15; ...
30 5 34 12 14 16; ...
4 36 29 13 18 11 ...
]
idx = zeros(size(A));
idx(3, 2) = 1
We get:
A =
[...]
idx =
0 0 0 0 0 0
0 0 0 0 0 0
0 1 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
Now, we use 2-D convolution, i.e. MATLAB's conv2 method to create the correct index matrix w.r.t. to the distance d:
idx = logical(conv2(idx, ones(2*d+1), 'same') - conv2(idx, ones(2*d-1), 'same'))
(Convolution is the key to success.)
Then, we get:
idx =
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
1 1 1 1 1 0
Since we already casted the indices to logical, we can directly access the proper elements in the matrix A:
B = A(idx).'
The final result:
B =
4 36 29 13 19 23 27 10 14 18
Please notice the difference in the result as you wrote (3, 2) in your second example, but actually marked (3, 3) as "seed".
Hope that helps!
Disclaimer: Tested with Octave 5.1.0, but also works with MATLAB Online.

How can I make a diamond of zeroes in a matrix of any size? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have a square Matrix N x M, odd dimensions, and I want to put a diamond of zeroes, for example, for a 5 x 5 matrix:
1 3 2 4 2
5 7 8 9 5
3 2 4 6 3
6 8 2 1 3
3 3 3 3 3
Is transform to:
1 3 0 4 2
5 0 8 0 5
0 2 4 6 0
6 0 2 0 3
3 3 0 3 3
How can this be done efficiently?
I'll bite, here is one approach:
% NxN matrix
N = 5;
assert(N>1 && mod(N,2)==1);
A = magic(N);
% diamond mask
N2 = fix(N/2);
[I,J] = meshgrid(-N2:N2);
mask = (abs(I) + abs(J)) == N2;
% fill with zeros
A(mask) = 0;
The result:
>> A
A =
17 24 0 8 15
23 0 7 0 16
0 6 13 20 0
10 0 19 0 3
11 18 0 2 9
I also had some time to play around. For my solution there are no limits concerning A being odd or even or larger than 1. Every integer is fine (even 0 works, though it does not make sense).
% NxN matrix
N = 7;
A = magic(N);
half = ceil( N/2 );
mask = ones( half );
mask( 1 : half+1 : half*half ) = 0;
mask = [ fliplr( mask ) mask ];
mask = [ mask; flipud( mask ) ];
if( mod(N,2) == 1 )
mask(half, :) = []
mask(:, half) = []
end
A( ~mask ) = 0;
A
I am first creating a square sub-matrix mask of "quarter" size (half the number of columns and half the number of rows, ceil() to get one more in the case N is odd).
Example for N=7 -> half=4.
mask =
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
I then set it's diagonal values to zero:
mask =
0 1 1 1
1 0 1 1
1 1 0 1
1 1 1 0
Mirror the mask horizontally:
mask =
1 1 1 0 0 1 1 1
1 1 0 1 1 0 1 1
1 0 1 1 1 1 0 1
0 1 1 1 1 1 1 0
Then mirror it vertically:
mask =
1 1 1 0 0 1 1 1
1 1 0 1 1 0 1 1
1 0 1 1 1 1 0 1
0 1 1 1 1 1 1 0
0 1 1 1 1 1 1 0
1 0 1 1 1 1 0 1
1 1 0 1 1 0 1 1
1 1 1 0 0 1 1 1
As N is odd we got a redundant row and redundant column that are then removed:
mask =
1 1 1 0 1 1 1
1 1 0 1 0 1 1
1 0 1 1 1 0 1
0 1 1 1 1 1 0
1 0 1 1 1 0 1
1 1 0 1 0 1 1
1 1 1 0 1 1 1
The logical not is then used as a mask to select the values in the original matrix that are set to 0.
Probably not as efficient as #Amro's solution, but it works. :D
My solution:
looking at the first left half of the matrix
in the first row 0 is in the middle column (let's call it mc)
in the second row the 0is in column mc-1
and so on while the rows increase
when you reach column 1 the sequence continue but with mc+1 but the rows decrease
In a similar way for the right half of the matrix
n=7
a=randi([20 30],n,n)
% Centre of the matrix
p=ceil(n/2)
% Identify the column sequence
col=[p:-1:1 2:p p+1:n n-1:-1:p]
% Identify the row sequence
row=[1:n n-1:-1:1]
% Transorm the row and column index in linear index
idx=sub2ind(size(a),row,col)
% Set the 0'
a(idx)=0
a =
22 29 23 27 27 21 23
29 29 21 27 24 26 24
30 28 21 27 29 28 25
28 22 24 20 27 24 25
23 26 21 20 30 20 29
26 20 26 23 25 22 25
21 24 25 25 23 21 30
a =
22 29 23 0 27 21 23
29 29 0 27 0 26 24
30 0 21 27 29 0 25
0 22 24 20 27 24 0
23 0 21 20 30 0 29
26 20 0 23 0 22 25
21 24 25 0 23 21 30
Hope this helps.
Qapla'
Using indexing (only works when N is odd):
N = 7;
% Random matrix
A = randi(100, N);
idx = [N-1:-2:1; 2:2:N];
A(cumsum([ceil(N/2) idx(:)' idx(end-1:-1:1)])) = 0
A =
60 77 74 0 54 83 9
8 48 0 76 0 28 67
6 0 32 78 83 0 10
0 27 25 5 11 39 0
76 0 49 43 67 0 16
79 7 0 86 0 70 78
57 28 85 0 81 44 81

MATLAB - Sampling Random values

I want to use randsample to sample values from a matrix, but I want the values sampled to be replaced by zero in the matrix. What do I do/Is there a fuction for this?
I think you don't want to use randsample because you have a given matrix (here M). You can use datasample instead to randomly sample existing data. Then you can use the second output of datasample (here ind) to address the entries in the original matrix M and overwrite them easily.
In the following example operates over the second dimension and takes a selection of columns. If you want a selection of rows, change the third argument of datasample to 1 (this is Matlab's default behaviour when no third argument is given).
% create random data
M = randi(20,4,10)
% randomly sample data
[Y,ind] = datasample(M,4,2)
% write 0 for the sampled data in original matrix
M(:,ind) = 0
This is the result:
M =
20 14 6 18 1 9 4 15 11 11
11 5 9 20 8 19 2 9 3 13
20 20 16 4 1 16 13 11 4 9
15 1 4 12 20 18 4 19 11 13
Y =
18 4 15 14
20 2 9 5
4 13 11 20
12 4 19 1
ind =
4 7 8 2
M =
20 0 6 0 1 9 0 0 11 11
11 0 9 0 8 19 0 0 3 13
20 0 16 0 1 16 0 0 4 9
15 0 4 0 20 18 0 0 11 13
Initialized with rng(4).

Matlab: how I can transform this algorithm associated with matrices manipulation?

(For my problem, I use a matrix A 4x500000. And the values of A(4,k) varies between 1 and 200).
I give here an example for a case A 4x16 and A(4,k) varies between 1 and 10.
I want first to match a name to the value from 1 to 5 (=10/2):
1 = XXY;
2 = ABC;
3 = EFG;
4 = TXG;
5 = ZPF;
My goal is to find,for a vector X, a matrix M from the matrix A:
A = [20 52 70 20 52 20 52 20 20 10 52 20 11 1 52 20
32 24 91 44 60 32 24 32 32 12 11 32 2 5 24 32
40 37 24 30 11 40 37 40 40 5 10 40 40 3 37 40
2 4 1 3 4 5 2 1 3 3 8 6 7 9 6 10]
A(4,k) takes all values between 1 and 10. These values can be repeated and they all appear on the 4th line.
20
X= 32 =A(1:3,1)=A(1:3,6)=A(1:3,8)=A(1:3,9)=A(1:3,12)=A(1:3,16)
40
A(4,1) = 2;
A(4,6) = 5;
A(4,8) = 1;
A(4,9) = 3;
A(4,12) = 6;
A(4,16) = 10;
for A(4,k) corresponding to X, I associate 2 if A(4,k)<= 5, and 1 if A(4,k)> 5. For the rest of the value of A(4,k) which do not correspond to X, I associate 0:
[ 1 2 3 4 5 %% value of the fourth line of A between 1 and 5
2 2 2 0 2
ZX = 6 7 8 9 10 %% value of the fourth line of A between 6 and 10
1 0 0 0 1
2 2 2 0 2 ] %% = max(ZX(2,k),ZX(4,k))
the ultimate goal is to find the matrix M:
M = [ 1 2 3 4 5
XXY ABC EFG TXG ZPF
2 2 2 0 2 ] %% M(3,:)=ZX(5,:)
Code -
%// Assuming A, X and names to be given to the solution
A = [20 52 70 20 52 20 52 20 20 10 52 20 11 1 52 20
32 24 91 44 60 32 24 32 32 12 11 32 2 5 24 32
40 37 24 30 11 40 37 40 40 5 10 40 40 3 37 40
2 4 1 3 4 5 2 1 3 3 8 6 7 9 6 10];
X = [20 ; 32 ; 40];
names = {'XXY','ABC','EFG','TXG','ZPF'};
limit = 10; %// The maximum limit of A(4,:). Edit this to 200 for your actual case
%// Find matching 4th row elements
matches = A(4,ismember(A(1:3,:)',X','rows'));
%// Matches are compared against all possible numbers between 1 and limit
matches_pos = ismember(1:limit,matches);
%// Finally get the line 3 results of M
vals = max(2*matches_pos(1:limit/2),matches_pos( (limit/2)+1:end ));
Output -
vals =
2 2 2 0 2
For a better way to present the results, you can use a struct -
M_struct = cell2struct(num2cell(vals),names,2)
Output -
M_struct =
XXY: 2
ABC: 2
EFG: 2
TXG: 0
ZPF: 2
For writing the results to a text file -
output_file = 'results.txt'; %// Edit if needed to be saved to a different path
fid = fopen(output_file, 'w+');
for ii=1:numel(names)
fprintf(fid, '%d %s %d\n',ii, names{ii},vals(ii));
end
fclose(fid);
Text contents of the text file would be -
1 XXY 2
2 ABC 2
3 EFG 2
4 TXG 0
5 ZPF 2
A bsxfun() based approach.
Suppose your inputs are (where N can be set to 200):
A = [20 52 70 20 52 20 52 20 20 10 52 20 11 1 52 20
32 24 91 44 60 32 24 32 32 12 11 32 2 5 24 32
40 37 24 30 11 40 37 40 40 5 10 40 40 3 37 40
2 4 1 3 4 5 2 1 3 3 8 6 7 9 6 10]
X = [20; 32; 40]
N = 10;
% Match first 3 rows and return 4th
idxA = all(bsxfun(#eq, X, A(1:3,:)));
Amatch = A(4,idxA);
% Match [1:5; 5:10] to 4th row
idxZX = ismember([1:N/2; N/2+1:N], Amatch)
idxZX =
1 1 1 0 1
1 0 0 0 1
% Return M3
M3 = max(bsxfun(#times, idxZX, [2;1]))
M3 =
2 2 2 0 2

Comparing content of two columns in MATLAB

I need to compare the content of two tables, more exactly two columns (one column per table), in MATLAB to see for each element of the first column, if there is an equal element in the second column.
Should I use a for loop or is there an existing MATLAB function that does this?
If the order is important, you do element-wise comparison, after which you use all
%# create two arrays
A = [1,2;1,3;2,5;3,3];
B = [2,2;1,3;1,5;3,3];
%# compare the second column of A and B, and check if the comparison is `true` for all elements
all(A(:,2)==B(:,2))
ans =
1
If the order is unimportant and all elements are unique, use ismember
all(ismember(A(:,1),B(:,1))
ans =
1
If the order is unimportant, and there are repetitions, use sort
all(sort(A(:,1))==sort(B(:,2)))
ans =
0
did you know you could do this:
>> a = [1:5];
>> b = [5:-1:1];
>> a == b
ans =
0 0 1 0 0
so you could compare 2 columns in matlab by using the == operator on the whole column. And you could use the result from that as a index specifier to get the equal values. Like this:
>> a(a == b)
ans =
3
This mean, select all the elements out of a for which a == b is true.
For example you could also select all the elements out of a which are larger than 3:
>> a(a > 3)
ans =
4 5
Using this knowledge I would say you could solve your problem.
For arithmetic values, both solutions mentioned will work. For strings or cell arrays of strings, use strcmp/strcmpi.
From the help file:
TF = strcmp(C1, C2) compares each element of C1 to the same element in C2, where C1 and C2 are equal-size cell arrays of strings. Input C1 or C2 can also be a character array with the right number of rows. The function returns TF, a logical array that is the same size as C1 and C2, and contains logical 1 (true) for those elements of C1 and C2 that are a match, and logical 0 (false) for those elements that are not.
An example (also from the help file):
Example 2
Create 3 cell arrays of strings:
A = {'MATLAB','SIMULINK';'Toolboxes','The MathWorks'};
B = {'Handle Graphics','Real Time Workshop';'Toolboxes','The MathWorks'};
C = {'handle graphics','Signal Processing';' Toolboxes', 'The MATHWORKS'};
Compare cell arrays A and B with sensitivity to case:
strcmp(A, B)
ans =
0 0
1 1
Compare cell arrays B and C without sensitivity to case. Note that 'Toolboxes' doesn't match because of the leading space characters in C{2,1} that do not appear in B{2,1}:
strcmpi(B, C)
ans =
1 0
0 1
To get a single return value rather than an array of logical values, use the all function as explained by Jonas.
You can use for loop (code below) to compare the content of the column 1 and column % 2 in the same table:
clc
d=[ 19 24 16 12 35 0
16 16 18 0 23 18
16 10 7 10 13 24
19 8 30 0 12 26
16 12 4 1 13 12
24 0 31 0 40 0
12 11 10 6 20 0
16 11 6 2 25 9
17 9 21 0 17 8
20 0 7 10 22 0
13 16 12 18 17 13
17 23 17 0 23 20
25 0 10 3 17 15
14 4 4 17 12 10
19 24 21 5 35 0
15 20 5 0 10 31
13 8 0 16 40 0
18 27 26 1 19 14
12 0 2 0 12 4
20 0 6 2 15 21
20 0 26 0 18 26
12 11 1 13 19 15
14 0 20 0 9 16
14 15 6 12 40 0
20 0 8 10 18 12
10 11 14 0 13 11
5 0 22 0 8 12 ];
x1=d(:,1);
y1=d(:,2);
for i=1:27
if x1(i)>y1(i);
z(i)=x1(i);
else
z(i)=y1(i);
end
end
z'