计算大矩阵中RGB向量之间的欧几里德距离

时间:2014-06-24 23:41:14

标签: matlab image-processing matrix rgb euclidean-distance

我有一组不同像素的RGB矩阵。 (N像素=> n行,RGB => 3列)。我必须计算此矩阵中任意两个像素之间的最小RGB距离。我尝试了循环方法,但由于该集合太大(让我们说N = 24000),看起来它将需要永远完成程序。还有另一种方法吗?我读到了pdist,但RGB Euclidean距离不能与它一起使用。

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

两个像素之间的欧几里德距离: enter image description here 因此,pdist语法将如下所示:D=pdist2(U,U,@calc_distance());,其中U是这样获得的:

rgbImage = imread('peppers.png');
rgb_columns = reshape(rgbImage, [], 3)    
[U, m, n] = unique(rgb_columns, 'rows','stable');

但如果pdist2自行完成循环,我该如何输入我的函数参数?

function[distance]=RGB_dist(R1, R2, G1, G2, B1, B2),

其中R1,G1,B1,R2,G2,B2是每个像素的组成部分。

我做了一个像这样的新功能:

function[distance]=RGB_dist(x,y)

  distance=sqrt(sum(((x-y)*[3;4;2]).^2,2));

end

我称之为D=pdist(U,U,@RGB_dist);我使用pdist得到了错误(第132行) ' DISTANCE'论证必须是一个 字符串或函数。'

使用这些输入集

单独测试RGB_dist新函数
x=[62,29,64;
    63,31,62;
    65,29,60;
    63,29,62;
    63,31,62;];


d=RGB_dist(x,x);
disp(d);

仅输出值0.

1 个答案:

答案 0 :(得分:2)

与你的帖子所说的相反,你可以使用欧几里德距离作为pdist的一部分。当您致电pdist时,您必须指定作为旗帜。

您上面描述的循环可以简单地通过以下方式计算:

dist_vect = pdist(U, 'euclidean');

这应计算每对唯一行之间的L2范数。看到您的矩阵每行有一个RGB像素,而每列代表一个通道,pdist应该完全适合您的应用。

如果要将其显示为距离矩阵,则行i和列j对应于行i中的像素与您的矩阵j的行U,您可以使用squareform

dist_matrix = squareform(dist_vect);

作为额外的奖励,如果您想要找到矩阵中的哪两个像素共享最小距离,您只需在find的下三角半部分进行dist_matrix搜索。 dist_matrix的对角线将全部,因为任何向量与自身的距离应为0.此外,此矩阵是对称的,因此上三角形应该等于下三角半。因此,我们可以将对角线和上三角形半边设置为Inf,然后搜索剩余元素的最小值。换句话说:

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);
因此,

v1v2将包含U行,其中这些RGB像素包含最小的欧几里德距离。请注意,我们将第二个参数指定为1,因为我们只想找到一个匹配项,就像您的帖子所说的要求一样。如果您希望找到匹配相同距离的所有向量,只需删除第二个参数1


编辑 - 2014年6月25日

看看你想如何加权欧几里德距离的每个分量,你可以定义自己的自定义函数来计算两个RGB像素之间的距离。因此,您可以指定自己的函数,而不是指定euclidean,可以通过调用pdist来计算矩阵中两个向量之间的距离,如下所示:

pdist(x, @(XI,XJ) ...);

@(XI,XJ)...是一个匿名函数,它接收向量XI和矩阵XJ。对于pdist,您需要确保自定义距离函数将XI作为1 x N向量,这是一个像素。 XJM x N矩阵,包含多行像素。因此,此函数需要返回M x 1距离向量。因此,我们可以实现您的加权欧几里德距离:

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可以很好地处理它,因为它会根据需要复制XI多行,并且它应该通过减去XJ中的每个元素来计算这个单个向量。因此,我们将每个差异,weights加权,然后取平方根和求和。请注意,我没有使用sum(X,2),但我使用向量代数来计算总和。如果你还记得,我们只是计算每个组件与权重的平方距离之间的点积。换句话说,x^{T}y其中x是每个组件的平方距离,y是每个组件的权重。如果你愿意,你可以sum(X,2),但我觉得这更优雅,更容易阅读...而且代码更少!

现在我知道您是如何获得U的,因此类型为uint8,因此您需要在我们执行任何操作之前将图像投射到double。这应该达到我们所讨论的加权欧几里德距离。

作为一项检查,让我们在您的示例中添加矩阵,然后通过pdist然后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

如您所见,像素1和2之间的距离为5.1962。要检查sqrt(3*(63-62)^2 + 4*(31-29)^2 + 2*(64-62)^2) = sqrt(3 + 16 + 8) = sqrt(27) = 5.1962。您可以在此矩阵中的元素之间执行类似的检查。我们可以看出像素5和2之间的距离是 0 ,因为你已经使这些像素行相同。而且,它们之间的距离也是0(沿着对角线)。酷!