Drawing a line of ones on a matrix - matlab

I have a matrix m = zeros(1000, 1000). Within this matrix I want to draw an estimate of the line which passes through 2 points from my matrix. Let's say x = [122 455]; and y = [500 500];.
How can I do this in Matlab? Are there any predefined functions to do this? I am using Matlab 2012b.

I'll denote the two endpoints as p1 and p2 because I'm planning to use x and y for something else. I'm also assuming that the first coordinate of p1 and p2 is x and the second is y. So here's a rather simple way to do it:
Obtain the equation of the line y = ax + b. In MATLAB, this can be done by:
x = p1(1):p2(1)
dx = p2(1) - p1(1);
dy = p2(2) - p1(2);
y = round((x - p1(1)) * dy / dx + p1(2));
Convert the values of x and y to indices of elements in the matrix, and set those elements to 1.
idx = sub2ind(size(m), y, x);
m(idx) = 1;
Example
Here's an example for a small 10-by-10 matrix:
%// This is our initial conditon
m = zeros(10);
p1 = [1, 4];
p2 = [5, 7];
%// Ensure the new x-dimension has the largest displacement
[max_delta, ix] = max(abs(p2 - p1));
iy = length(p1) - ix + 1;
%// Draw a line from p1 to p2 on matrix m
x = p1(ix):p2(ix);
y = round((x - p1(ix)) * (p2(iy) - p1(iy)) / (p2(ix) - p1(ix)) + p1(iy));
m(sub2ind(size(m), y, x)) = 1;
m = shiftdim(m, ix > iy); %// Transpose result if necessary
The result is:
m =
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 0 1 1 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 0 0 0
0 0 0 0 0 0 0 0 0 0
Update: I have patched this algorithm to work when dy > dx by treating the dimension with the largest displacement as if it were the x-dimension, and then transposing the result if necessary.

Neither of the provided answers work for displacements in y greater than in x (dy > dx).
As pointed out, Bresenham's line algorithm is exactly meant for that.
The matlab file provided here works similarly than the examples provided in the other answers but covers all the use-cases.
To relate to the previously provided example, the script can be used like this:
% initial conditions
m = zeros(10);
p1 = [1, 4];
p2 = [5, 10];% note dy > dx
% use file provided on file exchange
[x y] = bresenham(p1(1),p1(2),p2(1),p2(2));
% replace entries in matrix m
m(sub2ind(size(m), y, x)) = 1;
result looks like this:
m =
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0

For me (matlab R2013b) following line did not work, when p1(1)>p2(2) (":" can not count backwards):
x = p1(1):p2(1);
E.G.:
1:10
1 2 3 4 5 6 7 8 9 10
10:1
Empty matrix: 1-by-0
But it worked when I used linspac instead:
x = linspace(p1(1), p2(1), abs(p2(1)-p1(1))+1);

Related

Changing the diagonals beside center diagonal of matrix

Is there a quick way to change the diagonals beside the center diagonal (referring to the 1s below):
m =
2 1 0 0 0 0 0 0 0
1 2 1 0 0 0 0 0 0
0 1 2 1 0 0 0 0 0
0 0 1 2 1 0 0 0 0
0 0 0 1 2 1 0 0 0
0 0 0 0 1 2 1 0 0
0 0 0 0 0 1 2 1 0
0 0 0 0 0 0 1 2 1
0 0 0 0 0 0 0 1 2
A quick way to change the center diagonal is m(logical(eye(size(m)))) = 2. How about assigning the diagonals beside it to values of 1?
The diag function takes a second parameter, k, which specifies which diagonal to target:
diag([-1,-1,-1,-1],-1) % or diag(-1*ones(4,1),1)
ans =
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
diag([1,1,1,1],1)
ans =
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
diag([2,2,2],2)
ans =
0 0 2 0 0
0 0 0 2 0
0 0 0 0 2
0 0 0 0 0
0 0 0 0 0
If you already have an existing matrix and you want to change one of the diagonals you could do this:
M = magic(5) % example matrix
v = [1,2,3,4] % example vector that must replace the first diagonal of M, i.e. the diagonal one element above the main diagonal
M - diag(diag(M,1),1) + diag(v,1)
The idea is to first use diag to extract the numbers of the diagonal you want to change, diag(M,1). Then to use diag again to change the vector that the first call to diag created into a matrix, diag(diag(M,1),1). You'll notice that this creates a matrix with the same dimensions as M, the same numbers as M on the 1st diagonal and 0s everywhere else. Thus M - diag(diag(M,1),1) just sets that first diagonal to 0. Now diag(v,1) creates a matrix with the same dimensions as M that is 0 everywhere but with the numbers of v on the first diagonal and so adding diag(v,1) only affects that first diagonal which is all 0s thanks to -diag(diag(M,1),1)
An alternative if you are just applying a constant to a diagonal (for example setting all the values on the first diagonal below the main diagonal to 6):
n = 5;
k = -1;
a = 6;
M = magic(n);
ind = diag(true(n-abs(k),1),k);
M(ind) = a;

I'm using MATLAB R2015b, How do we generate a rectangular matrix with upper diagonal elements 1?

I am trying to generate a rectangular matrix with 1s on the diagonal above the main diagonal and -1s on the main diagonal. I used "eye" which does not create the diagonal above the main.
Please find my attempt to this below.
N = 5
M1 = -eye([N-1 N])
M2 = eye([N N-1])'
M = M1+M2
I am unable to resolve this issue on my own. Any help or links to relevant documentation would be greatly appreciated.
I don't know of any prebuild function, but you can easily make such a matrix yourself:
N=5;
M=7;
diag=-eye(N,M);
upper_diag=horzcat(zeros(N,1),eye(N,M-1))
final=diag+upper_diag
using the identity matrix and some concatenation to shift the diagonal around. This example assumes you are looking for a square matrix.
The result looks like:
final =
-1 1 0 0 0 0 0
0 -1 1 0 0 0 0
0 0 -1 1 0 0 0
0 0 0 -1 1 0 0
0 0 0 0 -1 1 0
Just create eye and diag matrices as per normal, add them together, then chop away the rows you do not need:
nCol = 7;
nRow = 5;
M = -eye(nCol) + diag(ones(nCol - 1, 1), 1);
M = M(1:nRow, 1:nCol)
produces
M =
-1 1 0 0 0 0 0
0 -1 1 0 0 0 0
0 0 -1 1 0 0 0
0 0 0 -1 1 0 0
0 0 0 0 -1 1 0
The four-input version of spdiags does just that, producing a sparse matrix. You may need to convert to full then.
M = 5; %// number of rows
N = 7; %// number of columns
d = [0 1]; %// specify main diagonal and the one above
v = [-1 1]; %// values in those diagonals
result = full(spdiags(ones(M,1)*v, d, M, N));
This gives
result =
-1 1 0 0 0 0 0
0 -1 1 0 0 0 0
0 0 -1 1 0 0 0
0 0 0 -1 1 0 0
0 0 0 0 -1 1 0

Creating MATLAB neural network target array from class labels [duplicate]

For neural networking, I would like to represent a column vector y = [1;2;3] in a matrix like so:
y = [1 0 0;
0 1 0;
0 0 1]
My vector y is very large, and so hardcoding is not an option. Also, I would like to avoid using for-loops.
What I did so far:
y1 =[y; zeros(1,length(y)) ;zeros(1,length(y))] % add two rows with zeros in orde to give y the right format
idx = find(y1(1,:) == 2); % find all the columns containing a 2
y1(:,idx(1):idx(end)) = y1(:,[0;1;0]); % this does not work because now I am comparing a matrix with a vector
I also tried this:
y1( y1 == [2;0;0] )=[0;1;0]; % This of course does not work
Is there a way to specify I want to compare columns in y1 == [2;0;0], or is there another way to solve this?
From the context of your question, you wish to find a matrix where each column is an identity vector. For an identity vector, each column in this matrix is a non-zero vector where 1 is set in the position of the vector denoted by each position of y and 0 otherwise. Therefore, let's say we had the following example:
y = [1 5 4 3]
You would have y_out as the final matrix, which is:
y_out =
1 0 0 0
0 0 0 0
0 0 0 1
0 0 1 0
0 1 0 0
There are several ways to do this. The easiest one would be to declare the identity matrix with eye, then let y pick out those columns that you want from this matrix and place them as columns into your final matrix. If y had all unique values, then we would simply be rearranging the columns of this identity matrix based on y. As such:
y_out = eye(max(y));
y_out = y_out(:,y)
y_out =
1 0 0 0
0 0 0 0
0 0 0 1
0 0 1 0
0 1 0 0
Another way would be to declare a sparse matrix, where each row index is simply those elements from y and each column index is increasing from 1 up to as many elements as we have y:
y_out = sparse(y, 1:numel(y), 1, max(y), numel(y));
y_out = full(y_out)
y_out =
1 0 0 0
0 0 0 0
0 0 0 1
0 0 1 0
0 1 0 0
One more way would be to use sub2ind to find linear indices into your matrix, then access those elements and set them to 1. Therefore:
ind = sub2ind([max(y) numel(y)], y, 1:numel(y));
y_out = zeros(max(y), numel(y));
y_out(ind) = 1
y_out =
1 0 0 0
0 0 0 0
0 0 0 1
0 0 1 0
0 1 0 0
This works even if y has "missing" values:
n = numel(y);
y_matrix = zeros(n, max(y));
y_matrix((1:n) + (y-1)*n) = 1;
Example:
y = [1 5 3 2];
gives
y_matrix =
1 0 0 0 0
0 0 0 0 1
0 0 1 0 0
0 1 0 0 0
You can use bsxfun:
y_out = bsxfun(#eq, (1:max(y)).', y);
Not as efficient as the #rayryeng's answer but this might also help,
Also if there are repeated values in y this code works fine.
a = [1 2 3 2 5 7 6 8];
[X,Y] = meshgrid(a,1 : length(a));
A = X == Y;
A =
1 0 0 0 0 0 0 0
0 1 0 1 0 0 0 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1

Replace specific columns in a matrix with a constant column vector

For neural networking, I would like to represent a column vector y = [1;2;3] in a matrix like so:
y = [1 0 0;
0 1 0;
0 0 1]
My vector y is very large, and so hardcoding is not an option. Also, I would like to avoid using for-loops.
What I did so far:
y1 =[y; zeros(1,length(y)) ;zeros(1,length(y))] % add two rows with zeros in orde to give y the right format
idx = find(y1(1,:) == 2); % find all the columns containing a 2
y1(:,idx(1):idx(end)) = y1(:,[0;1;0]); % this does not work because now I am comparing a matrix with a vector
I also tried this:
y1( y1 == [2;0;0] )=[0;1;0]; % This of course does not work
Is there a way to specify I want to compare columns in y1 == [2;0;0], or is there another way to solve this?
From the context of your question, you wish to find a matrix where each column is an identity vector. For an identity vector, each column in this matrix is a non-zero vector where 1 is set in the position of the vector denoted by each position of y and 0 otherwise. Therefore, let's say we had the following example:
y = [1 5 4 3]
You would have y_out as the final matrix, which is:
y_out =
1 0 0 0
0 0 0 0
0 0 0 1
0 0 1 0
0 1 0 0
There are several ways to do this. The easiest one would be to declare the identity matrix with eye, then let y pick out those columns that you want from this matrix and place them as columns into your final matrix. If y had all unique values, then we would simply be rearranging the columns of this identity matrix based on y. As such:
y_out = eye(max(y));
y_out = y_out(:,y)
y_out =
1 0 0 0
0 0 0 0
0 0 0 1
0 0 1 0
0 1 0 0
Another way would be to declare a sparse matrix, where each row index is simply those elements from y and each column index is increasing from 1 up to as many elements as we have y:
y_out = sparse(y, 1:numel(y), 1, max(y), numel(y));
y_out = full(y_out)
y_out =
1 0 0 0
0 0 0 0
0 0 0 1
0 0 1 0
0 1 0 0
One more way would be to use sub2ind to find linear indices into your matrix, then access those elements and set them to 1. Therefore:
ind = sub2ind([max(y) numel(y)], y, 1:numel(y));
y_out = zeros(max(y), numel(y));
y_out(ind) = 1
y_out =
1 0 0 0
0 0 0 0
0 0 0 1
0 0 1 0
0 1 0 0
This works even if y has "missing" values:
n = numel(y);
y_matrix = zeros(n, max(y));
y_matrix((1:n) + (y-1)*n) = 1;
Example:
y = [1 5 3 2];
gives
y_matrix =
1 0 0 0 0
0 0 0 0 1
0 0 1 0 0
0 1 0 0 0
You can use bsxfun:
y_out = bsxfun(#eq, (1:max(y)).', y);
Not as efficient as the #rayryeng's answer but this might also help,
Also if there are repeated values in y this code works fine.
a = [1 2 3 2 5 7 6 8];
[X,Y] = meshgrid(a,1 : length(a));
A = X == Y;
A =
1 0 0 0 0 0 0 0
0 1 0 1 0 0 0 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1

Matlab/Octave 1-of-K representation

I have a y of size 5000,1 (matrix), which contains integers between 1 and 10. I want to expand those indices into a 1-of-10 vector. I.e., y contains 1,2,3... and I want it to "expand" to:
1 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
What is the best way to do that?
I tried:
Y = zeros(5000,10); Y(y) = 1;
but it didn't work.
It works for vectors though:
if y = [2 5 7], and Y = zeros(1,10), then Y(y) = [0 1 0 0 1 0 1 0 0 0].
Consider the following:
y = randi([1 10],[5 1]); %# vector of 5 numbers in the range [1,10]
yy = bsxfun(#eq, y, 1:10)'; %# 1-of-10 encoding
Example:
>> y'
ans =
8 8 4 7 2
>> yy
yy =
0 0 0 0 0
0 0 0 0 1
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 1 0
1 1 0 0 0
0 0 0 0 0
0 0 0 0 0
n=5
Y = ceil(10*rand(n,1))
Yexp = zeros(n,10);
Yexp(sub2ind(size(Yexp),1:n,Y')) = 1
Also, consider using sparse, as in: Creating Indicator Matrix.
While sparse may be faster and save memory, an answer involving eye() would be more elegant as it is faster than a loop and it was introduced during the octave lecture of that class
Here is an example for 1 to 4
V = [3;2;1;4];
I = eye(4);
Vk = I(V, :);
You can try cellfun operations:
function vector = onehot(vector,decimal)
vector(decimal)=1;
end
aa=zeros(10,2);
dec=[5,6];
%split into columns
C=num2cell(aa,1);
D=num2cell(dec,1);
onehotmat=cellfun("onehot",C,D,"UniformOutput",false);
output=cell2mat(onehotmat);
I think you mean:
y = [2 5 7];
Y = zeros(5000,10);
Y(:,y) = 1;
After the question edit, it should be this instead:
y = [2,5,7,9,1,4,5,7,8,9....]; //(size (1,5000))
for i = 1:5000
Y(i,y(i)) = 1;
end