Image 图像间欧氏距离
我有两个图像,比如说Image 图像间欧氏距离,image,algorithm,matlab,Image,Algorithm,Matlab,我有两个图像,比如说p和S,大小为8192×200,我想计算它们之间的自定义“欧几里德距离”。目前,我使用以下步骤: 将图像重塑为一对列向量和行向量: Ip=Ip(:); Is=Is(:); 计算一个度量矩阵,G,其条目由公式给出 G(i,j) = 1/(2*pi*r*r) * exp((-d*d)/(2*r*r)); 其中,r是一个从0到20变化的全局参数,d是像素i和像素j之间的距离。例如,如果像素i为(k,l)且像素j为(k1,l1),则d=sqrt((k-k1)^2+(l-l1)^2
p
和S
,大小为8192×200,我想计算它们之间的自定义“欧几里德距离”。目前,我使用以下步骤:
Ip=Ip(:);
Is=Is(:);
G
,其条目由公式给出
G(i,j) = 1/(2*pi*r*r) * exp((-d*d)/(2*r*r));
其中,r
是一个从0到20变化的全局参数,d
是像素i
和像素j
之间的距离。例如,如果像素i
为(k,l)
且像素j
为(k1,l1)
,则d=sqrt((k-k1)^2+(l-l1)^2)代码>。像素1将是(1,1)
,像素2将是(1,2)
,依此类推。因此,矩阵G
的大小将为1638400×1638400
ImEuDist = sqrt( (Ip-Is) * G * (Ip-Is).' );
请帮我优化这个;我希望它能在几秒钟内运行。请注意,我对涉及GPU的解决方案不感兴趣 如果我理解正确,您应该能够执行以下操作,并在2s下运行它: 样本数据:
s1 = 8192; s2 = 200;
img_a = rand(s1, s2);
img_b = rand(s1, s2);
r = 2;
以及计算本身:
img_diff=img_a-img_b;
kernel=bsxfun(@plus,(-s1:s1)。^2.,(-s2:s2)。^2);
内核=1/(2/pi/r^2)*exp(-kernel/(2*r*2));
g=conv2(img_diff,内核“相同”);
res=g(:)'*img_diff(:);
res=sqrt(res);
以上过程大约需要25秒。要精确到2秒,您需要用更快的、基于fft的卷积代替标准的conv2
。见和:
函数c=conv2fft(X,Y)
%忽略小的浮点差异,这是等效的
%到内置的Matlab conv2(X,Y,‘相同’)
X1=[X个零(大小(X,1),大小(Y,2)-1);
零(大小(Y,1)-1,大小(X,2)+大小(Y,2)-1)];
Y1=零(尺寸(X1));
Y1(1:size(Y,1),1:size(Y,2))=Y;
c=ifft2(fft2(X1)。*fft2(Y1));
c=c(尺寸(X,1)+1:尺寸(X,1)+尺寸(X,1),尺寸(X,2)+1:尺寸(X,2)+尺寸(X,2));
结束
顺便说一句,如果您仍然希望它运行得更快,您可以利用
exp(-d^2/r^2)
对于相当小的d非常接近于零的事实:因此您实际上可以将内核裁剪为一个小矩形,而不是上面建议的大矩形。更小的内核意味着conv2fft
(尤其是conv2
)运行得更快。我仍然认为您应该给出一个图表。只需在绘画中做一些简单的事情感谢编辑,但在第一步中,我同时将两个图像重塑为行向量或列向量,而不是一对行向量和列向量。我可以知道你的想法吗?如果你还需要图片,请告诉我。我可以放一个简单的。一个图像会很好,是的。我认为你的第一步不是正确的方法,考虑到你正在努力做的事情。“我的编辑”确实稍微改变了它(在转换为向量之前,您翻转了两幅图像),但这对解决整个问题并不特别有趣/相关。我不确定你在评论中所说的“同时”是什么意思。我所说的同时,是指Ip
和Is
都是行向量或列向量。它排除了Ip
是行向量和是列向量的情况,反之亦然。非常感谢您提供了如此出色的解决方案。如果有任何疑问,我会在这个帖子中再次回复你。再次感谢。如果您可以检查此解决方案是否有效(或者几乎有效),请将其标记为正确。另外,编辑上一个问题以链接到此问题可能会很好。请您解释一下步骤kernel=bsxfun(@plus,(-s1:s1)。^2.”,(-s2:s2)。^2)背后的想法好吗代码>。此外,在这一步之后,数字非常大,以至于MATLAB为表达式exp(-kernel/(2*r*2))
生成了0。因此,我认为这不符合我的目的。@nagarwal-第一行生成(正确地)一个大的2d数组,给出中心一点和每隔一点的一个点之间的平方距离。卷积将内核移动到每个可能的位置,并对该位置进行乘法和,这就是您所需要的。关于“Matlab正在生成[几乎]0”,我想你会发现这正是你想要的,我在答案的最后记下了这一点。我对你的代码进行了彻底的分析,意识到你的想法非常好。内核实际上是以多个8152x200数组的形式存储每个像素与所有其他像素的距离,然后卷积完成乘法和加法的其余工作。我只觉得在第一行,kernel应该定义为kernel=bsxfun(@plus,(-s1+1:s1-1)。^2',(-s2+1:s2-1)。^2)因为我不认为这些角行和角列有任何距离。虽然我仍然相信,由于我们在conv2
期间使用了same
标志,因此我们的结果不会受到影响。