【问题标题】:MATLAB/Octave: cut a lot of circles from a imageMATLAB / Octave:从图像中切出很多圆圈
【发布时间】:2011-09-28 13:50:24
【问题描述】:

我有一个矩阵(图像)和有关圆圈内有趣部分的信息 (给定的中心坐标和半径)。我想剪掉所有的圈子 矩阵的一部分,以便为每个圆做更多的计算。或者至少我想要一个带有所有圆圈的位掩码。

我使用 Octave(但也可以使用 MATLAB,但由于许可证的原因会很困难),并且有以下脚本以及来自 stackoverflow 的一些提示。我有 20 个圆圈的信息,在我的 Core i5 上使用 Octave 大约需要 0.7 秒:

% image
dim_x = 1000;
dim_y = 1000;
A=rand(dim_x,dim_y);

% center positions and ...
c = [222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112];
%...  radii of the circles
r = [10 33 55 2 22 10 33 55 2 22 10 33 55 2 22 10 33 55 2 22];

tic;
for i=1:size(c,1)
    % create a bitmask ...
    mask = bsxfun(@plus, ((1:dim_y) - c(i,1)).^2, (transpose(1:dim_x) - c(i,2)).^2) < r(i)^2;
    % ... cut the circles out of the image
    B=A.*mask;
end;
toc;

你知道一个更高效的解决方案,因为我想要大约 600 个圈子。

提前致谢

【问题讨论】:

  • 您可能需要考虑预先计算或至少将掩码缓存到一定大小。看起来有很多重复的 r 值。因此,每次计算掩码时,计算圆形部分,然后将其存储在单元格数组或其他东西中,然后将其移动中心偏移量以实际应用它。当再次遇到相同的 r 时,只需从元胞数组中拉出掩码即可。

标签: performance matlab image-processing geometry octave


【解决方案1】:

试试

mask = bsxfun(@lt, ((1:dim_y) - c(i,1)).^2,  r(i)^2 - ((1:dim_x).' - c(i,2)).^2);

根据我的 MATLAB 分析器,这比您的版本快大约 4 倍。此外,B = A.*mask 行与原始mask = ... 行所用的时间大致相同。不确定您能做些什么。

【讨论】:

    【解决方案2】:

    您可以做几件事来提高代码效率,但其中一些取决于您最终想要什么,以及您可以对圆圈做出哪些假设(例如,它们可以重叠吗?有很多类似的吗?半径?)。

    下面是一个假设半径之间几乎没有重复的解决方案,并且中心坐标始终是整数像素值。

    %# image
    dim_x = 1000;
    dim_y = 1000;
    A=rand(dim_x,dim_y);
    
    %# center positions and ...
    c = [222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112];
    %#...  radii of the circles
    r = [10 33 55 2 22 10 33 55 2 22 10 33 55 2 22 10 33 55 2 22];
    
    %# find the largest circle...
    rMax = max(r);
    %#... and create a distance array
    distFromCenterSquared = bsxfun(@plus,(-rMax:rMax).^2,transpose(-rMax:rMax).^2);
    
    %# now we can loop over the radii to create the logical mask for all circles
    mask = false(dim_x,dim_y); %# initialize inside the loop if you want one circle at a time
    for i=1:length(r)
    
        %# create logical mini-circle mask
        miniMask = distFromCenterSquared(rMax-r(i)+1:end-(rMax-r(i)),rMax-r(i)+1:end-(rMax-r(i)))...
           < r(i)^2;
    
        %# add to the mask. The ranges need to be fixed, obviously, if 
        %# circles can be only partially inside the image
        %# also, the "or" is only necessary if you're adding to
        %# a mask, instead of recreating it each iteration
        mask(c(i,1)-r(i):c(i,1)+r(i),c(i,2)-r(i):c(i,2)+r(i)) = ...
           mask(c(i,1)-r(i):c(i,1)+r(i),c(i,2)-r(i):c(i,2)+r(i)) | ...
           miniMask;
    
    end
    

    顺便说一句:如果你有不重叠的圆圈,你可以在循环之后使用bwlabel(或者使用find和sub2ind将i写入单个圆圈中),这样你就可以在一个圆圈中处理所有的圆圈去使用accumarray

    【讨论】:

      【解决方案3】:

      您可能想查看 Matlab 的 strel(不确定 Octave 的可用性,在 Matlab 中它是图像处理工具箱的一部分)。

      radius = 10;
      center = [320 240];
      nn = 0; 
      se = strel('disk', radius, nn);
      px = se.getneighbors;
      px = px + repmat(center, [length(px) 1]);
      

      nn 参数影响性能。将其设为 4、6 或 8 会提高性能,但代价是您的蒙版不是精确的圆形。

      您还可以通过使用bsxfun 重写repmat 位来从中挤出一些性能。

      【讨论】:

      • Strel 似乎不是八度音阶。
      • 太糟糕了:-/我认为这可能是一种非常快速的方法。我之所以这么说,是因为它依赖于 strel,它已经被 Matlab 进行了大量优化,用于繁重的工作。
      【解决方案4】:

      我建议使用 MATLAB 图像处理工具箱中的 POLY2MASK 函数(也可在 Octave 的 Image 包中找到)。查看“算法”部分,了解它如何处理离散像素。

      这是一个测试性能的例子:

      %# image
      dim_x = 1000;
      dim_y = 1000;
      A = rand(dim_x,dim_y);
      
      %# center positions and radii of the circles
      c = [222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112];
      r = [10 33 55 2 22 10 33 55 2 22 10 33 55 2 22 10 33 55 2 22];
      
      %# lets make them 600 circles
      c = repmat(c,30,1);
      r = repmat(r,1,30);
      
      %# zero-centered unit circle
      t = linspace(0,2*pi,50);
      ct = cos(t);
      st = sin(t);
      
      %# compute binary mask for each circle
      tic
      for i=1:numel(r)
          %# scale and shift scale circle, and use to get mask
          BW = poly2mask(r(i).*ct + c(i,1), r(i).*st + c(i,2), dim_x, dim_y);
      
          %# use the mask ...
      end
      toc
      

      在我的笔记本电脑上,完成:

      经过的时间是 4.864494 秒。

      【讨论】:

        猜你喜欢
        • 2012-06-29
        • 2011-06-06
        • 2012-12-06
        • 2014-10-27
        • 1970-01-01
        • 1970-01-01
        • 2017-11-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多