Re: [討論] for迴圈 如何改成矩陣運算

作者: celestialgod (天)   2015-10-08 13:56:57
花一點記憶體可以加速六倍左右吧
Img = randn(1e3, 1e3);
[h, v] = size(Img);
F = rand(20, 10);
[F_h, F_v] = size(F);
tic
fI = zeros(h-F_h+1, v-F_v+1);
for i=1:(h-F_h+1)
for j=1:(v-F_v+1)
R = Img(i:i+F_h-1, j:j+F_v-1);
fI(i,j) = sum(sum(R .* F));
end
end
toc
% Elapsed time is 5.834513 seconds.
as_vector = @(x) x(:);
tic
index_1 = as_vector(repmat(1:F_h, h-F_h+1, 1)' + repmat(0:(h-F_h), F_h, 1));
expand_F = repmat(F, size(index_1,1) / F_h, 1);
fI2 = zeros(h-F_h+1, v-F_v+1);
for i = 1:(v-F_v+1)
fI2(:, i) = sum(reshape(sum(Img(index_1, i:i+F_v-1) .* expand_F, 2), ...
F_h, []))';
end
toc
% Elapsed time is 0.979537 seconds.
tic
index_2 = as_vector(repmat(1:F_v, v-F_v+1, 1)' + repmat(0:(v-F_v), F_v, 1));
expand_F = repmat(F, 1, size(index_2,1) / F_v);
fI3 = zeros(h-F_h+1, v-F_v+1);
for i = 1:(h-F_h+1)
fI3(i, :) = sum(reshape(sum(Img(i:i+F_h-1, index_2) .* expand_F), ...
F_v, []));
end
toc
% Elapsed time is 0.947438 seconds.
all(all(abs(fI - fI2) < 1e-4)) % true
all(all(abs(fI - fI3) < 1e-4)) % true
如果空間全部展開會變得很慢,不建議
展開一個空間讓迴圈減少一層,是可以快滿多的
至於展開比較短還是比較長的部分,我這裡測試差不多
一般而言,迴圈比較少次會比較快
這裡只差10次,所以感覺不出來
原PO可以多試試看
另外,根據我的測試,F的大小影響速度非常大
F越大,兩層迴圈跟一層迴圈的差異越小
我推測是複製的時間會隨著F的大小而增加較多
PS: blockproc在這裡很慢,不建議用
blockproc:
tic
index_2 = as_vector(repmat(1:F_v, v-F_v+1, 1)' + repmat(0:(v-F_v), F_v, 1));
fun = @(block_struct) sum(sum(block_struct.data .* F));
fI4 = zeros(h-F_h+1, v-F_v+1);
for i = 1:(h-F_h+1)
fI4(i, :) = blockproc(Img(i:i+F_h-1, index_2),[F_h, F_v],fun);
end
toc
% Elapsed time is 129.542762 seconds.
all(all(abs(fI - fI4) < 1e-4)) % true
※ 引述《Portentera (SupP)》之銘言:
: 這是一個影像濾波的迴圈
: Img is input image. (h, v) is image isze.
: F is filter matrix. (F_h, F_v) is filter size.
: fI is filtering image.
: for i=1:h
: for j=1:v
: R = Img( i:i+F_h, j:j+F_v );
: fI(i,j) = sum(sum(R .* F));
: end
: end
: 剛開始學習用Matlab,只會使用for迴圈解決問題;
: 想學習如何改寫成矩陣運算,感謝大大們解惑!
作者: Portentera (SupP)   2015-10-08 15:53:00
感謝c大的分析,我再試試看。有收獲會上來留言。

Links booklink

Contact Us: admin [ a t ] ucptt.com