Issue trying to sub sample an image - matlab

I am trying to resize a given image by sub-sampling it. I am using grayscae iamges.
The way I understand sub-sampling is basically this:
Let's say we have an 5x5 image and we want to resize it by a factor of 2, so the output image will be 3x3.
So if the 5x5 is: (1 2 3 4 5; 6 7 8 9 10; 11 12 13 14 15; 16 17 18 19 20; 21 22 23 24 25)
Then the 3x3 will be: (1 3 5; 11 13 15; 21 23 25)
So if the factor is 2, for the first row we take the first sample and then every second sample and so on. The same for columns.
The code that I wrote for this is:
i = 0;
j = 0;
for row=1:old_rows
if mod((row-1), a) == 0
i = i + 1;
end
for col=1:old_cols
if mod((row-1), a) == 0 && mod((col-1), a) == 0
j = j + 1;
sub_sampled_I(i, j) = I(row, col); % I is the input image
end
end
j = 0;
end
sub_sampled_I = im2uint8(sub_sampled_I);
end
The issue is that the final image has nothing to do with the original. It is just a white image with some black points here and there. What I understand wrong about sub-sampling?

Related

How to shift non circularly in Matlab

I am trying to shift non circularly in MATLAB so even if I shift outside of the index it will add 0s to correct it. I tried following the answer in How do I shift columns (left or right) in a matrix? but had no success.
data = [1 2 3 4 5; 11 12 13 14 15; 21 22 23 24 25; 31 32 33 34 35]
d = 3; % shift; positive/negative for right/left
result = zeros(size(data), 'like', data); % preallocate with zeros
result(:,max(1,1+d):min(end,end+d)) = data(:,max(1,1-d):min(end,end-d)); % write values
In my output results is nothing but the same size but all zeroes
Desired output:
0 0 0 1 2 3 4 5
0 0 0 11 12 13 14 15
0 0 0 21 22 23 24 25
0 0 0 31 32 33 34 35
You can do it by creating a matrix result, the final size, filled with zeros, then copying the original data into the final result, making sure you place the data at the right indices.
What you have in your example code is not right for what you ask. If I run it,the final result is padded fine but truncated at the size of the original data matrix. This is how some matrix are shifted (with the shifted columns dropped altogether), but that's not what you asked.
A simple way to do it, is to create a padding matrix of the proper size, then simply concatenate it with your original data matrix. This can be done as below:
%% Initial data
data = [1 2 3 4 5; 11 12 13 14 15; 21 22 23 24 25; 31 32 33 34 35] ;
d = 3 ;
%% shift and pad with zeros
nrows = size(data,1) ; % Number of rows in [data]
pad = zeros( nrows , abs(d) ) ; % create padding matrix
if d>0
result = [pad data] ; % Concatenate the filler matrix on the left
else
result = [data pad] ; % Concatenate the filler matrix on the right
end
And just to be sure:
>> result
result =
0 0 0 1 2 3 4 5
0 0 0 11 12 13 14 15
0 0 0 21 22 23 24 25
0 0 0 31 32 33 34 35
If you want to reuse the same way than in your example code, you have to adjust it a bit to allow for the new columns:
%% create result and copy data
result = zeros( size(data,1) , size(data,2)+abs(d) ) ;
colStart = max(1,1+d) ;
result(:,colStart:colStart+size(data,2)-1) = data ;
This will create the same result matrix as above.

Create new matrix based on diagonal and antidiagonal of given matrix

I want to create matrix B from matrix A, with the following rules:
Non-diagonal elements A are like non-diagonal elements of B.
The main diagonal of A is the antidiagonal of B
The antidiagonal of A is the main diagonal of B.
For example:
A = [ 1 2 3 4;
7 8 9 10;
13 14 15 16;
19 20 21 22 ];
B = [ 4 2 3 1;
7 9 8 10;
13 15 14 16;
22 20 21 19 ];
How can I create B given A?
You can create all of the indices, then it's a single assignment.
% Get size of square matrix A
n = size(A,1);
% Indicies are 1:n^2 by default
idx = 1:n^2;
% Swap diagonal and antidiagonal indices
idx( [1:(n+1):n^2, n^2-n+1:1-n:n] ) = [n^2-n+1:1-n:n, 1:(n+1):n^2];
% Use the indexing array to create B from A, reshape to be n*n
B = reshape( A( idx ), n, n );
Output for your example A:
B =
4 2 3 1
7 9 8 10
13 15 14 16
22 20 21 19
There are so many ways to reach that results, it is just an indexing exercise. Here is one (of the many) way to reach that result for any square matrix of size n:
%% input
A=[ 1 2 3 4 ;
7 8 9 10 ;
13 14 15 16 ;
19 20 21 22 ];
%% Calculate linear indices for the diagonal and antidiagonal
n=size(A,1) ;
idxdiag = 1:(n+1):n^2 ; % => idxdiag = [1 6 11 16]
idxantidiag = n:(n-1):n^2-1 ; % => idxantidiag = [4 7 10 13]
%% Generate B
B = A ; % start with a simple copy (for the non-diagonal elements)
% Method 1: direct indice assignment
B(idxdiag) = diag(fliplr(A)) ; % Assign diagonal elements of B
B(idxantidiag) = flipud(diag(A)) ; % Assign antidiagonal elements of B
% Method 2: summation
B([idxdiag idxantidiag]) = 0 ;
B = B + diag(diag(fliplr(A))) + fliplr(diag(diag(A))) ;
B =
4 2 3 1
7 9 8 10
13 15 14 16
22 20 21 19
Both methods return exactly the same matrix B.
I suggest you familiarise yourself with the MATLAB function used to understand what is going on behind the scene:
fliplr
flipud
diag
and may be have a read at:
Matrix Indexing in MATLAB
I thought a little differently and came to a conclusion
A=[1 2 3 4;7 8 9 10;13 14 15 16; 19 20 21 22];;
n=size(A,1) ;
B=zeros(n,n) ;
for i=1:n
for j=1:n
if i==j
B(i,j)=A(i,n-i+1);
elseif j==n-i+1
B(i,j)=A(i,i);
else
B(i,j)=A(i,j);
end
end
end
B
Here's a variant using eye, find, and flip to generate linear indices:
ind1 = find(eye(size(A)));
ind2 = flip(find(flip(eye(size(A)))));
B = A;
B([ind1 ind2]) = B([ind2 ind1]);
B =
4 2 3 1
7 9 8 10
13 15 14 16
22 20 21 19
And here's a variant of the above that uses just eye and flip to generate logical indices:
ind1 = eye(size(A), 'logical');
ind2 = flip(ind1);
B = A;
B(ind1) = flip(A(ind2));
B(ind2) = flip(A(ind1));
B =
4 2 3 1
7 9 8 10
13 15 14 16
22 20 21 19

concurrent for loop over 2 variables

Is it possible in Octave to made 2 loops in the same time like :
(for i=0:10 && j=10:20)
i;
j;
end
If the loops are of the same length, then yes. Not well known is that for non-vectors, a for loop, loops over columns. So just place your vectors in a matrix, one row per variable:
for r = [0:10; 10:20]
printf ("1st is %2i; 2nd is %2i\n", r(1), r(2));
endfor
which returns:
1st is 0; 2nd is 10
1st is 1; 2nd is 11
1st is 2; 2nd is 12
1st is 3; 2nd is 13
1st is 4; 2nd is 14
1st is 5; 2nd is 15
1st is 6; 2nd is 16
1st is 7; 2nd is 17
1st is 8; 2nd is 18
1st is 9; 2nd is 19
1st is 10; 2nd is 20
In Matlab you can use arrayfun with two input arrays of the same size:
>> arrayfun(#(x,y) x+y, 1:10, 10:10:100)
ans =
11 22 33 44 55 66 77 88 99 110
If you want them to move in step then use a counter variable to reference them as arrays:
j = 0:10;
i = 0:10;
for k = 1:11
i(k);
j(k);
end
But you most likely need to make nested for loops:
for i = 0:10
for j = 0:10
i;
j;
end
end

Setting a specified number of rows in each column and block of elements to zero

Is there any easy way to set a specified number of rows k in nth column to zero ? Its a bit tricky question to explain so I guess its best to look at the example.
Lets say I have:
A =
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
16 17 18
I wish to set rows, like this: [row1 col1] = 0; [row2 col1] = 0, and then [row3 col2]= 0; row4 col2]= 0 and so on, so my output is:
k = 2
B =
0 2 3
0 5 6
7 0 9
10 0 12
13 14 0
16 17 0
Do you have any suggestions/solutions how this could be solved with a for loop, or maybe there is another way?
and how this solution could be extend further to something like this:
A =
1 2 3 1 2 3
4 5 6 4 5 6
7 8 9 7 8 9
10 11 12 10 11 12
13 14 15 13 14 15
16 17 18 16 17 18
B =
0 0 3 1 2 3
0 0 6 4 5 6
7 8 0 0 8 9
10 11 0 0 3 1
13 14 15 13 0 0
16 17 18 16 0 0
One approach -
k = 2;
row1 = 1:size(A,1)
col1 = ceil([1:size(A,1)]./k)
A(sub2ind(size(A),row1,col1))=0
For the edited question, use kron like this -
k = 2;
a1 = eye(size(A)./k);
b1 = ones(k,k);
A(logical(kron(a1,b1)))=0
That isn't a problem. We can figure out exactly which rows and columns you want to set to 0 based on this value k, then use sub2ind to get a single index to access into your matrix. This will be in column-major format. Then you can use this and set all of your values to zero. Here is an example. We need to know the width and height of your matrix first before we do this:
rows = [row1 row2 row3];
cols = [col1 col2 col3];
%// Get column major indices
ind = sub2ind([height width], rows, cols);
%// Set the values in this matrix to 0.
B(ind) = 0;
Now with your example, we need to access all of the rows. However, for the columns, we need to access k elements in each column and ensuring they don't overlap. As such, we can do it like so:
k = 2;
B = reshape(1:18, 6, 3).';
rows = 1 : 6;
cols = ceil(rows / k);
ind = sub2ind([rows cols], rows, cols);
B(ind) = 0;
You would thus get:
B =
0 2 3
0 5 6
7 0 9
10 0 12
13 14 0
16 17 0
The following code is executable in matlab, and does what you want:
% Create A-matrix
A = reshape(1:18,6,3)
% Set specified datapoints to zero
A([1,2],[1,1]) = 0
Alternatively, you can set each element separately
A(1,1) = 0
A(1,2) = 0
And the most general way, with k and n:
A([1:k],n) = 0
For first question:
A(mod(0:numel(A)-1, size(A,1)+k) < k) = 0;
For second question, including first question as a particular case:
c = repmat({ones(k,size(B,2)/size(B,1)*k)}, size(B,1)/k, 1);
B = B.*~blkdiag(c{:})

Matlab Matrix Counter rotation of elements

Hi i would like to create a function which rotates all elements counter clockwise by one place of a square matrix.
[ 1 2 3 4;
5 6 7 8;
9 10 11 12;
13 14 15 16]
shall become:
[ 2 3 4 8;
1 7 11 12;
5 6 10 16;
9 13 14 15]
This is my attempt:
size_mat = size(A,1)
B=zeros(size_mat);
loops = fix(size_mat/2)
if mod(size_mat,2) ~= 0
B(loops+1,loops+1)= A(loops+1,loops+1)
end
for i=1:loops,
B(i+1,i)=A(i,i);
for j=i:(size_mat-i)
B(i,j)=A(i,j+1);
B(j,size_mat+1-i)=A(j+1,size_mat+1-i);
B(size_mat+1-i,size_mat+1-j)=A(size_mat+1-i,size_mat-j);
if((j+2)<=size_mat)
B(size_mat+1-j,i)=A(size_mat-j,i);
end
end
end
Can I do better?
Code
%%// A is the input matrix
N = size(A,1)
sz = ceil(N/2)
quad4 = ones(sz)
quad1 = quad4
quad1(logical(fliplr(triu(ones(sz),1))))=N
quad4(logical(tril(quad4)))=-N
quad14 = [quad1;quad4]
quad = [-1*rot90(quad14,2) quad14]
if rem(N,2)==1
quad(:,sz)=[]
quad(sz,:)=[]
quad(sz,sz)=0
end
rotatedA = A(reshape(1:numel(A),size(A))+quad) %%// rotated output matrix