2017-02-09 15 views
2

Итак, мне нужно оцифровать некоторые из циклов в одну строку. Я понимаю, как векторизовать один и два for-loops, но я действительно стараюсь сделать больше, чем это. По существу, я вычисляю матрицу «размытие» М2 размера (п-2) х (м-2) оригинальной матрица М размера NxM, где s = размер (М):Matlab: Vectorizing 4 вложенных для циклов

for x = 0:1 
    for y = 0:1 
     m = zeros(1, 9); 
     k = 1; 
     for i = 1:(s(1) - 1) 
      for j = 1:(s(2) - 1) 
       m(1, k) = M(i+x,j+y); 
       k = k+1; 
      end 
     end 
    M2(x+1,y+1) = mean(m); 
    end 
end 

Это ближайший я получил:

for x=0:1 
    for y=0:1 
     M2(x+1, y+1) = mean(mean(M((x+1):(3+x),(y+1):(3+y)))) 
    end 
end 

чтобы получить ближе к решению одной строки, то кажется, что там должно быть каким-то «общение», где я назначаю две переменные (х, у) к индексу над M2 и индекс над M; Я просто не понимаю, как это можно сделать в противном случае, но я уверен, что есть решение.

ответ

3

Есть ли причина, по которой вы не используете функцию свертки MATLAB, чтобы помочь вам в этом? Вы выполняете размытие с 3 x 3 усредняющим ядром с перекрывающимися окрестностями. Это именно то, что делает свертка. Вы можете выполнить это с помощью conv2:

M2 = conv2(M, ones(3)/9, 'valid'); 

'valid' флаг гарантирует, что вы возвращаете size(M) - 2 матрицу в обоих направлениях, как вы просили.


В вашем коде вы жестко закодировали это для матрицы 4 x 4. Для того, чтобы перепроверить, чтобы увидеть, если у нас есть правильные результаты, давайте генерировать случайные 4 х 4 матрица:

rng(123); 
M = rand(4, 4); 
s = size(M); 

Если мы запустим это с вашим кодом, мы получаем:

>> M2 

M2 = 

    0.5054 0.4707 
    0.5130 0.5276 

Делать это с conv2:

>> M2 = conv2(M, ones(3)/9, 'valid') 

M2 = 

    0.5054 0.4707 
    0.5130 0.5276 

Однако, если вы хотите сделать это из первых принципов, перекрывание пикселя ржать bourhoods очень трудно избежать с помощью петель. Два подхода for, которые у вас есть, достаточно хороши, и он решает проблему соответствующим образом. Я бы сделал размер ввода вместо жесткого кодирования. Таким образом, написать функцию, которая делает что-то вроде этого:

function M2 = blur_fp(M) 
s = size(M); 
M2 = zeros(s(1) - 2, s(2) - 2); 
for ii = 2 : s(1) - 1 
    for jj = 2 : s(2) - 1 
     p = M(ii - 1 : ii + 1, jj - 1 : jj + 1); 
     M2(ii - 1, jj - 1) = mean(p(:)); 
    end 
end 

Первая строка кода определяет функцию, которую мы будем называть blur_fp. Следующие пары строк кода определяют размер входной матрицы, а также инициализацию пустой матрицы для хранения выходных данных. Затем мы пробиваем каждое местоположение пикселя в матрице, которое возможно, если ядро ​​не выходит за пределы границ изображения, мы захватываем 3 x 3 окрестности с каждым местоположением пикселя, выступающим в качестве центра, тогда мы получаем unroll матрица в один вектор столбца, найдите среднее значение и сохраните его в соответствующем выводе. Для небольших ядер и относительно больших матриц это должно выполняться нормально.


Для того, чтобы это немного дальше, вы можете использовать пользовательский Divakar «s im2col_sliding функция, которая принимает пересекающиеся окрестности и разворачивает их в столбцы. Поэтому каждый столбец представляет собой окрестность, которая затем может размывать вход, используя умножение векторной матрицы.Вы бы затем использовать reshape, чтобы изменить результат обратно в матрицу:

T = im2col_sliding(M, [3 3]); 
V = ones(1, 9)/9; 
s = size(M); 
M2 = reshape(V * T, s(1) - 2, s(2) - 2); 

К сожалению, это не может быть сделано в одной строке, если не использовать встроенные функции. Я не уверен, каково ваше намерение, но, надеюсь, диапазон подходов, которые вы здесь видели, дал вам некоторое представление о том, как это сделать эффективно. Кстати, использование петель для малых матриц (т. Е. 4 х 4) может быть лучше по эффективности. Вы начнете замечать изменения производительности при увеличении размера ввода ... опять же, я бы сказал, что использование циклов конкурентоспособно по сравнению с R2015b, когда JIT значительно улучшилось.

+0

Спасибо! Я думаю, что намерение упражнения состояло в том, чтобы сделать это, используя только «первые принципы», и предполагается, что мы не знаем этих функций, о которых вы говорите. Но все и все, я думаю, это полезно для моего фактического знания о Matlab. –

+0

@DylanBrown ОК, в этом случае то, что у вас есть с двумя циклами 'for', достаточно для первых принципов. Вам нужна дополнительная помощь? Если нет, тогда мне бы это понравилось, если бы вы могли принять мой ответ. Это позволит сообществу понять, что вам больше не нужна помощь. Удачи! – rayryeng

+0

@DylanBrown Я также отредактирую свое сообщение, чтобы использовать два цикла 'for' без жесткого кодирования размера ввода. Я сделаю его динамичным. – rayryeng

 Смежные вопросы

  • Нет связанных вопросов^_^