从千个图像中提取许多兴趣区域ROI)

时间:2014-09-04 08:20:02

标签: image matlab

我有大量的显微镜图像,每张图像都有数百个点(ROI)。这些斑点固定在太空中。我想从每个图像中提取每个点并保存到工作区中,以便我可以进一步分析它们。

我自己编写了一个代码,它运行得很好,但速度太慢了。大约需要250秒才能完全读出每张图像中的所有斑点。

我的代码核心如下:

for s=1:NumberImages   
  im1=imread(fn(s,1).name);    
  im=im1-medfilt2(im1,[15,15]);    
  for i=1:length(p_g_x)    
    GreenROI(i,s)=double(sum(sum(im(round(p_g_y(i))+(-2:2), round(p_g_x(i))+(-2:2)))));
    RedROI(i,s)=double(sum(sum(im(round(p_r_y(i))+(-2:2), round(p_r_x(i))+(-2:2)))));        
  end
end

从代码中可以看出,我正在提取5x5区域。 p_g_x的长度在500-700之间。

感谢您的投入。我使用个人资料查看器来确定哪个功能正好花费更多时间。这是中值滤波器,需要花费很多时间(约90%)。

任何有关加快速度的建议都将不胜感激。

感谢

马希普尔

4 个答案:

答案 0 :(得分:3)

使用Matlab的分析工具!

profile on % Starts the profiler
% Run some code now.
profile viewer % Shows you how often each function was called, and
               % where most time was spent. Try to start with the slowest part.
profile off  % Resets the Profiler, so you can measure again.

预分配

预先输出输出,因为你知道它的大小,这样它的速度要快得多。 (Matlab已经告诉过你了!)

GreenROI = zeros(length(p_g_x), NumberImages); % And the same for RedROI.

使用卷积

阅读Matlab的conv2代码。

for s=1:NumberImages   
  im=imread(fn(s,1).name);    
  im=im-medfilt2(im,[15,15]);    
  % Pre-compute the sums first. This will only be faster for large p_g_x
  roi_image = conv2(im, ones(5,5));
  for i=1:length(p_g_x)    
    GreenROI(i,s)=roi_image(round(p_g_y(i)), round(p_g_x(i))); % You might have to offset the indices by 2, because of the convolution. Check that results are the same.
    RedROI(i,s)=roi_image(round(p_r_y(i)), round(p_r_x(i)));        
  end
end

Matlab-ize代码

现在,您已经使用卷积来获取超过5x5窗口的图像(或者您可以使用@ Shai' s accumarray,同样的事情),您可以加速不再遍历p_g_x中的每个元素,而是直接将其用作向量。

我把它作为读者的练习。 (使用p_g_xp_g_ysub2ind转换为索引,作为提示)。

更新

我的答案,包括我的答案,表明过早优化是一件坏事。在不知情的情况下,我认为你的循环会占用大部分时间,但是当你测量它时(谢谢!),事实证明这不是问题。瓶颈是medfilt2中值过滤器,占90%的时间。所以你应该先解决这个问题。 (请注意,在我的计算机上,您的原始代码足够快,但我的口味仍然是中位数过滤器占用的大部分时间。)

查看中值过滤器操作的作用可能有助于我们弄清楚如何使其更快。这是一张图片。在左侧,您可以看到原始图像。在中间过滤器中间,在右侧有结果。

enter image description here

对我而言,结果与边缘检测结果非常相似。 (数学上这并不奇怪。)

我建议你开始尝试各种边缘检测。看看Canny和Sobel。或者只使用conv2(image, kernel_x) kernel_x = [1, 2, 1; 0, 0, 0; -1, -2, -1]kernel_y相同但转置edge(im, option)。您可以在此处找到各种边缘检测选项:{'sobel', 'canny', 'roberts', 'prewitt'}。我尝试了imgradient的所有选项。除了Canny之外,它们与中值滤波方法大致相同。 Canny慢了4倍,其余的(包括原版)需要7.x秒。所有这一切都没有GPU。 gpuArray是9秒。

因此,我会说你不能更快。如果你有一个GPU,它可以与Matlab一起使用,你可以加速它。将图片加载为{{1}} s。 medfilt2 documentation上有一个例子。你仍然可以做一些小的加速,但它们只能增加10%的速度,所以几乎不值得。

答案 1 :(得分:2)

你应该做的一些事情

  1. Pre-allocate按照Didac Perez的建议。

  2. 使用profiler查看代码中完全需要多长时间,是中值过滤器吗?它是索引吗?

  3. 假设所有图片大小相同,您可以使用accumarray和固定掩码subs快速求和值:

    subs_g = zeros( h, w ); %// allocate mask for green
    subs_r = zeros( h, w );  
    subs_g( sub2ind( [h w], round(p_g_y), round(p_g_x) ) = 1:numel(p_g_x); %//index each region
    subs_g = conv2( subs_g, ones(5), 'same' );
    subs_r( sub2ind( [h w], round(p_r_y), round(p_r_x) ) = 1:numel(p_r_x); %//index each region
    subs_r = conv2( subs_r, ones(5), 'same' );
    sel_g = subs_g > 0;
    sel_r = subs_r > 0;
    subs_g = subs_g(sel_g);
    subs_r = subs_r(sel_r);
    

    修复这些蒙版后,您可以处理所有图像

    %// pre-allocation goes here - I'll leave it to you
    for s=1:NumberImages   
        im1=imread(fn(s,1).name);    
        im=double( im1-medfilt2(im1,[15,15]) ); 
        accumarray( subs_g, im( sel_g ) ); % summing all the green ROIs 
        accumarray( subs_r, im( sel_r ) ); % summing all the green ROIs 
    end
    

答案 2 :(得分:0)

首先,预先分配您的GreenROI和RedROI结构,因为您之前知道最终大小。现在,您将在每次迭代中反复调整它们的大小。

其次,我建议你使用" tic"和" toc"为了研究问题的位置,它将为您提供有用的时间。

答案 3 :(得分:0)

对每个图像进行操作的矢量化代码 -

%// Pre-compute green and red indices to be used across all the images
r1 = round(bsxfun(@plus,permute(p_g_y,[3 2 1]),[-2:2]'));
c1 = round(bsxfun(@plus,permute(p_g_x,[3 2 1]),[-2:2]));
green_ind = reshape(bsxfun(@plus,(c1-1)*size(im,1),r1),[],numel(p_g_x));

r2 = round(bsxfun(@plus,permute(p_r_y,[3 2 1]),[-2:2]'));
c2 = round(bsxfun(@plus,permute(p_r_x,[3 2 1]),[-2:2]));
red_ind = reshape(bsxfun(@plus,(c2-1)*size(im,1),r2),[],numel(p_g_x));

for s=1:NumberImages
    im1=imread(fn(s,1).name);
    im=double(im1-medfilt2(im1,[15,15]));

    GreenROI=sum(im(green_ind));
    RedROI =sum(im(red_ind));
end