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

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

Related

How to rearrange matrix column into block using for loop?

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

Taking a matrix and retrieving both the diagonals keeping the dimensions of the original matrix in MATLAB

Given the matrix A = magic(5) you get:
A = 17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
I want to use commands such as rot90, diag, triu, tril and matrices sum to get the matrix:
A = 17 0 0 0 15
0 5 0 14 0
0 0 13 0 0
0 12 0 21 0
11 0 0 0 9
Please, if you can't think of a way to solve this without the commands I wrote, it's OK to do it your own way.
You can use eye function for indexing
>> A(~eye(size(A)) & ~flipud(eye(size(A))))=0
A =
17 0 0 0 15
0 5 0 14 0
0 0 13 0 0
0 12 0 21 0
11 0 0 0 9
You can simply use linear indexing to access the diagonals:
n = size(A,1);
B = zeros(n);
B( 1:(n+1):end ) = A( 1:(n+1):end ); %// main diagonal
B( n:(n-1):(end-n+1) ) = A( n:(n-1):(end-n+1) )
And you get
B =
17 0 0 0 15
0 5 0 14 0
0 0 13 0 0
0 12 0 21 0
11 0 0 0 9
Another approach is:
mDiag = diag(diag(A));
aDiag = rot90(diag(diag(rot90(A))))';
overlap = A.*((diag(diag(A)) ~= 0) & (rot90(diag(diag(rot90(A)))) ~= 0));
solution = mDiag + aDiag - overlap
And than:
solution =
17 0 0 0 15
0 5 0 14 0
0 0 13 0 0
0 12 0 21 0
11 0 0 0 9
Using bsxfun
out = A.*bsxfun(#(x,y) x == y | x+y == size(A,1)+1,(1:size(A,1)).',1:size(A,1)) %//'

How to add noise to an image loaded from .mat file?

So I have loaded the .mat file:
load Yale_32x32.mat;
X = fea';
I then can view the image using:
imshow(reshape(X(:,1),32,32),[])
There are 165 images, so the second dimension can be any number in the range from 1 to 165. Suppose, I want to add 'salt-pepper' noise to one of the images. If I try to do:
J = imnoise(reshape(X(:,1),32,32),'salt & pepper', 0.05);
and then:
imshow(J,[]);
... it will display to me a noise on the purely white background. What am I doing wrong?
EDIT
X(:,1) gives me:
70
68
49
53
50
50
37
33
26
13
17
61
69
109
....
etc.
After applying J = imnoise(X(:,1),'salt & pepper', 0.05);, I get:
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
0
1
1
etc.
EDIT
Fixed: I had to normalize my image. Thank you.

Is it possible to rotate a matrix by 45 degrees in matlab

i.e. so that it appears like a diamond. (it's a square matrix) with each row having 1 more element than the row before up until the middle row which has the number of elements equal to the dimensions of the original matrix, and then back down again with each row back to 1?
A rotation is of course not possible as the "grid" a matrix is based on is regular.
But I remember what your initially idea was, so the following will help you:
%example data
A = magic(5);
A =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
d = length(A)-1;
diamond = zeros(2*d+1);
for jj = d:-2:-d
ii = (d-jj)/2+1;
kk = (d-abs(jj))/2;
D{ii} = { [zeros( 1,kk ) A(ii,:) zeros( 1,kk ) ] };
diamond = diamond + diag(D{ii}{1},jj);
end
will return the diamond:
diamond =
0 0 0 0 17 0 0 0 0
0 0 0 23 0 24 0 0 0
0 0 4 0 5 0 1 0 0
0 10 0 6 0 7 0 8 0
11 0 12 0 13 0 14 0 15
0 18 0 19 0 20 0 16 0
0 0 25 0 21 0 22 0 0
0 0 0 2 0 3 0 0 0
0 0 0 0 9 0 0 0 0
Now you can again search for words or patterns row by row or column by column, just remove the zeros then:
Imagine you extract a single row:
row = diamond(5,:)
you can extract the non-zero elements with find:
rowNoZeros = row( find(row) )
rowNoZeros =
11 12 13 14 15
Not a real diamond, but probably useful as well:
(Idea in the comments by #beaker. I will remove this part, if he is posting it by himself.)
B = spdiags(A)
B =
11 10 4 23 17 0 0 0 0
0 18 12 6 5 24 0 0 0
0 0 25 19 13 7 1 0 0
0 0 0 2 21 20 14 8 0
0 0 0 0 9 3 22 16 15

(matlab) qtdecomp works with uint8 matrix?

I haven't fully understood how qtdecomp works...
I = [1 1 1 1 2 3 6 6
1 1 2 1 4 5 6 8
1 1 1 1 10 15 7 7
1 1 1 1 20 25 7 7
20 22 20 22 1 2 3 4
20 22 22 20 5 6 7 8
20 22 20 20 9 10 11 12
22 22 20 20 13 14 15 16];
S = qtdecomp(I,2);
disp(full(S));
The results of this are:
4 0 0 0 1 1 2 0
0 0 0 0 1 1 0 0
0 0 0 0 1 1 2 0
0 0 0 0 1 1 0 0
4 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1
in the left bottom 4*4 matrix, maximum value (22) of the block elements minus the minimum value (20) is 2, so when decomposing this part, it will left as is.
When I do this on a uint8 matrix:
I = uint8([...
1 1 1 1 2 3 6 6
1 1 2 1 4 5 6 8
1 1 1 1 10 15 7 7
1 1 1 1 20 25 7 7
20 22 20 22 1 2 3 4
20 22 22 20 5 6 7 8
20 22 20 20 9 10 11 12
22 22 20 20 13 14 15 16]);
S = qtdecomp(I,2/255);
disp(full(S));
the answer is just like before. But when I change S to this:
S = qtdecomp(I,1.9/255);
The answer is
4 0 0 0 1 1 2 0
0 0 0 0 1 1 0 0
0 0 0 0 1 1 2 0
0 0 0 0 1 1 0 0
4 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1
I suppose the left bottom 4*4 matrix should decompose, but why doesn't it?
What matlab does here is when I is uint8 it multiples the threshold by 255 and rounds it, so 1.9/255 is evaluated to 2.
You can see this by opening the source code for qtdecomp (by pressing ctrl+D) or here. There's an if/elseif near the end of the file (params{1} = round(255 * params{1});).
You should be able to use S = qtdecomp(I,1/255); to get the result you are looking for.