我有大量的显微镜图像,每张图像都有数百个点(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%)。
任何有关加快速度的建议都将不胜感激。
感谢
马希普尔
答案 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
现在,您已经使用卷积来获取超过5x5窗口的图像(或者您可以使用@ Shai' s accumarray
,同样的事情),您可以加速不再遍历p_g_x
中的每个元素,而是直接将其用作向量。
我把它作为读者的练习。 (使用p_g_x
将p_g_y
和sub2ind
转换为索引,作为提示)。
我的答案,包括我的答案,表明过早优化是一件坏事。在不知情的情况下,我认为你的循环会占用大部分时间,但是当你测量它时(谢谢!),事实证明这不是问题。瓶颈是medfilt2
中值过滤器,占90%的时间。所以你应该先解决这个问题。 (请注意,在我的计算机上,您的原始代码足够快,但我的口味仍然是中位数过滤器占用的大部分时间。)
查看中值过滤器操作的作用可能有助于我们弄清楚如何使其更快。这是一张图片。在左侧,您可以看到原始图像。在中间过滤器中间,在右侧有结果。
对我而言,结果与边缘检测结果非常相似。 (数学上这并不奇怪。)
我建议你开始尝试各种边缘检测。看看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)
你应该做的一些事情
Pre-allocate按照Didac Perez的建议。
使用profiler
查看代码中完全需要多长时间,是中值过滤器吗?它是索引吗?
假设所有图片大小相同,您可以使用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