Performance MATLAB/Octave:从图像中剪切许多圆

Performance MATLAB/Octave:从图像中剪切许多圆,performance,matlab,image-processing,geometry,octave,Performance,Matlab,Image Processing,Geometry,Octave,我有一个矩阵(图像)和关于圆圈内有趣部分的信息 (给出了中心坐标和半径)。我想参加所有的比赛 部分矩阵,以便对每个圆进行更多计算。或者至少我想要一个包含所有圆圈的位掩码 我使用Octave(但也可以使用MATLAB,但由于许可证的限制,这将很困难),并且有下面的脚本和stackoverflow的一些提示。我有20个圆圈的信息,在我的核心i5上使用倍频程大约需要0.7秒: % image dim_x = 1000; dim_y = 1000; A=rand(dim_x,dim_y); % cen

我有一个矩阵(图像)和关于圆圈内有趣部分的信息 (给出了中心坐标和半径)。我想参加所有的比赛 部分矩阵,以便对每个圆进行更多计算。或者至少我想要一个包含所有圆圈的位掩码

我使用Octave(但也可以使用MATLAB,但由于许可证的限制,这将很困难),并且有下面的脚本和stackoverflow的一些提示。我有20个圆圈的信息,在我的核心i5上使用倍频程大约需要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;
%图像
尺寸x=1000;
尺寸y=1000;
A=兰特(尺寸x,尺寸y);
%中心位置和。。。
c=[222111;878112;81718;89112;222111;878112;81718;89112;222111;878112;81718;89112;222111;878112;81718;89112;81718;89112;222111;878112;81718;89112];
%...  圆的半径
r=[10335522210355225221035522522210210355222103552222];
抽搐;
对于i=1:尺寸(c,1)
%创建一个位掩码。。。
mask=bsxfun(@plus,((1:dim_y)-c(i,1))。^2,(转置(1:dim_x)-c(i,2))。^2
你知道一个更有效的解决方案吗,因为我想有大约600个圆圈

提前感谢

试试看

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

根据我的MATLAB profiler,这大约比你的版本快4倍。另外,
B=A.*掩码
行所用的时间与原始的
mask=…
行所用的时间大致相同。不确定你能做什么。

你可能想看看Matlab的
strel
(不确定倍频程的可用性,在Matlab中它是图像处理工具箱的一部分)

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


您还可以通过使用
bsxfun
重写
repmat
位来压缩它的一些性能。您可以做一些事情来提高代码的效率,尽管其中一些事情完全取决于您最终想要什么,以及您可以对圆圈做出什么样的假设(例如,它们是否可以重叠?是否有许多类似的半径?)

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

%# 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
%#图像
尺寸x=1000;
尺寸y=1000;
A=兰特(尺寸x,尺寸y);
%#中心位置和。。。
c=[222111;878112;81718;89112;222111;878112;81718;89112;222111;878112;81718;89112;222111;878112;81718;89112;81718;89112;222111;878112;81718;89112];
%#…圆的半径
r=[10335522210355225221035522522210210355222103552222];
%#找到最大的圆。。。
rMax=最大值(r);
%#…并创建一个距离数组
distFromCenterSquared=bsxfun(@plus,(-rMax:rMax)。^2,转置(-rMax:rMax)。^2);
%#现在我们可以在半径上循环,为所有圆创建逻辑掩码
mask=false(dim_x,dim_y);%#如果希望一次一个圆,则在循环内初始化
对于i=1:长度(r)
%#创建逻辑小圆圈掩码
最小任务=距离中心平方(rMax-r(i)+1:end-(rMax-r(i)),rMax-r(i)+1:end-(rMax-r(i))。。。

顺便说一下:如果你有不重叠的圆,你可以在循环后使用
bwlabel
(或者使用find和sub2ind将
i
写入各个圆),这样你就可以使用
accumarray

一次性处理所有圆。我建议使用MATLAB图像处理工具箱中的函数(也可在倍频程软件包中获得)。检查“算法”部分,查看它如何处理离散像素

以下是测试性能的示例:

%# 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秒


<代码> Strel <代码>似乎不在倍频程中。这太糟糕了:-我认为这可能是一种非常快的方法。我只说这是因为它依赖于代码> Strut,它已经被MATLAB重优化了。你可能想考虑预计算或至少缓存掩模达到一定的大小。re是大量重复的
r
值。因此,每次计算遮罩时,计算圆形部分,然后将其存储在单元格数组或其他东西中,然后将其移动中心偏移量以实际应用。当再次遇到相同的r时,只需从单元格数组中拉出遮罩。相关:
%# 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