Предварительное выделение памяти для переменной, которая изменяет размер на каждой итерации (длинный текстовый файл) - PullRequest
1 голос
/ 23 июня 2019

Я написал код, который переводит изображение в текстовый файл для литографии. Изображения имеют высокое разрешение (26,5 x 26,5 КБ), а текстовые файлы имеют размер более 2 МБ. Моя проблема в том, что для работы кода требуется очень много времени, и я подозреваю, что он как-то связан с фрагментацией памяти (я не опытный программист и специально только начал работать с 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];

Где cmdJump, cmdZ и cmdMov - команды, созданные в этой конкретной итерации. Перед итерацией я уже знаю количество необходимых итераций. Каждая итерация будет всегда включать эти 3 команды. Каждое изображение (фрагментированное от исходного) обрабатывается отдельно. Когда и как распределять память?

В настоящее время выполнение кода занимает более 40 минут, и, учитывая, что размер выходного файла составляет всего 2 МБ, я действительно хотел бы, чтобы это заняло менее нескольких минут.

1 Ответ

4 голосов
/ 23 июня 2019

В вашем первом фрагменте кода я предполагаю, что это медленная часть:

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, чтобы занять память.

Изображения X и Y совершенно излишни.Начиная с R2016b, вы можете просто добавить два ортогональных вектора, и за 10 лет до этого у нас было 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, затем замените 3-ю строку на:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...