I have created a position matrix which I am happy with, and for each position (or element) of this matrix, I want to calculate the positional distance between all other positions in the matrix. This way i can obtain the direction each other element is from another. I have tried to do this in the following way:
pos = [X(:),Y(:),Z(:)];
for j = 1:length(pos)
for i = 1:length(pos)
vecdir(i,:,:) = pos(i,:,:) - pos(j,:,:);
end
v(i) = {vecdir};
i = i+1;
end
where each cell holds the positional distance per position in the position matrix. v(i) only seems to store the last calculation (i.e. all cells are empty apart from the last cell which holds the correct information for the last position on the position matrix.). Where am I going wrong here? Also, if there is a more efficient way of doing this then I'd like to know, as I know storing and accessing cell arrays slows programs down a lot.
They're is always pdist2:
dist = pdist2(pos,pos);
which gives the norm of the distance vectors.
In case you also need the distance vectors I'd use something like this:
N = size(pos,1);
v = arrayfun(#(ii) bsxfun(#minus,pos,pos(ii,:)),1:N,'uni',false)
which returns a Nx1 cell array, each cell containing the distance vector of pos(ii,:) to the other positions.
Your code seems to do the same, altough there are some errors; I think you intended to do the following:
N = size(pos,1);
v = cell(N,1);
for j = 1:N
for i = 1:N
vecdir(i,:) = pos(i,:) - pos(j,:);
end
v{j} = vecdir;
end
What are these statements doing at the end of your loop over j ?
v(i) = {vecdir};
i = i+1;
As I read your code, these always set v(length(pos)) to {vecdir} and then add 1 to i. This updated value of i is never used before it is reset (to 1) at the next go round the inner loop.
I can't say that the rest of your code is OK, I'm not sure I follow your question entirely, but these bits smell a bit fishy.
x = repmat(X(:), 1, numel(X));
y = repmat(Y(:), 1, numel(Y));
z = repmat(Z(:), 1, numel(Z));
dst = sqrt((x - x') .^ 2 + (y - y') .^ 2 + (z - z') .^ 2);
Related
I don't understand why I can't find any clear answer on this! Such a basic thing...
I have a normal 2D matrix, such as this one:
matrix = zeros(w, h);
Where w, h ∈ Z+, which means w and h are positive integers greater than zero.
I need to loop through the matrix and do something with it's element. For this task, we can assume h=3. Therefore, I tried this:
test = zeros(w, 3);
for i = 1:test
point = test(:,i);
[point(0), point(1), point(2)] = MY_CONVERSION(point(0), point(1),point(2));
test(:,i) = point;
end
The MY_CONVERSION is varargin function and for 3 parameters defined as:
function [rho, alpha, z] = MY_CONVERSION(r, alpha, epsilon)
Of course, in real code the test contains data, not just zeros. But this code alone could, for example, fill matrix with random numbers. But it doesn't work.
I also tried using three variables to store the column values:
for i = 1:Xi
[a,b,c] = Xi(:,i);
[a,b,c] = mysph2cyl(a, b, c);
rho(:,i) = a,b,c;
end
Matlab marks it as incorrect syntax:
An assignment statement makes an assignment to multiple values, but
the expression on the right side of the assignment does not appear to
produce multiple values.
The first piece of code is what you need to get it working. However, your for loop is incorrect. You probably want to iterative over all of the columns, so do for i = 1 : size(test,2), not test. size(test,2) determines how many columns your matrix has.
Therefore:
test = zeros(w, 3);
for i = 1:size(test,2) %// Change here
point = test(:,i);
[point(0), point(1), point(2)] = MY_CONVERSION(point(0), point(1),point(2));
test(:,i) = point;
end
Also, your second piece of code, you need to fix that for loop problem like I mentioned above. The first statement inside the for loop is superfluous. You don't need it. The third line of code needs to have [] surrounding a,b,c.
First, matrix = zeros(w, h); creates confusion: you are probably thinking of w as width and h as height. But the first argument of zeros is height: for example, zeros(2,3) is
0 0 0
0 0 0
Generally: row index first, column index second.
Then you have for i = 1:test but test is a matrix. You need a number here.
Here is a working example similar to your first fragment:
w = 2; h =3;
test = zeros(w, h);
for i = 1:h
point = test(:,i);
point = cos(point)*i; % sample conversion
test(:,i) = point;
end
Output:
1 2 3
1 2 3
I'm new to Matlab and struggling with understanding the concept of array notation (coming from a Perl background).
Let's assume we have two random vectors (X,Y) which are coordinates in 2D (range -r ... r) and we want to find out which points (x, y) lie within a circle with radius r. This would be our setup:
n = 100000000; % point number
r = 1; % circle size
X = (rand(1,n) .* 2*r) - r; % generate coordinates (-r .. r)
Y = (rand(1,n) .* 2*r) - r;
As I understood, Matlab is able to do almost anything fully vectorized on the way to classify the coordinates (in C):
C = - ... % negate sign, 1: within, 0,-1: outside
sign( ... % -1: within, 0,1: outside
(X.^2 + Y.^2) - r^2 ... % calculate distance
);
Now I would like to retain only the values for points within the circle and therefore drop all -1 (former >=0 values) values from C, which could be done by:
C(C < 0) = 0;
I found no obvious way to include the latter expression with the former into a single expression, because I did not find out how the temporary array which is about to be created and modified by the distance-, sign-, and negation operators can be "addressed" to do another "step" with C(C < 0) = 0. Would this be possible at all?
Edit:
According to Dan's comment below, I could simplify the whole expression to:
C = ( (X.^2 + Y.^2) - r^2 ) < 0;
which is exactly what I had looked for. Thank you very much! I didn't think this is possible in Matlab ...
In your specific case I think you could just equate it to 1:
C = -sign((X.^2 + Y.^2) - r^2) == 1;
or
C = -sign((X.^2 + Y.^2) - r^2) > 0;
because what your output is in the end is just a matrix of 1s and 0s so you might as well take advantage of Matlab's logical datatype
But addressing the temporary matrix is not really the way to do things in Matlab. Normally you would just leave it as two lines of code. But if you really really want to, I think you can use the subsref function to do it.
I have a matrix and for each element I want to get the index of its surrounding elements. All these results have to be stored into a matrix in the following way. Each row of the matrix corresponds to a matrix element and each of the columns of this matrix contain s the neighbor indexes. For example, for a 4x4 matrix we will get a 16x8 result array. Some of the matrix elements do not have 8 neighbors.
There is an example, I think it is working, I there any way to avoid for loop?:
ElementNeighbors = [];
for n = 1:numel(Matrix)
NeighborsMask = [ n-1 n+1 n+size(matrix,1) n-size(Matrix,1) n-size(Matrix,1)-1 n-size(Matrix,1)+1 ...
n+size(Matrix,1)-1 n+size(Matrix,1)+1 ];
ElementNeighbors = [ElementNeighbors ; NeighborsMask ];
end
ElementNeighbors (ElementNeighbors ==0|ElementNeighbors <0) = NaN;
Given the linear indices of a matrix M(n,m), you can convince yourself that the top left neighbor of element M(i,j) = M(i-1, j-1) = M(i-1 + n * (j-2))
In "linear index" space that means the offset of this element is
-n-1
Doing this for all other locations, we find
-n-1 | -1 | n-1
-n | x | n => [-n-1, -n, -n+1, -1, +1, +n-1, +n, +n+1]
-n+1 | +1 | n+1
Thus you can create a vector offset with the above values (replacing n with the first dimension). For example, if M is (5x4), then
offset = [-6 -5 -4 -1 1 4 5 6];
You then create all the indices:
indices = bsxfun(#plus, (1:m*n), offset(:));
bsxfun is a cool shorthand for "do this function on these elements; where one element has a singleton dimension and the other doesn't, expand accordingly". You could do the same with repmat, but that creates unnecessary intermediate matrices (which can sometimes be very large).
That command will create a (8 x m*n) matrix of indices of all 8 neighbors, including ones that may not really be the neighbors... something you need to fix.
Several possible approaches:
pad the matrix before you start
don't care about wrapping, and just get rid of the elements that fall off the edge
create a mask for all the ones that are "off the edge".
I prefer the latter. "Off the edge" means:
going up in the top row
going left in the left column
going down in the bottom row
going right in the right column
In each of these four cases there are 3 indices that are 'invalid'. Their position in the above matrix can be determined as follows:
mask = zeros(size(M));
mask(:,1) = 1;
left = find(mask == 1);
mask(:,end) = 2;
right = find(mask == 2);
mask(1,:) = 3;
top = find(mask == 3);
mask(end,:) = 4;
bottom = find(mask == 4);
edgeMask = ones(8,m*n);
edgeMask(1:3, top) = 0;
edgeMask([1 4 6], left) = 0;
edgeMask([3 5 8], right) = 0;
edgeMask(6:8, bottom) = 0;
Now you have everything you need - all the indices, and the "invalid" ones. Without loops.
If you were feeling ambitious you could turn this into a cell array but it will be slower than using the full array + mask. For example if you want to find the average of all the neighbors of a value, you can do
meanNeighbor = reshape(sum(M(indices).*edgeMask, 1)./sum(edgeMask, 1), size(M));
EDIT re-reading your question I see you wanted a M*N, 8 dimension. My code is transposed. I'm sure you can figure out how to adapt it...
ATTRIBUTION #Tin helpfully suggested many great edits to the above post, but they were rejected in the review process. I cannot totally undo that injustice - but would like to record my thanks here.
EXTENDING TO DIFFERENT REGIONS AND MULTIPLE DIMENSIONS
If you have an N-dimensional image matrix M, you could find the neighbors as follows:
temp = zeros(size(M));
temp(1:3,1:3,1:3) = 1;
temp(2,2,2) = 2;
offsets = find(temp==1) - find(temp==2);
If you want a region that is a certain radius in size, you could do
sz = size(M);
[xx yy zz] = meshgrid(1:sz(1), 1:sz(2), 1:sz(3));
center = round(sz/2);
rr = sqrt((xx - center(1)).^2 + (yy - center(2)).^2 + (zz - center(3)).^2);
offsets = find(rr < radius) - find(rr < 0.001);
You can probably figure out how to deal with the problem of edges along the lines shown earlier for the 2D case.
Untested - please see if you notice any problems with the above.
I have a solution to creating a vector for just one element of a matrix:
[dx,dy] = gradient(Im);
orient11 = [(-dx(1,1)) (dy(1,1)) 0];
where
size(orient11) =
0 0 0
ie for the first element of orient, namely orient11, is a vector. How do I do this for all the other elements, so I have orient12, orient13....orientnn. I know I need a for loop, however what object do I store the vectors into from the for loop? I have discovered I can't create a matrix of vectors.
Thanks in advance.
You can try building an N-by-N-by-3 matrix, but it won't be so convenient to manipulate. This is because extracting a vector from this matrix would yield a 1-by-1-by-3 vector, which you would need to reshape. Definitely not fun.
Instead, I suggest that you build an N-by-N cell array of 1-by-3 vectors, like so:
[dx, dy] = gradient(Im);
vec = #(i)[-dx(i), dy(i), 0];
orient = arrayfun(vec, reshape(1:numel(dx), size(dx)), 'UniformOutput', 0);
To access a vector, use the curly braces. For example, the vector at the (1, 2) position would be:
orient12 = orient{1, 2};
Hope it helps!
v = -2:0.2:2;
[x,y] = meshgrid(v);
z = x .* exp(-x.^2 - y.^2);
[px,py] = gradient(z,.2,.2);
orient11 = [(-px(1,1)) (py(1,1)) 0]; % based off of your concatination there.
size(orient11)
I then get:
ans =
1 3
If you're looking to just grab the first column of data from the gradients you have and want to just stack zeros with them, you can do this:
orient11 = [(-px(:,1)) (py(:,1)) zeros(size(px,1),1)];
Instead of a for loop.
Update:
Orient = zeros(size(px,1),3,size(px,2));
for n = 1:size(px,1)
Orient(:,:,n) = [(-px(:,n)) (py(:,n)) zeros(size(px,1),1)];
end
The layout of Orient is now your -px, py, 0 in layers. Each layer represents the column from the initial data. So if you wanted to get access to row 4 column 14, you would call Orient(4,:,14).
Hope that makes sense and helps!
how to pick values from matrix closest to or equal to K = 0.5? I know I could obtain values from the matrix, by taking the absolute values and its min. However, I want to be able to loop through the matrix, check if the the first element is equal K, if it is equal,take its index and break. But if the first element is not equal to K, loop until you find value equal to K. Continue until all values equal to K is exhausted. Can anybody point me in the right direction? Thanks in advance.
Here is my code:
data = rand(10,2);k =0.5;
indr = find(data(:,1));
cNum = data(1,1);
if cNum < k
old_distance = abs(k - cNum);
else
old_distance = abs(cNum - k);
end
Xdata = data(2:end,:);
indeX = find(Xdata(:,1));
for i = 1:size(Xdata,1)
if Xdata(i,1) < k
min_Val = abs(k-Xdata(i,1));
new_distance = min(min_Val);
else
min_Val = abs(Xdata(i,1) -k);
new_distance = min(min_Val);
end
if (new_distance < old_distance)
old_distance = new_distance;
cNum = Xdata(i,1);
end
end
cNum_indeX = indr(indeXm);
Y = cNum;
X = indr(cNum_indeX);'
To find the closest value in a vector to a particular value you can do this:
>> data = rand(10, 1)
data =
0.7060
0.0318
0.2769
0.0462
0.0971
0.8235
0.6948
0.3171
0.9502
0.0344
>> k = 0.5;
>> [~, index] = min(abs(data - k));
>> closestValue = data(index)
closestValue =
0.3171
For loops are rarely the answer in MATLAB. Let's say you want to check if your array elements are within K ± tol, where tol is some tolerance that you've set. You can do that by simple logical indexing.
K=0.5;
tol=0.001; %# set your tolerance here
boolIndex=xVector<=K+tol & xVector>=K-tol; %# xVector is your vector
Now boolIndex is just a logical index array of 0's and 1's. It gives a 1 wherever your array element has satisfied this criteria. You can use this directly in indexing your vector for further manipulation. If, for some reason, you need the exact index, you can get them by doing find(boolIndex==1).
The constraints of the problem aren't clear enough (and I don't have enough points to make this a comment rather than an answer.)
Is speed critical here? If so, then you should avoid any sort of explicit loop. It's usually better to use builtin functions unless the matrix is really huge and you want to break when you find something close enough. If it's millions of entries long, I'd break it into chunks of 10000 or so and let MATLAB use the min function on chunks. Or rows. Or columns. Depends on what you want to do.
How close is close enough? You demonstrate with a random matrix, but are you expecting something within rounding error of 0.5?
Are you aware that [value,index]=min(x) will give the value and index of minimum?
I assume the matrix must be large, otherwise there would be no downside to letting MATLAB do the vectorized:
[colminval,colminind]=min(abs(x-0.5));
[minval,rowminind]=min(colminval);
That's the best I can do for direction without more... direction.