This question already has answers here:
Create a zero-filled 2D array with ones at positions indexed by a vector
(4 answers)
Closed 5 years ago.
Often you are given a vector of integer values representing your labels (aka classes), for example
[2; 1; 3; 3; 2]
and you would like to hot one encode this vector, such that each value is represented by a 1 in the column indicated by the value in each row of the labels vector, for example
[0 1 0;
1 0 0;
0 0 1;
0 0 1;
0 1 0]
For speed and memory savings, you can use bsxfun combined with eq to accomplish the same thing. While your eye solution may work, your memory usage grows quadratically with the number of unique values in X.
Y = bsxfun(#eq, X(:), 1:max(X));
Or as an anonymous function if you prefer:
hotone = #(X)bsxfun(#eq, X(:), 1:max(X));
Or if you're on Octave (or MATLAB version R2016b and later) , you can take advantage of automatic broadcasting and simply do the following as suggested by #Tasos.
Y = X == 1:max(X);
Benchmark
Here is a quick benchmark showing the performance of the various answers with varying number of elements on X and varying number of unique values in X.
function benchit()
nUnique = round(linspace(10, 1000, 10));
nElements = round(linspace(10, 1000, 12));
times1 = zeros(numel(nUnique), numel(nElements));
times2 = zeros(numel(nUnique), numel(nElements));
times3 = zeros(numel(nUnique), numel(nElements));
times4 = zeros(numel(nUnique), numel(nElements));
times5 = zeros(numel(nUnique), numel(nElements));
for m = 1:numel(nUnique)
for n = 1:numel(nElements)
X = randi(nUnique(m), nElements(n), 1);
times1(m,n) = timeit(#()bsxfunApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times2(m,n) = timeit(#()eyeApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times3(m,n) = timeit(#()sub2indApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times4(m,n) = timeit(#()sparseApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times5(m,n) = timeit(#()sparseFullApproach(X));
end
end
colors = get(0, 'defaultaxescolororder');
figure;
surf(nElements, nUnique, times1 * 1000, 'FaceColor', colors(1,:), 'FaceAlpha', 0.5);
hold on
surf(nElements, nUnique, times2 * 1000, 'FaceColor', colors(2,:), 'FaceAlpha', 0.5);
surf(nElements, nUnique, times3 * 1000, 'FaceColor', colors(3,:), 'FaceAlpha', 0.5);
surf(nElements, nUnique, times4 * 1000, 'FaceColor', colors(4,:), 'FaceAlpha', 0.5);
surf(nElements, nUnique, times5 * 1000, 'FaceColor', colors(5,:), 'FaceAlpha', 0.5);
view([46.1000 34.8000])
grid on
xlabel('Elements')
ylabel('Unique Values')
zlabel('Execution Time (ms)')
legend({'bsxfun', 'eye', 'sub2ind', 'sparse', 'full(sparse)'}, 'Location', 'Northwest')
end
function Y = bsxfunApproach(X)
Y = bsxfun(#eq, X(:), 1:max(X));
end
function Y = eyeApproach(X)
tmp = eye(max(X));
Y = tmp(X, :);
end
function Y = sub2indApproach(X)
LinearIndices = sub2ind([length(X),max(X)], [1:length(X)]', X);
Y = zeros(length(X), max(X));
Y(LinearIndices) = 1;
end
function Y = sparseApproach(X)
Y = sparse(1:numel(X), X,1);
end
function Y = sparseFullApproach(X)
Y = full(sparse(1:numel(X), X,1));
end
Results
If you need a non-sparse output bsxfun performs the best, but if you can use a sparse matrix (without conversion to a full matrix), then that is the fastest and most memory efficient option.
You can use the identity matrix and index into it using the input/labels vector, for example if the labels vector X is some random integer vector
X = randi(3,5,1)
ans =
2
1
2
3
3
then, the following will hot one encode X
eye(max(X))(X,:)
which can be conveniently defined as a function using
hotone = #(v) eye(max(v))(v,:)
EDIT:
Although the solution above works in Octave, you have you modify it for Matlab as follows
I = eye(max(X));
I(X,:)
I think this is fast specially when matrix dimension grows:
Y = sparse(1:numel(X), X,1);
or
Y = full(sparse(1:numel(X), X,1));
Just posting the sub2ind solution too to satisfy your curiosity :)
But I like your solution better :p
>> X = [2,1,2,3,3]'
>> LinearIndices = sub2ind([length(X),3], [1:length(X)]', X);
>> tmp = zeros(length(X), 3);
>> tmp(LinearIndices) = 1
tmp =
0 1 0
1 0 0
0 1 0
0 0 1
0 0 1
Just in case someone is looking for the 2D case (as I was):
X = [2 1; ...
3 3; ...
2 4]
Y = zeros(3,2,4)
for i = 1:4
Y(:,:,i) = ind2sub(X,X==i)
end
gives a one-hot encoded matrix along the 3rd dimension.
I'm currently trying to implement the HS-method for optical flow but my u and v always seem to have only zeros in them. I can't seem to figure out my error in here:
vid=VideoReader('outback.AVI');
vid.CurrentTime = 1.5;
alpha=1;
iterations=10;
frame_one = readFrame(vid);
vid.CurrentTime = 1.6;
frame_two = readFrame(vid);
% convert to grayscale
fone_gr = rgb2gray(frame_one);
ftwo_gr = rgb2gray(frame_two);
% construct for each image
sobelx=[-1 -2 -1; 0 0 0; 1 2 1];
sobely=sobelx';
time=[-1 1];
fx_fone=imfilter(fone_gr, sobelx);
fy_fone=imfilter(fone_gr, sobely);
ft_fone=imfilter(fone_gr, time);
fx_ftwo=imfilter(ftwo_gr, sobelx);
fy_ftwo=imfilter(ftwo_gr, sobely);
ft_ftwo=imfilter(ftwo_gr, time);
Ix=double(fx_fone+fx_ftwo);
Iy=double(fy_fone+fy_ftwo);
It=double(ft_fone+ft_ftwo);
% flow-variables (velocity = 0 assumption)
velocity_kernel=[0 1 0; 1 0 1; 0 1 0];
u = double(0);
v = double(0);
% iteratively solve for u and v
for i=1:iterations
neighborhood_average_u=conv2(u, velocity_kernel, 'same');
neighborhood_average_v=conv2(v, velocity_kernel, 'same');
data_term = (Ix .* neighborhood_average_u + Iy .* neighborhood_average_v + It);
smoothness_term = alpha^2 + (Ix).^2 + (Iy).^2;
numerator_u = Ix .* data_term;
numerator_v = Iy .* data_term;
u = neighborhood_average_u - ( numerator_u ./ smoothness_term );
v = neighborhood_average_v - ( numerator_v ./ smoothness_term );
end
u(isnan(u))=0;
v(isnan(v))=0;
figure
imshow(frame_one); hold on;
quiver(u, v, 5, 'color', 'b', 'linewidth', 2);
set(gca, 'YDir', 'reverse');
The only thing I'm not really confident about is the computation of the neighborhood average:
velocity_kernel=[0 1 0; 1 0 1; 0 1 0];
u = double(0);
v = double(0);
[..]
neighborhood_average_u=conv2(u, velocity_kernel, 'same');
neighborhood_average_v=conv2(v, velocity_kernel, 'same');
Wouldn't that always result in a convolution matrix with only zeros?
I thought about changing it to the following, since I need to compute the average velocity using the velocity kernel on each pixel of my images:
velocity_kernel=[0 1 0; 1 0 1; 0 1 0];
u = double(0);
v = double(0);
[..]
neighborhood_average_u=conv2(Ix, velocity_kernel, 'same');
neighborhood_average_v=conv2(Iy, velocity_kernel, 'same');
But I still don't know if that would be the correct way. I followed the instructions on the bottom of this MATLAB page:
http://de.mathworks.com/help/vision/ref/opticalflowhs-class.html
I found this paper with some further explanations and also some matlab code.
They compute the average of u and v as follows:
% initial values
u = 0; v = 0;
% weighted average kernel
kernel = [1/12 1/6 1/12; 1/6 0 1/6; 1/12 1/6 1/12];
for i = 1:iterations
uAvg = conv2( u, kernel 'same' );
vAvg = conv2( v, kernel 'same' );
...
end
I want to speed up my code. I always use vectorization. But in this code I have no idea how to avoid the for-loop. I would really appreciate a hint how to proceed.
thank u so much for your time.
close all
clear
clc
% generating sample data
x = linspace(10,130,33);
y = linspace(20,100,22);
[xx, yy] = ndgrid(x,y);
k = 2*pi/50;
s = [sin(k*xx+k*yy)];
% generating query points
xi = 10:5:130;
yi = 20:5:100;
[xxi, yyi] = ndgrid(xi,yi);
P = [xxi(:), yyi(:)];
% interpolation algorithm
dx = x(2) - x(1);
dy = y(2) - y(1);
x_ = [x(1)-dx x x(end)+dx x(end)+2*dx];
y_ = [y(1)-dy y y(end)+dy y(end)+2*dy];
s_ = [s(1) s(1,:) s(1,end) s(1,end)
s(:,1) s s(:,end) s(:,end)
s(end,1) s(end,:) s(end,end) s(end,end)
s(end,1) s(end,:) s(end,end) s(end,end)];
si = P(:,1)*0;
M = 1/6*[-1 3 -3 1
3 -6 3 0
-3 0 3 0
1 4 1 0];
tic
for nn = 1:numel(P(:,1))
u = mod(P(nn,1)- x_(1), dx)/dx;
jj = floor((P(nn,1) - x_(1))/dx) + 1;
v = mod(P(nn,2)- y_(1), dy)/dy;
ii = floor((P(nn,2) - y_(1))/dy) + 1;
D = [s_(jj-1,ii-1) s_(jj-1,ii) s_(jj-1,ii+1) s_(jj-1,ii+2)
s_(jj,ii-1) s_(jj,ii) s_(jj,ii+1) s_(jj,ii+2)
s_(jj+1,ii-1) s_(jj+1,ii) s_(jj+1,ii+1) s_(jj+1,ii+2)
s_(jj+2,ii-1) s_(jj+2,ii) s_(jj+2,ii+1) s_(jj+2,ii+2)];
U = [u.^3 u.^2 u 1];
V = [v.^3 v.^2 v 1];
si(nn) = U*M*D*M'*V';
end
toc
scatter3(P(:,1), P(:,2), si)
hold on
mesh(xx,yy,s)
This is the full example and is a cubic B-spline surface interpolation algorithm in 2D space.
If I have a function f(x) which is defined as
f(x) = x^2; x>0 & x<=1
= x^3; x>1 & x<2
= 2*x; elsewhere
How do I plot this in Matlab in the same graph?
I would do this without fplot :
x = 0:0.1:3;
x1 = x(x>0 & x<=1);
x2 = x(x>1 & x<2);
x3 = x(x>2);
y1 = (x1).^2;
y2 = (x2).^3;
y3 = 2*(x3);
plot([x1 x2 x3], [y1 y2 y3])
You can define a set of x values (say between 4 <= x <= 4), then apply 2*x to every value within this interval. After, search for those x values that are within the intervals of the other functions and set those values to what they should be within those intervals. As such, try something like this:
x = -4 : 0.001 : 4;
y = 2*x;
y(x > 0 & x <= 1) = x(x > 0 & x <= 1).^2;
y(x > 1 & x < 2) = x(x > 1 & x < 2).^3;
plot(x,y);
grid;
This is what I get:
I want to plot n vs theta1 from the function tan(n*theta1) + tan(n*theta2) + tan(n*thetas)= 0 in MATLAB; where n, theta1 and theta2 are variables and thetas is given. Can anyone give any pointers how to do so ?
I have tried using ezplot. It didn't work.
Next, I used this bit of code,
c = 1;
thetas = pi/4;
for n = 1.01:0.01:3.50
for theta1 = pi/2 : 0.01 : 5*pi/6
for theta2 = 0: 0.01: pi/2
if(tan(n*theta1) + tan(n*theta2) + tan(n*thetas) >= -0.0001 && tan(n*theta1) + tan(n*theta2) + tan(n*thetas) <= 0.0001 && (n*theta1) ~= pi/2 ...
&& (n*theta2) ~= pi/2 && (n*thetas) ~= pi/2)
ns(c) = n;
theta1s(c) = theta1;
theta2s(c) = theta2;
c = c + 1;
end
end
end
end
And I tried to plot the result using the plot command. Didn't work out either. Mostly the plot should come as three different curves for every given value of thetas.
Can anyone help ?
Something like this might work? -
%%// Data (Random numbers)
thetas_array = [2 4 6]; %// Put different thetas here
theta2 = 2:2:20;
n = 1:10;
figure,
for k = 1:numel(thetas_array)
thetas = thetas_array(k);
%%// Since tan(n*theta1) + tan(n*theta2) + tan(n*thetas)= 0;
theta1 = (1./n).*atan(- tan(n.*theta2) - tan(n.*thetas));
subplot(3,1,k), plot(n,theta1), xlabel('n'), ylabel(strcat('theta1 [thetas = ',num2str(thetas),']'));
end
Output