【问题标题】:Fast way to copy pixels belonging to the circles复制属于圆圈的像素的快速方法
【发布时间】:2015-08-12 20:23:06
【问题描述】:

我有一个img 格式的初始灰度图像double,其中包含多个具有相同半径的圆和具有圆心坐标xy 的列向量。我需要将属于圆圈的所有像素复制到数组cpix。到目前为止,我只提出了使用for 循环的最直接的解决方案。有没有办法对这段代码进行矢量化或让它更快地运行?

% x(:) - vector with a few circles center X coordinates
% y(:) - vector with a few circles center Y coordinates
d = 27;                  %diameter
r = floor(d/2);          %radius
cpix = double(zeros(d,d,size(x,1)));

for iCent = 1:size(x,1)  %for each circle
    for ix = 1:d
        for iy = 1:d
            if ((ix-r)^2 + (iy-r)^2) < r^2
                cpix(iy,ix,iCent) = img(iy+y(iCent)-r,ix+x(iCent)-r);
            end
        end
    end
end

【问题讨论】:

  • 圆可以靠近图像的边界吗?在这种情况下应该怎么办?
  • 不,圆圈距离边界超过半径r

标签: matlab image-processing vectorization


【解决方案1】:

只需一个循环(每个圆圈),您就可以使用像磁盘这样的蒙版从图像中选择合适的像素。 从您的初始代码开始。

% x(:) - vector with a few circles center X coordinates
% y(:) - vector with a few circles center Y coordinates
d = 27;                  %diameter
r = floor(d/2);          %radius
cpix = double(zeros(d,d,size(x,1)));

现在创建具有所需半径的蒙版。如果您有图像处理工具箱,就可以轻松完成。

h = fspecial('disk', r);
h = h > 0;

然后在循环中使用这个掩码来选择所需的区域。

for i = 1:size(x,1)
    cpix(:,:,i) = h .* img(x(i)-r:x(i)+r, y(i)-r:y(i)+r);
end

由于您只创建一次蒙版,因此它应该比为每个圆圈计算它要快。

如果您构建 3D 蒙版,您可以一次性完成。如果a x b 是图像的大小,n 是圆圈的数量,则掩码将为a x b x n。如果你repmat你的图像到一个大小为n的堆栈。然后,您可以使用 .* 乘法来获得最终结果。但是,结果将是一堆a x b 图像,而不是您提到的d x d。 不确定它是否会更快,因为无论如何您都必须在创建 3D 蒙版期间循环它。如果遮罩只构建一次并用于大量图像,那可能是值得的。

【讨论】:

  • 谢谢!这是一个完美的解决方案,与我原始代码的 4.594374 相比,只需 0.008290 秒即可工作。我唯一需要更改的是 img 索引 - y 和 x 被交换,所以该行看起来像 cpix(:,:,i) = h .* img(y(i)-r:y(i)+r, x(i)-r:x(i)+r);
  • 请在某处通知用户将需要图像处理工具箱来运行您的解决方案。如果以后用户尝试此代码并且在他们不知道原因的情况下失败,则可能会减少挫败感。
  • 谢谢@hoki!我添加了图像处理工具箱注释。
【解决方案2】:

考虑到您的图像是双倍的并且有 1 层,对于圆的中心在 [cx,cy],您可以获得一个与主图像大小相同的矩阵,其中 1 指定像素的逻辑值在圆内(半径 = r),否则为 0

[X,Y] = meshgrid(1:size(img,1),1:size(img,2));
C = bsxfun(@le,(X-cx).^2+(Y-cy).^2 ,r);

最后,img(C) 包含所有有效的像素值。

单圈示例:

r = 5;
cx=100;
cy=100;
Id = im2double(imread('myimage.png'));
Id1 = Id(:,:,1);
[X,Y] = meshgrid(1:size(Id1,1),1:size(Id1,2));
C = bsxfun(@le,(X-cx).^2+(Y-cy).^2 ,r);

length(Id1(C))
ans = 
      21

圈子不止一个,你需要有一个for循环

cx = [100,110,120];
cy = [150,170,190];

for ii = 1:length(cx);
    C = bsxfun(@le,(X-cx(ii)).^2+(Y-cy(ii)).^2 ,r);
end

代码的其他部分保持不变。

【讨论】:

  • 这是一种方法,但也许您可以扩展您的示例以处理中心 cxcyarray。 OP 似乎有一些需要处理。
  • 感谢您的建议,这是一个有趣的方法。但关键是要得到3维数组,第3维等于圆数
  • 完全矢量化在这里可能没有好处,所以单循环在我看来是合理的。干得好!
  • 执行建议的代码后,我需要再次进行分段以获得所需的数组,其中有关圆圈内磁盘区域的所有信息都将在第 3 维中进行索引。要处理具有 350 个半径 = 15 的圆的示例图像 966x966px,我的代码需要 4.59 秒,NKN 提出的代码需要 3.60 秒(请记住,执行后我需要再次执行某种循环才能获得所需的数组)那么有没有办法进行产生指定数组的矢量化操作?我还没想出基于meshgrid的解决方案
【解决方案3】:

我有一个开源库pixelscan,它可以扫描各种空间模式(圆、环、蛇、网格、随机游走)中的像素。还可以应用各种空间变换(例如,旋转、缩放、裁剪)。它是一个 python 库,但您可以轻松地将相关代码移植到 MATLAB。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-30
    • 2011-09-05
    相关资源
    最近更新 更多