I have declared 2 matrixes like this:
a = [ 1 2;
11 12];
[m, n] = size(a);
b = a(2,:);
dist( b , a ); % the first column is not interesting
This works, I get a vector
[ 10.0499 9.0000 ]
However if I want to add a column or a line to my matrix a:
a = [ 1 2 3 ;
11 12 13];
then apply the same algorithm, than above, ignoring or not the first column, I get this error:
Error using -
Matrix dimensions must agree
I have no idea why it does not work, can someone explain to me please?
Actually I don't even know how to retrieve the way this euclidian distance is computed, I failed at trying to retrieve those values [ 10.0499 9.0000 ] by hand.
The Matlab mathworks manual says he algorithm used is the following:
d = sum((x-y).^2).^0.5
Any help
It does not work because the dist function when called with two arguments works like this:
Z = dist(W,P) takes an SxR weight matrix and RxQ input matrix and
returns the SxQ matrix of distances between W's rows and P's columns.
dist(P',P) returns the same result as dist(P).
That is, if you do this:
a = [ 1 2 3 ;
11 12 13]
b = a(2,:) % Then b = [11 12 13]
...and call:
dist(b, a)
It will try to compute the distance between b's rows (in this case, only a row with three numbers, that is, a 3D point) and a's columns (each column has two numbers, that is, a 2D point). Measuring a distance between them makes no sense.
The reason it worked on your first example was because the matrix was square (2x2). Therefore, you're computing distances between a row (2D) to the other columns (also 2D).
A distance by definition is a single number, not a vector. The fact that you've getting a vector for matrices of the same size already indicates that something is wrong. In particular, it gives you distance between each of the corresponding column vectors to each other. So it doesn't work when your matrices are of different sizes. A distance between matrices is not defined in any one particular way. I don't know of a notion of Euclidean distance between two matrices.
Related
I have x,y pixel coordinates of multiple objects that have been tracked from an image (3744x5616). The coordinates are stored in a structure called objects, e.g.
objects(1).centre = [1868 1236]
The objects are each uniquely identified by a numerical code, e.g.
objects(i).code = 33
I want to be able to record each time any two objects come within a radius of 300 pixels each other. What would be the best way to check through if any objects are touching and then record the identity of both objects involved in the interaction, like object 33 interacts with object 34.
Thanks!
Best thing I can think of right now is a brute force approach. Simply check the distances from one object's centre with the rest of the other objects and manually check if the distances are < 300 pixels.
If you want this fast, we should probably do this without any toolboxes. You can intelligently do this with vanilla MATLAB using bsxfun. First, create separate arrays for the X and Y coordinates of each object:
points = reshape([objects.centre], 2, []);
X = points(1,:);
Y = points(2,:);
[objects.centre] accesses the individual coordinates of each centre field in your structure and unpacks them into a comma-separated list. I reshape this array so that it is 2 rows where the first row is the X coordinate and the second row is the Y coordinate. I extract out the rows and place them into separate arrays.
Next, create two difference matrices for each X and Y where the rows denote one unique coordinate and the columns denote another unique coordinate. The values inside this matrix are the differences between the point i at row i and point j at column j:
Xdiff = bsxfun(#minus, X.', X);
Ydiff = bsxfun(#minus, Y.', Y);
bsxfun stands for Binary Singleton EXpansion FUNction. If you're familiar with the repmat function, it essentially replicates matrices and vectors under the hood so that both inputs you're operating on have the same size. In this case, what I'm doing is specifying X or Y as both of the inputs. One is the transposed version of the other. By doing this bsxfun automatically broadcasts each input so that the inputs match in dimension. Specifically, the first input is a column vector of X and so this gets repeated and stacked horizontally for as many times as there are values in X.
Similarly this is done for the Y value. After you do this, you perform an element-wise subtraction for both outputs and you get the component wise subtraction between one point and another point for X and Y where the row gives you the first point, and the column gives you the second point. As a toy example, imagine we had X = [1 2 3]. Doing a bsxfun call using the above code gives:
>> Xdiff = bsxfun(#minus, [1 2 3].', [1 2 3])
Xdiff =
## | 1 2 3
----------------------
1 | 0 -1 -2
2 | 1 0 -1
3 | 2 1 0
There are some additional characters I placed in the output, but these are used solely for illustration and to give you a point of reference. By taking a row value from the ## column and subtracting from a column value from the ## row gives you the desired subtract. For example, the first row second column illustrates 1 - 2 = -1. The second row, third column illustrates 2 - 3 = -1. If you do this for both the X and Y points, you get the component-wise distances for one point against all of the other points in a symmetric matrix.
You'll notice that this is an anti-symmetric matrix where the diagonal is all 0 ... makes sense since the distance of one dimension of one point with respect to itself should be 0. The bottom left triangular portion of the matrix is the opposite sign of the right... because of the order of subtraction. If you subtracted point 1 with point 2, doing the opposite subtraction gives you the opposite sign. However, let's assume that the rows denote the first object and the columns denote the second object, so you'd want to concentrate on the lower half.
Now, compute the distance, and make sure you set either the upper or lower triangular half to NaN because when computing the distance, the sign gets ignored. If you don't ignore this, we'd find duplicate objects that interact, so object 3 and object 1 would be a different interaction than object 1 and object 3. You obviously don't care about the order, so set either the upper or lower triangular half to NaN for the next step. Assuming Euclidean distance:
dists = sqrt(Xdiff.^2 + Ydiff.^2);
dists(tril(ones(numel(objects))==1)) = NaN;
The first line computes the Euclidean distance of all pairs of points and we use tril to extract the lower triangular portion of a matrix that consists of all logical 1. Extracting this matrix, we use this to set the lower half of the matrix to NaN. This allows us to skip entries we're not interested in. Note that I also set the diagonal to 0, because we're not interested in distances of one object to itself.
Now that you're finally here, search for those objects that are < 300 pixels:
[I,J] = find(dists < 300);
I and J are row/column pairs that determine which rows and columns in the matrix have values < 300, so in our case, each pair of I and J in the array gives you the object locations that are close to each other.
To finally figure out the right object codes, you can do:
codes = [[objects(I).code].' [objects(J).code].'];
This uses I and J to access the corresponding codes of those objects that were similar in a comma-separated list and places them side by side into a N x 2 matrix. As such, each row of codes gives you unique pairs of objects that satisfied the distance requirements.
For copying and pasting:
points = reshape([objects.centre], 2, []);
X = points(1,:);
Y = points(2,:);
Xdiff = bsxfun(#minus, X.', X);
Ydiff = bsxfun(#minus, Y.', Y);
dists = sqrt(Xdiff.^2 + Ydiff.^2);
dists(tril(ones(numel(objects))==1)) = NaN;
[I,J] = find(dists < 300);
codes = [[objects(I).code].' [objects(J).code].'];
Toy Example
Here's an example that we can use to verify if what we have is correct:
objects(1).centre = [1868 1236];
objects(2).centre = [2000 1000];
objects(3).centre = [1900 1300];
objects(4).centre = [3000 2000];
objects(1).code = 33;
objects(2).code = 34;
objects(3).code = 35;
objects(4).code = 99;
I initialized 4 objects with different centroids and different codes. Let's see what the dists array gives us after we compute it:
>> format long g
>> dists
dists =
NaN 270.407100498489 71.5541752799933 1365.69396278961
NaN NaN 316.227766016838 1414.2135623731
NaN NaN NaN 1303.84048104053
NaN NaN NaN NaN
I intentionally made the last point farther than any of the other three points to ensure that we can show cases where there are points not near other ones.
As you can see, points (1,2) and (1,3) are all near each other, which is what we get when we complete the rest of the code. This corresponds to objects 33, 34 and 35 with pairings of (33,34) and (33,35). Points with codes 34 and 35 I made slightly smaller, but they are still greater than the 300 pixel threshold, so they don't count either:
>> codes
codes =
33 34
33 35
Now, if you want to display this in a prettified format, perhaps use a for loop:
for vec = codes.'
fprintf('Object with code %d interacted with object with code %d\n', vec(1), vec(2));
end
This for loop is a bit tricky. It's a little known fact that for loops can also accept matrices and the index variable gives you one column of each matrix at a time from left to right. Therefore, I transposed the codes array so that each pair of unique codes becomes a column. I just access the first and second element of each column and print it out.
We get:
Object with code 33 interacted with object with code 34
Object with code 33 interacted with object with code 35
I have this RGB matrix of a set of different pixels. (N pixels => n rows, RGB => 3 columns). I have to calculate the minimum RGB distance between any two pixels from this matrix. I tried the loop approach, but because the set is too big (let's say N=24000), it looks like it will take forever for the program to finish. Is there another approach? I read about pdist, but the RGB Euclidean distance cannot be used with it.
k=1;
for i = 1:N
for j = 1:N
if (i~=j)
dist_vect(k)=RGB_dist(U(i,1),U(j,1),U(i,2),U(j,2),U(i,3),U(j,3))
k=k+1;
end
end
end
Euclidean distance between two pixels:
So, pdist syntax would be like this: D=pdist2(U,U,#calc_distance());, where U is obtained like this:
rgbImage = imread('peppers.png');
rgb_columns = reshape(rgbImage, [], 3)
[U, m, n] = unique(rgb_columns, 'rows','stable');
But if pdist2 does the loops itself, how should I enter the parameters for my function?
function[distance]=RGB_dist(R1, R2, G1, G2, B1, B2),
where R1,G1,B1,R2,G2,B2 are the components of each pixel.
I made a new function like this:
function[distance]=RGB_dist(x,y)
distance=sqrt(sum(((x-y)*[3;4;2]).^2,2));
end
and I called it D=pdist(U,U,#RGB_dist); and I got 'Error using pdist (line 132)
The 'DISTANCE' argument must be a
string or a function.'
Testing RGB_dist new function alone, with these input set
x=[62,29,64;
63,31,62;
65,29,60;
63,29,62;
63,31,62;];
d=RGB_dist(x,x);
disp(d);
outputs only values of 0.
Contrary to what your post says, you can use the Euclidean distance as part of pdist. You have to specify it as a flag when you call pdist.
The loop you have described above can simply be computed by:
dist_vect = pdist(U, 'euclidean');
This should compute the L2 norm between each unique pair of rows. Seeing that your matrix has a RGB pixel per row, and each column represents a single channel, pdist should totally be fine for your application.
If you want to display this as a distance matrix, where row i and column j corresponds to the distance between a pixel in row i and row j of your matrix U, you can use squareform.
dist_matrix = squareform(dist_vect);
As an additional bonus, if you want to find which two pixels in your matrix share the smallest distance, you can simply do a find search on the lower triangular half of dist_matrix. The diagonals of dist_matrix are going to be all zero as any vector whose distance to itself should be 0. In addition, this matrix is symmetric and so the upper triangular half should be equal to the lower triangular half. Therefore, we can set the diagonal and the upper triangular half to Inf, then search for the minimum for those elements that are remaining. In other words:
indices_to_set = true(size(dist_matrix));
indices_to_set = triu(indices_to_set);
dist_matrix(indices_to_set) = Inf;
[v1,v2] = find(dist_matrix == min(dist_matrix(:)), 1);
v1 and v2 will thus contain the rows of U where those RGB pixels contained the smallest Euclidean distance. Note that we specify the second parameter as 1 as we want to find just one match, as what your post has stated as a requirement. If you wish to find all vectors who match the same distance, simply remove the second parameter 1.
Edit - June 25th, 2014
Seeing as how you want to weight each component of the Euclidean distance, you can define your own custom function to calculate distances between two RGB pixels. As such, instead of specifying euclidean, you can specify your own function which can calculate the distances between two vectors within your matrix by calling pdist like so:
pdist(x, #(XI,XJ) ...);
#(XI,XJ)... is an anonymous function that takes in a vector XI and a matrix XJ. For pdist you need to make sure that the custom distance function takes in XI as a 1 x N vector which is a single row of pixels. XJ is then a M x N matrix that contains multiple rows of pixels. As such, this function needs to return a M x 1 vector of distances. Therefore, we can achieve your weighted Euclidean distance as so:
weights = [3;4;2];
weuc = #(XI, XJ, W) sqrt(bsxfun(#minus, XI, XJ).^2 * W);
dist_matrix = pdist(double(U), #(XI, XJ) weuc(XI, XJ, weights));
bsxfun can handle that nicely as it will replicate XI for as many rows as we need to, and it should compute this single vector with every single element in XJ by subtracting. We thus square each of the differences, weight by weights, then take the square root and sum. Note that I didn't use sum(X,2), but I used vector algebra to compute the sum. If you recall, we are simply computing the dot product between the square distance of each component with a weight. In other words, x^{T}y where x is the square distance of each component and y are the weights for each component. You could do sum(X,2) if you like, but I find this to be more elegant and easy to read... plus it's less code!
Now that I know how you're obtaining U, the type is uint8 so you need to cast the image to double before we do anything. This should achieve your weighted Euclidean distance as we talked about.
As a check, let's put in your matrix in your example, then run it through pdist then squareform
x=[62,29,64;
63,31,62;
65,29,60;
63,29,62;
63,31,62];
weights = [3;4;2];
weuc = #(XI, XJ, W) sqrt(bsxfun(#minus,XI,XJ).^2 * W);
%// Make sure you CAST TO DOUBLE, as your image is uint8
%// We don't have to do it here as x is already a double, but
%// I would like to remind you to do so!
dist_vector = pdist(double(x), #(XI, XJ) weuc(XI, XJ, weights));
dist_matrix = squareform(dist_vector)
dist_matrix =
0 5.1962 7.6811 3.3166 5.1962
5.1962 0 6.0000 4.0000 0
7.6811 6.0000 0 4.4721 6.0000
3.3166 4.0000 4.4721 0 4.0000
5.1962 0 6.0000 4.0000 0
As you can see, the distance between pixels 1 and 2 is 5.1962. To check, sqrt(3*(63-62)^2 + 4*(31-29)^2 + 2*(64-62)^2) = sqrt(3 + 16 + 8) = sqrt(27) = 5.1962. You can do similar checks among elements within this matrix. We can tell that the distance between pixels 5 and 2 is 0 as you have made these rows of pixels the same. Also, the distance between each of themselves is also 0 (along the diagonal). Cool!
I would like to plot two matrices both of (4*36 double) size. The first contains rho and the second contains depths for the 36 locations
well I looked into surf but it reads two arrays and one matrix rather than two matrices and yes I would like to plot them as column graph
here is an example
rho= magic(36);
rho(5:1:end,:)=[];
D= magic(36);
D(5:1:end,:)=[];
D=sort(depth);
So right now the matrix rho contains the densities for the 36 location at four different depths. The matrix D contains the four different depths at which the reading at rho is found. The first element in the first matrix corresponds to the first element in the second matrix and so on
in the end what I would like to have is the 36 column with the different reading from (rho) plotted against appropriate depth in (D)
I hope I helped make it clearer somehow
Simple example of plotting four sets of X and Y data:
X = repmat(1:36, [4 1]);
Y(1,:) = rand(1,36);
Y(2,:) = 0.2 * (1:36);
Y(3,:) = 5 * sin(linspace(-pi,pi,36));
Y(4,:) = 0.1 * (1:36).^2;
figure
plot(X', Y')
This results in
Note - in order to get four series to plot like this, the data has to be in COLUMNS. The original data was in 4x36 matrix, so it was in ROWS. I used the transpose operator (apostrophe - X' rather than just X) to get the data organized in columns.
Maybe this helps...
I need to generate N random coordinates for a 2D plane. The distance between any two points are given (number of distance is N(N - 1) / 2). For example, say I need to generate 3 points i.e. A, B, C. I have the distance between pair of them i.e. distAB, distAC and distBC.
Is there any built-in function in MATLAB that can do this? Basically, I'm looking for something that is the reverse of pdist() function.
My initial idea was to choose a point (say A is the origin). Then, I can randomly find B and C being on two different circles with radii distAB and distAC. But then the distance between B and C might not satisfy distBC and I'm not sure how to proceed if this happens. And I think this approach will get very complicated if N is a large number.
Elaborating on Ansaris answer I produced the following. It assumes a valid distance matrix provided, calculates positions in 2D based on cmdscale, does a random rotation (random translation could be added also), and visualizes the results:
%Distance matrix
D = [0 2 3; ...
2 0 4; ...
3 4 0];
%Generate point coordinates based on distance matrix
Y = cmdscale(D);
[nPoints dim] = size(Y);
%Add random rotation
randTheta = 2*pi*rand(1);
Rot = [cos(randTheta) -sin(randTheta); sin(randTheta) cos(randTheta) ];
Y = Y*Rot;
%Visualization
figure(1);clf;
plot(Y(:,1),Y(:,2),'.','markersize',20)
hold on;t=0:.01:2*pi;
for r = 1 : nPoints - 1
for c = r+1 : nPoints
plot(Y(r,1)+D(r,c)*sin(t),Y(r,2)+D(r,c)*cos(t));
plot(Y(c,1)+D(r,c)*sin(t),Y(c,2)+D(r,c)*cos(t));
end
end
You want to use a technique called classical multidimensional scaling. It will work fine and losslessly if the distances you have correspond to distances between valid points in 2-D. Luckily there is a function in MATLAB that does exactly this: cmdscale. Once you run this function on your distance matrix, you can treat the first two columns in the first output argument as the points you need.
I have a point-cloud, for which i want to calculate the distance between all individual points in Matlab (preferably without duplicates).
The matrix with the coordinates is formatted as: points [ p x n x d ]. Where p = 1 (for now), n is as large as the number of points and d as large as the number of dimensions (3 in this case).
This is the data i have:
points(:,:,1) = 1 2 3
points(:,:,2) = 4 5 6
points(:,:,3) = 7 8 9
So i have three points in three dimensions. Now using pdist, i have tried to calculate the euclidian distance between each point using distances = pdist(points(:,1:3)); and distances = pdist(X(:,:,1:3)); But both just return an empty matrix.
Does anyone know how to use pdist to calculate these distances? It should return 3 distances, instead of 0, but i must be doing something wrong.
Btw. this question is a follow up to this one. I asked it in the comments at first, but thought it deserved a new question because it is a considerable expansion of the original question.
Try
distances = pdist(squeeze(X(:,:,1:3)));
or the transpose of squeeze(...) if that isn't correct.