本代码的改进范围

时间:2011-05-18 23:54:04

标签: matlab performance parallel-processing

我在MATLAB中编写了以下代码来处理大小为3000x2500像素的图像。目前该操作需要半个多小时才能完成。是否有任何改进代码的余地可以消耗更少的时间?我听说并行处理可以让事情变得更快,但我不知道如何实现它。如果给出以下代码,我该怎么做?

function dirvar(subfn)
[fn,pn] = uigetfile({'*.TIF; *.tiff; *.tif; *.TIFF; *.jpg; *.bmp; *.JPG; *.png'}, ...
            'Select an image', '~/');
I = double(imread(fullfile(pn,fn)));
ld = input('Enter the lag distance = '); % prompt for lag distance
fh = eval(['@' subfn]); % Function handles
I2 = uint8(nlfilter(I, [7 7], fh));
imshow(I2); % Texture Layer Image
imwrite(I2,'result_mat.tif');

% Zero Degree Variogram
function [gamma] = ewvar(I)
    c = (size(I)+1)/2; % Finds the central pixel of moving window
    EW = I(c(1),c(2):end); % Determines the values from central pixel to margin of window
    h = length(EW) - ld; % Number of lags
    gamma = 1/(2 * h) * sum((EW(1:ld:end-1) - EW(2:ld:end)).^2);
end

输入滞后距离通常为1.

3 个答案:

答案 0 :(得分:3)

一些通用技巧:

1 - 使用MATLAB profiler确定所有计算瓶颈

2 - 并行处理可以使事情变得更快,并且您可以使用许多工具,但这取决于您的整个代码的设置方式以及代码是否针对它进行了优化。到目前为止,最简单的学习方法是parfor,您可以在其中用for替换顶级parfor循环。这意味着您必须使用matlabpool open打开MATLAB池。

3 - 如果你有一个相当新的Nvidia GPU以及MATLAB 2011,你也可以写一些CUDA代码。

对我而言,总共30分钟就是花生,所以不要担心太多。

答案 1 :(得分:3)

您确实需要使用分析器来获得一些改进。我的第一个猜测(因为我没有运行探查器,你应该已经建议),将使用尽可能少的length操作。由于您使用[7 7]窗口处理每个图像,因此可以预先计算某些部分, 这样你就不会重复这些动作了

function dirvar(subfn)
[fn,pn] = uigetfile({'*.TIF; *.tiff; *.tif; *.TIFF; *.jpg; *.bmp; *.JPG; *.png'}, ...
            'Select an image', '~/');
I = double(imread(fullfile(pn,fn)));
ld = input('Enter the lag distance = '); % prompt for lag distance
fh = eval(['@' subfn]); % Function handles

%% precalculations
wind = [7 7];
center = (wind+1)/2; % Finds the central pixel of moving window
EWlength = (wind(2)+1)/2;
h = EWlength - ld; % Number of lags

%% calculations
I2 = nlfilter(I, wind, fh);
imshow(I2); % Texture Layer Image
imwrite(I2,'result_mat.tif');

% Zero Degree Variogram
function [gamma] = ewvar(I)
    EW = I(center(1),center(2):end); % Determines the values from central pixel to margin of window
    gamma = 1/(2 * h) * sum((EW(1:ld:end-1) - EW(2:ld:end)).^2);
end
end

请注意,通过这样做,您可以交换性能以获得清晰的代码和耦合(在函数dirvar和嵌套函数ewvar之间)。但是,由于我没有对您的代码进行概要分析(您应该使用自己的输入自行完成),您可以找到代码的哪一行消耗最多的时间。

对于批处理,我还建议省略任何inputimshowimwriteuigetfile。这些是您通常从更高级别的函数/脚本调用的命令,即使您希望它们保持不变,也会强制您输入这些输入。因此,不是代码,而是为它们生成的每个变量(/ process)为您的函数生成一个参数(/返回值)。这样,即使您无法加速代码,也可以在周末运行MATLAB来处理所有内容(无需手动输入所有这些值)。

答案 2 :(得分:1)

首先,我强烈建议您遵循@Egon的建议:编写一个单独的函数来收集文件列表(来自FEX的优秀UIPICKFILES是您的朋友),然后运行您的过滤每个图像的循环代码。请注意,您应该在过滤代码中保持对imwrite的调用:如果分析在图像48崩溃(例如由于电源故障),您不希望丢失以前的所有工作。

以批处理模式运行有两个很大的优点:(1)您可以开始运行代码并回家进行周末,(2)您可以使用PARFOR轻松地并行化这个外部循环。但是,由于只有双核机器,您不太可能从并行化中获得任何显着的改进 - 您的操作系统有时也希望运行内容,而并行化的开销可能不仅仅是运行两个工作者的收益。此外,2.5GB的RAM严重限制。

至于您的具体代码:根据我使用IM2COL的经验,通常比NLFILTER更快。 im2col会从您的图片中创建一个nElementsInMask-by-nMasks数组,以便您可以在一次操作中应用过滤。使用7x7窗口,im2col的输出将为3000 * 2500 * 49字节,接近400MB。因此,它应该工作。所有你需要做的就是重写ewvar,以便它可以在49x1像素数组上运行,这些像素组成了你的掩码像素,如果我正确理解你的代码,这将需要一些索引杂耍。