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!
RBG_dist
? I can't find it with Google - Luis MendoRGB_dist
is simply the distance between two colour pixels using the red, green and blue channels. Though we don't have the source code, it should be fairly easy to implement, depending on what criteria you use. OP: What kind of distance measure do you want to implement? - rayryengpdist
. You simply have to specify your own distance function to it. I'll write an answer for you but I need to know what distance measure you want first. Is it the Euclidean distance as what your post title says? - rayryengRGB_dist = @(x,y)sqrt(sum(((x-y)*[3;4;2]).^2,2))
should work. - jpjacobs