Vectorization using accumarray - matlab

I want to project the texture of 3D surface (CylCoors 300000x3) into a 2D plane (Image 380x360). For doing so I take every unique value in Z (UniqueZ=unique(CylCoors(:,3))) and and Theta (UniqueTheta=unique(CylCoors(:,1))) and project all the texture values (PointValues 300000x1) where both meet like this:
Image=zeros(max(UniqueH),max(UniqueTheta)); %380x360
tic
HMat=bsxfun(#eq,CylCoors(:,3),UniqueH'); % 300000x380
ThetaMat=bsxfun(#eq,CylCoors(:,1),UniqueTheta'); %300000x360
for ii=1:length(UniqueH) % Sloooow and not nice :(
for jj=1:length(UniqueTheta)
Image(ii,jj)=sum(PointValues.*...
HMat(:,ii).*ThetaMat(:,jj))/...
sum(HMat(:,ii).*ThetaMat(:,jj));
end
end
toc
Here's an example with trimmed variables:
CylCoorsSample = [263.0000 184.2586 10.0000
264.0000 183.0417 10.0000
264.0000 182.1572 10.0000
82.0000 157.4746 11.0000
80.0000 158.2348 11.0000
86.0000 157.3507 11.0000
84.0000 157.7633 11.0000]
PointValuesSample = [0.4745
0.5098
0.5020
0.4784
0.4510
0.4431
0.5804]
UniqueTheta = [80
82
84
86
263
264]
UniqueH =[10
11]
ThetaMat = HMat =
0 0 0 0 1 0 1 0
0 0 0 0 0 1 1 0
0 0 0 0 0 1 1 0
0 1 0 0 0 0 0 1
1 0 0 0 0 0 0 1
0 0 0 1 0 0 0 1
0 0 1 0 0 0 0 1
Image = % size: length(UniqueH)xlength(UniqueTheta)
NaN NaN NaN NaN 0.4745 0.5059
0.4510 0.4784 0.5804 0.4431 NaN NaN
Is there a way to vectorize the for loops using accumarray? Something tells me this is the case, but I find the multidimensional sub indexing for this function quite confusing.
Any other vectorization solutions (using smart combinations of reshape,bsxfun, and sum I assume) are also welcome, but I would really like to understand this use of accumarray a bit better.

Given:
CylCoorsSample = [263.0000 184.2586 10.0000
264.0000 183.0417 10.0000
264.0000 182.1572 10.0000
82.0000 157.4746 11.0000
80.0000 158.2348 11.0000
86.0000 157.3507 11.0000
84.0000 157.7633 11.0000]
PointValuesSample = [0.4745
0.5098
0.5020
0.4784
0.4510
0.4431
0.5804]
You can use accumarray as follows (using the third output of unique to generate the required subs input):
[UniqueTheta, ~, subsTheta]=unique(CylCoorsSample(:,1))
[UniqueH,~,subsH]=unique(CylCoorsSample(:,3))
sz = [numel(UniqueH), numel(UniqueTheta)]
Image = accumarray([subsH, subsTheta], PointValuesSample, sz, #mean, NaN)

Related

Manipulating bar3 x-Axis values results into hollow barplot

I am setting up a bar3 plot and manipulated the X-Axis values since there is not a better way to do so. I went thorugh the code that Ander Biguri provided in his answer to this thread: How to set x and y values when using bar3 in Matlab?.
It turns out that the X-Axis values are fine but the bars that are not located at the borders are archetype shaped. Probably it has to do with the data manipulation.
Here is the corrisponding plot:
The data i used for this example:
klasse_sig_a=[70 82 94 106 118 130 142 154 166 178 190];
klasse_sig_m=[-120 -102 -84 -66 -48 -30 -12 6 24 42 60];
RFMatrix=
[2 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 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 2 0 0 0 0 2;
0 0 0 0 1 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0;
0 0 0 0 2 0 0 0 0 0;]
My code:
b=bar3(klasse_sig_m(2:end),RFMatrix,1);
xlabel('\sigma_a [MPa]')
ylabel('\sigma_m [MPa]')
zlabel('N [-]')
axis tight
for k = 1:length(b)
zdata = b(k).ZData;
b(k).CData = zdata;
b(k).FaceColor = 'interp';
end
Xdat=get(b,'XData');
diff=klasse_sig_a(2)-klasse_sig_a(1);
ONEMAT=ones(size(Xdat{1},1),size(Xdat{1},2)/2);
for ii=1:length(Xdat)
MAT=(Xdat{ii}-0.5);
if ii==1
MAT=MAT+[ONEMAT*min(klasse_sig_a) ONEMAT*(min(klasse_sig_a)+diff)-ii];
MAT_VOR=MAT(:,3:4);
else
MAT(:,1:2)=MAT_VOR;
MAT(:,3:4)=MAT(:,3:4)+ONEMAT*(min(klasse_sig_a)+ii*diff)-ii;
MAT_VOR=MAT(:,3:4);
end
Xdat{ii}=MAT;
set(b(ii),'XData',Xdat{ii});
end
set(gca,'XTick', klasse_sig_a(1:2:end))
set(gca,'YTick', klasse_sig_m(1:2:end))
I noticed that the non manipulated data always has a difference of 1 between left and right side of the matrix for each xdata{ii}
... ... ... ...
NaN NaN NaN NaN
NaN 0.5000 1.5000 NaN
0.5000 0.5000 1.5000 1.5000
0.5000 0.5000 1.5000 1.5000
NaN 0.5000 1.5000 NaN
NaN 0.5000 1.5000 NaN
NaN NaN NaN NaN
When setting my own data the difference becomes much bigger and the bar plots become hollow
... ... ... ...
NaN 70 82 NaN
70 70 82 82
70 70 82 82
NaN 70 82 NaN
NaN 70 82 NaN
NaN NaN NaN NaN
How can I make the bars appear solid again? I guess the data manipulation is erroneous.
Thanks for any help!
Regards
Note that the answer to the related question is specifically designed to deal with the case when your x values are sequential integers (i.e. the bin width is 1). Your case is more general, with a bin width of 12. This requires slightly different logic. I was able to get your desired results with the following code:
b = bar3(klasse_sig_m(2:end), RFMatrix,1);
xlabel('\sigma_a [MPa]');
ylabel('\sigma_m [MPa]');
zlabel('N [-]');
axis tight;
for k = 1:length(b)
xData = b(k).XData;
zData = b(k).ZData;
set(b(k), 'XData', (xData-k).*diff(klasse_sig_a(k:(k+1)))+klasse_sig_a(k), ...
'CData', zData, 'FaceColor', 'interp');
end
set(gca, 'XTick', klasse_sig_a(1:2:end), 'YTick', klasse_sig_m(1:2:end));
And the plot:

Matlab : What am I doing wrong? (Indexing)

I'm trying to solve a system of 10 linear equations out of which the middle 8 equations look alike. They look like this :
t_i-1 - 2.3086*(t_i) + t_i+1 == -7.7160
where i = 2:9
so I decided to construct the coefficient matrix and the constant matrix(array) for the system of equations through looping.This is what I did.
T = sym('t' , [1 10]); %% Creates a vector T = [ t1 t2 .... t10]
A_10 = zeros(10,10);
b_10 = zeros(10,1);
for i = 2:9 %% This loop generates the equations and arranges them in the matrices A_10 and B_10.
T(i-1) - 2.3086*T(i) + T(i+1) == -7.7160;
[A_10(i,i-1:i+1),b_10(i,1)] = equationsToMatrix(ans)
end
Everything except for the ninth row(last but one) is correct in the Matrix A_10. This is what A_10 looks like
A_10 =
Columns 1 through 9
0 0 0 0 0 0 0 0 0
1.0000 -2.3086 1.0000 0 0 0 0 0 0
0 1.0000 -2.3086 1.0000 0 0 0 0 0
0 0 1.0000 -2.3086 1.0000 0 0 0 0
0 0 0 1.0000 -2.3086 1.0000 0 0 0
0 0 0 0 1.0000 -2.3086 1.0000 0 0
0 0 0 0 0 1.0000 -2.3086 1.0000 0
0 0 0 0 0 0 1.0000 -2.3086 1.0000
0 0 0 0 0 0 0 1.0000 1.0000
0 0 0 0 0 0 0 0 0
Column 10
0
0
0
0
0
0
0
0
-2.3086
0
The last three elements of the row nine should be 1 , -2.3086 , 1 like the previous rows but it shows 1, 1, -2.3086. What am I doing wrong here?
This is what the iteration looks like in the loop
ans = t8 - (11543*t9)/5000 + t10 == -1929/250
The equation is correct too. I can't figure out what the problem is.
Without the second input vars, equationsToMatrix uses symvar to determine the variable list.
Using symvar directly with the last equation gives
>> i = 9;symvar(T(i-1) - 2.3086*T(i) + T(i+1) == -7.7160)
ans =
[ t10, t8, t9]
So for whatever reason, symvar produced the incorrect ordering for only the last equation (possibly because 1 < 9). To remedy the situation, pass your intended ordering using the second input
eqn = T(i-1) - 2.3086*T(i) + T(i+1) == -7.7160;
[A_10(i,i-1:i+1),b_10(i,1)] = equationsToMatrix(eqn,T(i-1:i+1));
You'll also noticed I assigned the equation to an explicit variable eqn. This is better practice than relying on ans.
Also, since you're producing a numeric array anyway, you can produce A without the Symbolic Toolbox in a number of ways. For example:
n = 10;
A = full(spdiags(ones(n,1)*[1,-2.3086,1],[-1,0,1],n,n));
A([1,end],:) = 0;

for loops and matrices in matlab

I am trying to link two equations, where I use a for loop calculate the value of k from the range of frequencies (eg. 1-5 Hz) then use each of the k values and substitute the values of k into a 6x6 matrix. Can anyone help show me how to create a matrix for each value of k in Matlab?
1st Equation
for f = 1:5; % Range of Frequencies (Hz)
f;
w = 2.*pi.*f; % Angular Frequency (Hz)
p = 8050;% Density of Mild Steel(kg/m^3)
v = 0.30; % Poissons Ratio of Mild Steel
R = 0.02; % Radius of Pipe (m)
E = 210*10^9; % Youngs Modulus of Mild Steel (pa)
a = (w.^2).*p;
b = (p.*(1-(v.^2)).*(R.^2).*(w.^2)-E);
c = (p.*(R.^2).*(w.^2)-E).*E;
**k(f) = sqrt((a.*b)/c); % k = Wave Number**
end
2nd Equation (6x6 Matrix)
k =
L1=0.1;
L2=0.6;
L3=0.6;
D= [0,0,exp(-k*L1),exp(-k*L2),0,0; exp(-k*L1),1,exp(-k*L1),exp(-k*L2),0,0; -k*exp(-k*L1),k,k*exp(-k*L1),-k*exp(-k*L2),0,0;0,0,exp(-k*(L1+L2)),k,-exp(-k*(L1+L2)),-exp(-k*L3);0,0,-k*exp(-k*(L1+L2)),1,k*exp(-k*(L1+L2)),k*exp(-k*L3);0,0,exp(-k*(L1+L2)),1,0,0]
(Answer modified following the comment)
You can try definig the output array D as a 3 dimensions array.
D=NaN(6,6,length(k))
for i=1:length(k)
D(:,:,i)= [0,0,exp(-k(i)*L1),exp(-k(i)*L2),0,0; exp(-k(i)*L1),1,exp(-k(i)*L1),exp(-k(i)*L2),0,0; -k(i)*exp(-k(i)*L1),k(i),k(i)*exp(-k(i)*L1),-k(i)*exp(-k(i)*L2),0,0;0,0,exp(-k(i)*(L1+L2)),k(i),-exp(-k(i)*(L1+L2)),-exp(-k(i)*L3);0,0,-k(i)*exp(-k(i)*(L1+L2)),1,k(i)*exp(-k(i)*(L1+L2)),k(i)*exp(-k(i)*L3);0,0,exp(-k(i)*(L1+L2)),1,0,0]
end
The D array will be:
D(:,:,1) =
0 0 0.9999 0.9993 0 0
0.9999 1.0000 0.9999 0.9993 0 0
-0.0012 0.0012 0.0012 -0.0012 0 0
0 0 0.9991 0.0012 -0.9991 -0.9993
0 0 -0.0012 1.0000 0.0012 0.0012
0 0 0.9991 1.0000 0 0
D(:,:,2) =
0 0 0.9998 0.9985 0 0
0.9998 1.0000 0.9998 0.9985 0 0
-0.0025 0.0025 0.0025 -0.0025 0 0
0 0 0.9983 0.0025 -0.9983 -0.9985
0 0 -0.0025 1.0000 0.0025 0.0025
0 0 0.9983 1.0000 0 0
D(:,:,3) =
0 0 0.9996 0.9978 0 0
0.9996 1.0000 0.9996 0.9978 0 0
-0.0037 0.0037 0.0037 -0.0037 0 0
0 0 0.9974 0.0037 -0.9974 -0.9978
0 0 -0.0037 1.0000 0.0037 0.0037
0 0 0.9974 1.0000 0 0
D(:,:,4) =
0 0 0.9995 0.9971 0 0
0.9995 1.0000 0.9995 0.9971 0 0
-0.0049 0.0049 0.0049 -0.0049 0 0
0 0 0.9966 0.0049 -0.9966 -0.9971
0 0 -0.0049 1.0000 0.0049 0.0049
0 0 0.9966 1.0000 0 0
D(:,:,5) =
0 0 0.9994 0.9963 0 0
0.9994 1.0000 0.9994 0.9963 0 0
-0.0061 0.0062 0.0061 -0.0061 0 0
0 0 0.9957 0.0062 -0.9957 -0.9963
0 0 -0.0061 1.0000 0.0061 0.0061
0 0 0.9957 1.0000 0 0
Hope this helps.
I will try to answer your question...
Firstly, you don't need the initial for loop. You can calculate all values of wavelength without loops.
f = 1:5; % Range of Frequencies (Hz)
w = 2.*pi.*f; % Angular Frequency (Hz)
p = 8050;% Density of Mild Steel(kg/m^3)
v = 0.30; % Poissons Ratio of Mild Steel
R = 0.02; % Radius of Pipe (m)
E = 210*10^9; % Youngs Modulus of Mild Steel (pa)
a = (w.^2).*p;
b = (p.*(1-(v.^2)).*(R.^2).*(w.^2)-E);
c = (p.*(R.^2).*(w.^2)-E).*E;
k = sqrt((a.*b)./c); % k = Wave Number
L1=0.1;
L2=0.6;
L3=0.6;
Then you can use a for loop to calculate the D matrix and a cell array to store the results:
results = cell(1, length(k));
for i = 1:length(k)
results{i} = [
0,0,exp(-k(i)*L1),exp(-k(i)*L2),0,0;...
exp(-k(i)*L1),1,exp(-k(i)*L1),exp(-k(i)*L2),0,0;...
-k(i)*exp(-k(i)*L1),k(i),k(i)*exp(-k(i)*L1),-k(i)*exp(-k(i)*L2),0,0;...
0,0,exp(-k(i)*(L1+L2)),k(i),-exp(-k(i)*(L1+L2)),-exp(-k(i)*L3);...
0,0,-k(i)*exp(-k(i)*(L1+L2)),1,k(i)*exp(-k(i)*(L1+L2)),k(i)*exp(-k(i)*L3);...
0,0,exp(-k(i)*(L1+L2)),1,0,0
]
end
P.S. Without trying to get on to you, I think that what you just want is to someone solve an excercise for you. If this is not the case, ignore my p.s.

How to revert signed distance function back to binary image?

So I used MATLAB's bwdist function to obtain the distance transform of a binary image. My question is, how do I transform a signed distance matrix back into a binary image?
D = bwdist(BW)
Specifically, is there a transform that can go back from BW -> D?
If D = bwdist(BW), how about BW0 = D<=0?
Consider the first example from the bwdist documentation:
bw = zeros(5,5); bw(2,2) = 1; bw(4,4) = 1
bw =
0 0 0 0 0
0 1 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
[D,IDX] = bwdist(bw)
D =
1.4142 1.0000 1.4142 2.2361 3.1623
1.0000 0 1.0000 2.0000 2.2361
1.4142 1.0000 1.4142 1.0000 1.4142
2.2361 2.0000 1.0000 0 1.0000
3.1623 2.2361 1.4142 1.0000 1.4142
To get back your binary image, you just want the points in the distance transform that are equal to zero (i.e. on a non-zero pixel in the original bw):
>> bw0 = D<=0
bw0 =
0 0 0 0 0
0 1 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
>> isequal(bw,bw0)
ans =
1

Probability of a number occurring in a matrix

I'm using Matlab and well it's straightforward to find the probability of an element in a matrix, but I a little unsure of how to find probability of an element in a row or column.
e.g this matrix:
X = [
1 2 4 1 8;
5 3 6 9 2;
6 2 2 3 2
];
How would I find the probability of "2" occurring in each row and column of this random matrix.
You could do the following:
X_unique = unique(X);
p_row = zeros(size(X,1),numel(X_unique));
p_col = zeros(size(X,2),numel(X_unique));
for ii = 1:size(X,1)
p_row(ii,:) = hist(X(ii,:),X_unique);
p_row(ii,:) = p_row(ii,:)/sum(p_row(ii,:));
end
for ii = 1:size(X,2)
p_col(ii,:) = hist(X(:,ii),X_unique);
p_col(ii,:) = p_col(ii,:)/sum(p_col(ii,:));
end
Now, each row of p_row contains the probability distribution of the elements of unique(X) in the corresponding row of X and each row of p_col contains the probability distribution of the elements of unique(X) in the corresponding column of X.
For example, for the given example,
X_unique =
1
2
3
4
5
6
8
9
Thus,
p_row =
0.4000 0.2000 0 0.2000 0 0 0.2000 0
0 0.2000 0.2000 0 0.2000 0.2000 0 0.2000
0 0.6000 0.2000 0 0 0.2000 0 0
p_col =
0.3333 0 0 0 0.3333 0.3333 0 0
0 0.6667 0.3333 0 0 0 0 0
0 0.3333 0 0.3333 0 0.3333 0 0
0.3333 0 0.3333 0 0 0 0 0.3333
0 0.6667 0 0 0 0 0.3333 0
Here's a simple, not-quite-Matlab-ish solution that works on non-empty bi-dimensional matrices, looking for elements with the value "2", and returning probabilities by column:
a = [1 2 4 1 8; 5 3 6 9 2; 6 2 2 3 2];
nrows = size(a,1);
ncols = size(a,2);
pc = zeros(1, ncols); % Prob. by column
% Iterate trough columns
for k = 1:ncols
n = sum(a(:,k) == 2);
pc(k) = n/nrows;
end;
You can adapt it to compute "probabilities" by row, or by other dimensions, or look for other values.