【问题标题】:Vectorization of min distance in kernel内核中最小距离的矢量化
【发布时间】:2014-03-12 14:33:43
【问题描述】:

我有一个 Nx2 数组 K1 与 N 个关键点的位置和一个 3 维 WxHx3 数组 Kart1(width,height,coordinates) 将坐标映射到图像的每个像素。对于K1 中的每个关键点,我想读取Kart1 中像素的位置,并在其周围的 3x3 内核中评估坐标(搜索最小值/最大值或计算平均值)并为当前像素赋值在KPCoor1

我目前的做法是这样的:

for ii=1:length(K1(:,1)) %for every keypoint in K1

    MinDist=sqrt(sum(Kart1(K1(ii,2)-1,K1(ii,1)-1,:).^2)); %Calculate distance
    xShift=0;
    yShift=0;
    for kk=-1:1 %for every pixel in a 3x3 kernel...
        for ll=-1:1

            Distance=sqrt(sum(Kart1(K1(ii,2)+kk,K1(ii,1)+ll,:).^2));

            if Distance<MinDist   %... if the current distance is smaller than MinDist
                MinDist=Distance; %... update MinDist...
                xShift=kk; %... and take the kernel coordinate of the pixel
                yShift=ll;
            end

        end
    end

    KP1Coor(ii,:)=Kart1(K1(ii,2)+xShift,K1(ii,1)+yShift,:); %assign the coordinates of the pixel with the minimal distance in kernel.

end

它可以运行,但是很丑,我怀疑它是否在做我想做的事情。我对此事的“多维性”感到有些困惑,不知道评估内核的许多函数,并且想不出使用诸如bsxfun() 或逻辑运算之类的矢量化函数的方法(意味着我被卡住了我的大脑很干:/)

关于如何消除这些循环/更正代码的任何建议?

【问题讨论】:

  • 我认为您需要在第一个嵌套循环中使用xShift=-1yShift=-1,您不觉得吗?另外,你需要MinDist 作为输出吗?
  • 在这种情况下,我对最小距离的“位置”更感兴趣,我从 x 和 y 的变化中读出了这一点。这就是我使用它们的目的。 PS:我以更优雅的方式完全解决了这个问题,仍然感谢您对一个老问题的评论!
  • 好吧,我仍然继续使用基于bsxfun 的自己的解决方案!你说你已经实现了它的一个高效版本,我想我不会介意showdown of benchmarks 反对这里介绍的版本,如果你也愿意:) 如果你这样做,也许你可以编辑你的问题它或在这里制作自己的解决方案,尽管我认为后一个会很好。
  • 我的意思是我不再需要寻找那个了,但请放心,到目前为止,您的回答会赢得摊牌! ;)

标签: matlab multidimensional-array vectorization lookup bsxfun


【解决方案1】:

向量化方法:在深入研究向量化实现之后,它看起来很有趣look-up problem,所以如果您仍然对完成工作的向量化技术感兴趣,这里有一个带有@的方法987654321@-

%// Scalars to replace their repeated usages in the code
[W,H,NC]= size(Kart1);
d3a = 1:NC;

%// Indices for Kart1 at the first level of the nested loops
BI = bsxfun(@plus,K1(:,2)+(K1(:,1)-1)*W,(d3a-1)*W*H);

%// Indices for Kart1 in 3x3 kernel around the indices obtained at first level
BIW3 = bsxfun(@plus,[-1 0 1]',[-W 0 W]); %//'
%// Linear indices for the minimum value of Kart1 in the 3x3 neighborhood 
[~,MI3] = min(sqrt(sum(Kart1(bsxfun(@plus,...
    BI,permute(BIW3(:),[3 2 1]))).^2,2)),[],3);
%// X-Y indices
[xShift1,yShift1] = ind2sub([3 3],MI3);

%// Get Kart1 values corresponding to the indices for the minimum values
KP1Coor = Kart1(bsxfun(@plus,...
    K1(:,2)+xShift1-2 +(K1(:,1)+yShift1-2-1)*W,(d3a-1)*W*H));

基准测试

我也可以使用 Parallel Computing Toolbox 中的 gpuArray 使用 GPU 对其进行测试,然后使用 W = 1000H = 1000 运行一些基准测试,并使用 N 作为数据大小,使用 [1000 2000 5000 10000 20000] 改变它。结果似乎很疯狂,尽管并非不可靠,因为使用了来自Measure and Improve GPU Performance 的批准的基准测试方法。这是原始代码以及 CPU 和 GPU 矢量化代码的基准图 -

然后只对矢量化代码和更大的数据大小进行基准测试似乎是合适的,其图如下所示 -

结论:这个问题基本上看起来像一个查找问题,其中Kart1 是数据,K1 是要查找的索引数组。这里介绍的矢量化解决方案基本上是一种蛮力方法,基准测试结果显然有利于性能。但是,看看是否有任何非暴力方法甚至可能是基于循环的,但可以有效地利用这种查找,是否可以表现得更好。

【讨论】:

  • 感谢您提供如此出色的答案并回到老问题!即使在当前问题之外,我也从您的“作品”中学到了很多东西并获得了新的想法!
猜你喜欢
  • 2014-07-10
  • 1970-01-01
  • 2018-06-13
  • 1970-01-01
  • 1970-01-01
  • 2018-01-30
  • 1970-01-01
  • 2018-05-24
  • 2019-02-01
相关资源
最近更新 更多