4

我在光流上實現了Horn & Schunck paper的偏導數方程。但是,即使是相對較小的圖像(320x568),也需要很長的時間(約30-40秒)才能完成。我認爲這是由於320 x 568 = 181760循環迭代造成的,但我找不出一個更有效的方法來做到這一點(缺少MEX文件)。高效地計算光流參數 - MATLAB

有什麼方法可以將它變成更高效的MATLAB操作(也許是卷積)?我可以弄清楚如何做到這一點,作爲It的卷積,但不是IxIy。我也考慮過矩陣移位,但只要我能弄明白,那也只適用於It

有沒有其他人遇到這個問題,並找到了解決辦法?

我的代碼如下:

function [Ix, Iy, It] = getFlowParams(img1, img2) 

% Make sure image dimensions match up 
assert(size(img1, 1) == size(img2, 1) && size(img1, 2) == size(img2, 2), ... 
    'Images must be the same size'); 
assert(size(img1, 3) == 1, 'Images must be grayscale'); 

% Dimensions of original image 
[rows, cols] = size(img1); 
Ix = zeros(numel(img1), 1); 
Iy = zeros(numel(img1), 1); 
It = zeros(numel(img1), 1); 

% Pad images to handle edge cases 
img1 = padarray(img1, [1,1], 'post'); 
img2 = padarray(img2, [1,1], 'post'); 

% Concatenate i-th image with i-th + 1 image 
imgs = cat(3, img1, img2); 

% Calculate energy for each pixel 
for i = 1 : rows 
    for j = 1 : cols 
     cube = imgs(i:i+1, j:j+1, :); 
     Ix(sub2ind([rows, cols], i, j)) = mean(mean(cube(:, 2, :) - cube(:, 1, :))); 
     Iy(sub2ind([rows, cols], i, j)) = mean(mean(cube(2, :, :) - cube(1, :, :))); 
     It(sub2ind([rows, cols], i, j)) = mean(mean(cube(:, :, 2) - cube(:, :, 1))); 
    end 
end 
+0

在計算機視覺系統工具箱中實現了幾種光流算法。參見'opticalFlowHS','opticalFlowLK','opticalFlowFarneback'。 – Dima

回答

3

2D convolution是去這裏的還預測的問題,以取代那些沉重的mean/average計算的方式。此外,這些迭代差異可以由MATLAB's diff取代。因此,結合這一切,一個矢量化的實現是 -

%// Pad images to handle edge cases 
img1 = padarray(img1, [1,1], 'post'); 
img2 = padarray(img2, [1,1], 'post'); 

%// Store size parameters for later usage 
[m,n] = size(img1); 

%// Differentiation along dim-2 on input imgs for Ix calculations 
df1 = diff(img1,[],2) 
df2 = diff(img2,[],2) 

%// 2D Convolution to simulate average calculations & reshape to col vector 
Ixvals = (conv2(df1,ones(2,1),'same') + conv2(df2,ones(2,1),'same'))./4; 
Ixout = reshape(Ixvals(1:m-1,:),[],1); 

%// Differentiation along dim-1 on input imgs for Iy calculations 
df1 = diff(img1,[],1) 
df2 = diff(img2,[],1) 

%// 2D Convolution to simulate average calculations & reshape to col vector 
Iyvals = (conv2(df1,ones(1,2),'same') + conv2(df2,ones(1,2),'same'))./4 
Iyout = reshape(Iyvals(:,1:n-1),[],1); 

%// It just needs elementwise diffentiation between input imgs. 
%// 2D convolution to simulate mean calculations & reshape to col vector 
Itvals = conv2(img2-img1,ones(2,2),'same')./4 
Itout = reshape(Itvals(1:m-1,1:n-1),[],1) 

好處與這樣一個量化的實現將是:

  • 存儲效率:沿第三維會招致內存開銷沒有更多的級聯。同樣,表現明智,這將是一個好處,因爲我們不需要索引重型陣列

  • loopy代碼內部的迭代微分被diff微分代替,所以這應該是另一個改進。

  • 這些昂貴的平均計算被非常快速的卷積計算所取代,這應該是主要的改進部分。

+1

@marcman我使用的'img1'和'img2'是你代碼中的填充版本。所以,這應該照顧到邊緣,正因爲如此,我最終需要切片和重塑。查看所有這些編輯後的代碼和最後的一些評論。 – Divakar

+0

這是有道理的。感謝您的詳細解釋! – marcman

+0

@marcman嗯如果你不介意,想知道在實際輸入情況下的矢量化方法的運行時間和一些與原始的loopy的比較:) – Divakar

2

更快的方法,具有改善的結果(在我觀察到的情況下)如下:

function [Ix, Iy, It] = getFlowParams(imNew,imPrev) 

gg = [0.2163, 0.5674, 0.2163]; 
f = imNew + imPrev; 
Ix = f(:,[2:end end]) - f(:,[1 1:(end-1)]); 
Ix = conv2(Ix,gg','same'); 

Iy = f([2:end end],:) - f([1 1:(end-1)],:); 
Iy = conv2(Iy,gg ,'same'); 

It = 2*conv2(gg,gg,imNew - imPrev,'same'); 

此處理邊界情況典雅。

我將此作爲我的optical flow toolbox的一部分,您可以在其中實時查看H & S,Lucas Kanade等。在工具箱中,該函數被稱爲grad3D.m。您可能還想在同一個工具箱中查看grad3Drec.m,這會增加簡單的時間模糊。

+0

我認爲我應該爲這個算法添加至少2個註釋:1)通過簡單地將gg過濾器更改爲[1,2,1];它可以很容易地適用於整數運算; 2)邊界要素的權重應稍小於它們(考慮到它們是單側差異)。這對於光流應用來說實際上是需要的,但是它可能會影響其他應用,例如更一般的數值解算器。所以請注意 –