为每次迭代更改大小的变量预分配内存(长文本文件)

时间:2019-06-23 12:00:11

标签: arrays image matlab memory-management pre-allocation

我写了一个代码,将图像转换为文本文件以进行光刻。图像为高分辨率(26.5k x 26.5k),文本文件超过2MB。我的问题是代码需要花费很长时间才能工作,并且我怀疑它与内存碎片有关(我不是经验丰富的程序员,尤其是刚开始使用MATLAB。)它滞后于两个地方:在您必须选择要使用的特定图像之前以及在图像处理之后。

在处理部分,我从MATLAB得到以下注释:

  

所指示的变量或数组的大小似乎在每次循环迭代中都在变化。通常,出现此消息是因为数组通过分配或串联而增长。...

但是还有一部分:

  

如果满足以下任一条件,则如调整代码分析器消息指示符和消息中所述,抑制该消息可能是适当的:   循环代码包含一个条件块,数组在其中生长。 (在这种情况下,仅在循环找到此类条件时才增长数组是合理的。)   对于循环中的每次迭代,串联的长度都会变化(例如长度可变的字符向量)。进入循环之前,无法计算数组的总大小。

输出文本文件在很大程度上取决于所提供的图像和其中的黑白像素数量。

所以我想知道是否有任何方法可以提高代码的性能?

在选择图像文件之前,几乎没有任何计算,并且进行的计算非常简单,所以我不知道为什么它这么慢。

对于第一个功能,在调用第二个打开图像文件的功能之前:

function print_contacts(pixl, size, xRd, yRd, zRd, xRu, yRu, zRu)

meas_L=3960.05; % the lateral and veritcal measured distance e.g. 4900.5 between large pluses, 3960.05 between dots in corners
%%
conv=(size*1000)/pixl;%0.267;%0.4215; % pixel to microns
siz=pixl*conv;
xLd=0.0;
yLd=0.0;
zLd=0.0;

%%
delta_x_H=xLd-xRd;
delta_y_H=yLd-yRd;
delta_z_V=-(zLd-zRd);

delta_x_V=xRu-xRd;
delta_y_V=yRu-yRd;
delta_z_H=-(zRu-zRd);

%% find x-y angle of rotation teta (if teta is positive then rotation is clockwise)

if yRd > 0
    teta_xy=atand(-xRd/yRd)-90;
else
    teta_xy=atand(-xRd/yRd)+90;
end

%% find x-z angle of rotation teta (if teta is positive then rotation is clockwise)

teta_xz=atand(delta_z_H/delta_x_H);

%% find y-z angle of rotation teta (if teta is positive then rotation is clockwise)

teta_yz=atand(delta_z_V/delta_y_V);

%%
del_z_H=delta_z_H/meas_L*conv*pixl;
del_z_V=delta_z_V/meas_L*conv*pixl;

vec_xz=linspace(0,del_z_H,pixl);
vec_yz=linspace(0,del_z_V,pixl);
[X,Y] = meshgrid(vec_yz,vec_xz);
Z1=(X + Y);
shift=Z1(pixl/2,pixl/2);
valZ=round((Z1-shift),2);
%surf(valZ);
con=[conv];
R = [cosd(teta_xy) -sind(teta_xy); sind(teta_xy) cosd(teta_xy)];

PPM.Y=con;
PPM.X=con;

regionpropsApply(PPM, valZ, siz, R, conv)

之后是功能regionpropsApply,该功能使您可以选择图像文件并将其片段化为单个图像,每个图像都将由第三个也是最后一个功能处理为文本文件,其中收集长字符串的命令,该字符串将进入文本文件:

str2File = [str2File;cmdJump;cmdZ;cmdMov];

cmdJumpcmdZcmdMov是在此特定迭代中创建的命令。在进行迭代之前,我已经知道所需的迭代次数。每次迭代将始终包含这3个命令。每个图像(从原始图像分割)都将被分别处理。我应该何时分配内存以及如何分配内存?

当前,执行代码需要40分钟以上的时间,并且考虑到输出文件只有2MB的事实,我真的希望它不会花费几分钟。

1 个答案:

答案 0 :(得分:4)

在您的第一段代码中,我认为这是最慢的部分:

vec_xz=linspace(0,del_z_H,pixl);
vec_yz=linspace(0,del_z_V,pixl);
[X,Y] = meshgrid(vec_yz,vec_xz);
Z1=(X + Y);
shift=Z1(pixl/2,pixl/2);
valZ=round((Z1-shift),2);

由于您要处理的图像非常大,我想这里的pixl很大。您生成图像大小的4个矩阵。但是其中3个包含中间数据,这些数据仅在上面的代码中使用。不要将每个计算结果分配给一个新变量,而是重新使用变量,以避免使用过多的内存。例如,使用x = func(x)调用函数可以使该函数就地工作,修改x而不是复制它。现在,您不再需要Z1占用内存。

图像XY完全多余。从R2016b开始,您可以简单地添加两个正交向量,并且在十年之前,我们已经针对该类型的操作使用了bsxfun。这样不仅可以节省内存,还可以通过更好地使用缓存来加快计算速度。

因此,您可以通过以下方法完成上述操作:

vec_xz = linspace(0, del_z_H, pixl);
vec_yz = linspace(0, del_z_V, pixl);
valZ = vec_xz + vec_yz.';
shift = valZ(pixl/2, pixl/2);
valZ = round(valZ-shift, 2);

如果您使用的是旧版本的MATLAB,则将第三行替换为:

valZ = bsxfun(@plus, vec_xz, vec_yz.');

最后,我们可以通过更改操作顺序来减少操作次数:我们可以从两个向量的每个向量中减去一部分,而不是从每个像素中减去shift

vec_xz = linspace(0, del_z_H, pixl);
vec_xz = vec_xz - vec_xz(pixl/2);
vec_yz = linspace(0, del_z_V, pixl);
vec_yz = vec_yz - vec_yz(pixl/2);
valZ = vec_xz + vec_yz.';
valZ = round(valZ, 2);

对于问题的第二部分,我不知道还有什么其他内容,以及您对构建的字符串的处理方式,但是如果您要做的是构建此长字符串,然后将其写入文件,您相反,您应该将其写入文件:

file = fopen('name.txt', 'wt');
for ...
   fwrite(file, [cmdJump;cmdZ;cmdMov];
end
fclose(file);

如果需要在编写之前以某种方式修改字符串,则可以将它们存储在单元格数组中,因为您知道循环的迭代次数,因此可以预先分配它们:

str2File = cell(N,1);
for ii=1:N
   str2File{ii} = [cmdJump;cmdZ;cmdMov];
end
相关问题