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:从图像中切出很多圆圈的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Java 中从 ArrayList 中切出 ArrayList?