我有一组不同像素的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
两个像素之间的欧几里德距离:
因此,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.
答案 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);
因此, v1
和v2
将包含U
行,其中这些RGB像素包含最小的欧几里德距离。请注意,我们将第二个参数指定为1
,因为我们只想找到一个匹配项,就像您的帖子所说的要求一样。如果您希望找到匹配相同距离的所有向量,只需删除第二个参数1
。
看看你想如何加权欧几里德距离的每个分量,你可以定义自己的自定义函数来计算两个RGB像素之间的距离。因此,您可以指定自己的函数,而不是指定euclidean
,可以通过调用pdist
来计算矩阵中两个向量之间的距离,如下所示:
pdist(x, @(XI,XJ) ...);
@(XI,XJ)...
是一个匿名函数,它接收向量XI
和矩阵XJ
。对于pdist
,您需要确保自定义距离函数将XI
作为1 x N
向量,这是一个行像素。 XJ
是M 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(沿着对角线)。酷!