Я пытаюсь изучить MATLAB, и одной из первых проблем, с которыми я столкнулся, было угадывание фона из последовательности изображений со статической камерой и движущимися объектами. Для начала я просто хочу сделать среднее или медиану для пикселей со временем, поэтому это всего лишь одна функция, которую я хотел бы применить к одной из строк четырехмерного массива .
Я загрузил мои изображения RGB в 4-мерном массиве со следующими размерами:
uint8 [ num_images, width, height, RGB ]
Вот функция, которую я написал, которая включает 4 вложенных цикла. Я использую preallocation , но все же, он очень медленный. Я полагаю, что в C ++ эта функция может работать как минимум в 10–20 раз быстрее, и я думаю, что в CUDA она может выполняться в реальном времени. В MATLAB это занимает около 20 секунд с 4 вложенными циклами. Мой стек составляет 100 изображений с размерами 640x480x3.
function background = calc_background(stack)
tic;
si = size(stack,1);
sy = size(stack,2);
sx = size(stack,3);
sc = size(stack,4);
background = zeros(sy,sx,sc);
A = zeros(si,1);
for x = 1:sx
for y = 1:sy
for c = 1:sc
for i = 1:si
A(i) = stack(i,y,x,c);
end
background(y,x,c) = median(A);
end
end
end
background = uint8(background);
disp(toc);
end
Не могли бы вы сказать, как сделать этот код намного быстрее? Я попытался поэкспериментировать с каким-либо способом получения данных непосредственно из массива, используя только индексы, и это кажется НАМНОГО быстрее. Он завершается за 3 секунды против 20 секунд , так что это разница в производительности в 7 раз, просто написав меньшую функцию.
function background = calc_background2(stack)
tic;
% bad code, confusing
% background = uint8(squeeze(median(stack(:, 1:size(stack,2), 1:size(stack,3), 1:3 ))));
% good code (credits: Laurent)
background=uint8((squeeze(median(stack,1)));
disp(toc);
end
Так что теперь я не понимаю , если MATLAB может быть таким быстрым, тогда почему версия с вложенным циклом такая медленная? Я не делаю динамического изменения размера, и MATLAB должен запускать те же 4 вложенных цикла внутри .
Почему это происходит?
Есть ли способ ускорить выполнение вложенных циклов, как это было бы естественно в C ++?
Или я должен привыкнуть к идее программирования MATLAB в этом сумасшедшем однострочном способе получения оптимальной производительности?
Обновление
Спасибо за все великолепные ответы, теперь я понимаю намного больше. Мой исходный код с stack(:, 1:size(stack,2), 1:size(stack,3), 1:3 ))
не имеет никакого смысла, он точно такой же, как stack
, мне просто повезло с медианной опцией по умолчанию, использующей 1-е измерение для своего рабочего диапазона.
Я думаю, что лучше спросить, как написать эффективный вопрос в другом вопросе, поэтому я задал его здесь:
Как писать векторизованные функции в MATLAB