【问题标题】:Efficiently calculate optical flow parameters - MATLAB高效计算光流参数 - MATLAB
【发布时间】:2017-01-09 17:53:27
【问题描述】:

我正在实现来自Horn & Schunck paper 的光流偏导方程。然而,即使是相对较小的图像 (320x568),也需要非常长的时间(约 30-40 秒)才能完成。我认为这是由于 320 x 568 = 181760 循环迭代造成的,但我想不出更有效的方法来做到这一点(缺少 MEX 文件)。

有没有办法把它变成更高效的 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

【问题讨论】:

  • 计算机视觉系统工具箱中实现了几种光流算法。见opticalFlowHSopticalFlowLKopticalFlowFarneback

标签: performance matlab image-processing computer-vision vectorization


【解决方案1】:

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)

这种矢量化实现的好处是:

  • 内存效率:不再有沿第三维的串联会导致内存开销。同样,在性能方面,这将是一个好处,因为我们不需要索引到这样的重数组

  • 循环代码内部的迭代微分被替换为diff的微分,所以这应该是另一个改进。

  • 那些昂贵的平均计算被非常快速的卷积计算所取代,这应该是主要的改进部分。

【讨论】:

  • @marcman 我使用的img1img2 是您代码中的填充版本。所以,这应该照顾边缘,这就是为什么我需要在最后进行切片和重塑。最后查看所有这些和一些 cmets 上的编辑代码。
  • 有道理。感谢您的详细解释!
  • @marcman 啊,如果您不介意的话,也想知道在您的实际输入案例中使用矢量化方法的运行时以及与原始循环的一些比较:)
  • @marcman 不错!!与原来的 30-40 秒相比还不错! :)
  • @rayryeng 谢谢雷!意味着很多来自图像处理。大师! :)
【解决方案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,它添加了简单的时间模糊。

【讨论】:

  • 我认为我应该为这个算法添加至少 2 个注释: 1) 只需将 gg 过滤器更改为 [1,2,1] 即可轻松适应整数运算; 2)边界元素的权重将略低于应有的权重(考虑到它们是单边差异)。这实际上是光流应用程序所需要的,但它可能会对其他应用程序产生不利影响,例如更通用的数值求解器。所以要小心
猜你喜欢
  • 1970-01-01
  • 2014-11-10
  • 1970-01-01
  • 1970-01-01
  • 2013-12-17
  • 2014-07-07
  • 1970-01-01
  • 1970-01-01
  • 2021-01-15
相关资源
最近更新 更多