Есть ли более эффективный способ выполнения нескольких вложенных циклов for в matlab?

#matlab #performance #for-loop #nested-loops

#matlab #Производительность #цикл for #вложенные циклы

Вопрос:

У меня есть небольшой логический массив ( A ) размером 256x256x256 с неизвестной формой единиц где-то в массиве. Также существует двойной массив меньшего размера ( se ) размером 13x13x13. В se в середине массива находится определенный куб логических циклов ( se ).

Мне нужно пробежаться по каждому логическому элементу в A и для каждого логического элемента в A меньшем массиве se необходимо добавить его в A . Имеется в виду расширение формы A на se .

Вот что у меня получилось на данный момент. Это работает, но имеет очень низкую производительность в отношении скорости.

У кого-нибудь есть предложения о том, как ускорить эту задачу кодирования?

 [p, q, r] = size(se);
[m, n, o] = size(A);

temp = zeros(m, n, o);
for i = 1:m
    for j = 1:n
        for k = 1:o
            if img_g(i, j, k) == 1
                for s = 1:p
                    for t = 1:q
                        for u = 1:r
                            if se(s, t, u) == 1
                                c = i   s;
                                d = j   t;
                                e = k   u;
                                temp(c, d, e) = 1;
                            end
                        end
                    end
                end
            end
        end
    end
end
B = temp;
  

Я очень благодарен за любую помощь и предложения, которые улучшают мои навыки программирования.

Комментарии:

1. Если это действительно простое трехмерное расширение, и у вас есть доступ к инструменту обработки изображений MATLAB , тогда взгляните на то, как расширять точки в 3D-пространстве, используя сферические структурирующие элементы для примера. Помимо этого, трехмерная свертка (см. convn ) также должна работать (с некоторыми последующими шагами).

2. Определенно есть один, путем применения операций над матрицами вместо этого. Теперь, какую операцию выполнить? зависит от того, что вы хотите сделать. К сожалению, я не смог понять, чего вы хотите достичь. Не могли бы вы объяснить это другими словами, пожалуйста?

3. Нет способа ускорить вложенные циклы без изменения реализации вашего кода. Я бы также посоветовал вам проверить imdilate() из документации Matlab, если это то, что вы пытаетесь сделать.

4. Я пытался избежать использования инструментария обработки изображений. Вот почему я делаю набор сам.

5. Можете ли вы привести пример A и se ? Достаточно ли этого для выполнения A = rand(255, 255, 255); A(20:40, 20:40, 20:40) = 1; ?

Ответ №1:

в зависимости от используемого вами процессора, вы можете, по крайней мере, использовать «parfor» для внешнего цикла (первый цикл). это позволяет выполнять параллельные вычисления и ускоряет вашу производительность за счет количества физических ядер, полученных вашим процессором.

Комментарии:

1. В общем, можно было бы рассмотреть предложение, но оно не будет работать с моей структурой кода и моими изменениями temp .

Ответ №2:

Я не уверен на 100%, что это делает то, о чем вы просите (поскольку я не совсем понимаю, что делает ваш код), но, возможно, методология даст некоторое вдохновение.

Я сгенерировал не «логический» A , а случайный, и я установил куб внутри равным 1. Аналогично для se . Я использую meshgrid для получения массивов, соответствующих индексам, и использую mask логическую индексацию. (возможно, мой mask — это то, для A чего у вас есть в первую очередь?)

 A = rand(255,255,255);
A(40:50, 23:33, 80:100) = 1;
mask = (A==1);

[I,J,K] = meshgrid(1:255);

se = rand(13,13,13);
se(4:6, 3:7, 2:8) = 1;
se_mask = (se==1);

[se_I, se_J, se_K] = meshgrid(1:13);
  

Здесь я предполагаю, что куб в A находится достаточно далеко от любого ребра (скажем, 13 пробелов), поэтому мы не получим c , d или e больше 255.

Я сгладил mask в вектор строк, чтобы find получить единый индекс ii , который мы можем использовать для ссылки на любую точку в A , тогда исходные i , j и k индексы находятся в I(ii) , J(ii) и K(ii) соответственно. Аналогично для se_I и т.д.

 temp = zeros(255, 255, 255);
for ii=find(mask(:).')
  for jj=find(se_mask(:).')
    c = I(ii)   se_I(jj);
    d = J(ii)   se_J(jj);
    e = K(ii)   se_K(jj);
    temp(c,d,e) = 1;
  end % for
end % for
  

Матрицы I , J , K se_I se_J и se_K являются обычными, поэтому, если их создание / хранение становится узким местом, вы можете написать функции для их замены. Матрица temp может быть очень разреженной в зависимости от размера ваших кубов единиц, поэтому вы могли бы рассмотреть возможность использования sparse .

Я не сравнивал тайминги с вашим решением.