MATLAB / Octave:从图像中切出很多圆圈

Posted

技术标签:

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

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

我使用 Octave(但也可以使用 MATLAB,但由于许可证的原因会很困难),并且有以下脚本以及来自 *** 的一些提示。我有 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 时,只需从元胞数组中拉出掩码即可。 相关:MATLAB: how do I crop out a circle from an image 【参考方案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 秒。

【讨论】:

以上是关于MATLAB / Octave:从图像中切出很多圆圈的主要内容,如果未能解决你的问题,请参考以下文章

从背景中切出的透明文本

从背景中切出的透明文本

Android - 从方形位图中切出一个圆圈

如何在 Java 中从 ArrayList 中切出 ArrayList?

如何从 GTK+2 C 代码中调用 matlab/octave 函数

有人用过octave吗?能替代matlab吗