Algorithm Lukas-Kanade step的高效matlab实现
我在一个视频处理课程中得到了一个作业——实现Lucas Kanade算法。因为我们必须在金字塔模型中这样做,我首先为2个输入图像中的每一个构建一个金字塔,然后为每个级别执行一些LK迭代。在每个步骤(迭代)中,运行以下代码(注意:图像是零填充的,因此我可以轻松处理图像边缘): 从数学上讲,我所做的是计算每个像素的(I,j)以下光流: 正如您所见,在代码中,我为每个像素计算这个值,这需要相当长的时间(在远程连接到我的大学服务器时,2幅图像的整个处理过程——包括构建3层金字塔和3个LK步骤,就像上面每个层的步骤一样——大约需要25秒(!)Algorithm Lukas-Kanade step的高效matlab实现,algorithm,matlab,image-processing,video-processing,opticalflow,Algorithm,Matlab,Image Processing,Video Processing,Opticalflow,我在一个视频处理课程中得到了一个作业——实现Lucas Kanade算法。因为我们必须在金字塔模型中这样做,我首先为2个输入图像中的每一个构建一个金字塔,然后为每个级别执行一些LK迭代。在每个步骤(迭代)中,运行以下代码(注意:图像是零填充的,因此我可以轻松处理图像边缘): 从数学上讲,我所做的是计算每个像素的(I,j)以下光流: 正如您所见,在代码中,我为每个像素计算这个值,这需要相当长的时间(在远程连接到我的大学服务器时,2幅图像的整个处理过程——包括构建3层金字塔和3个LK步骤,就像上面
我的问题:有没有一种方法可以在没有嵌套for循环的情况下计算这个LK步骤?它必须更有效,因为分配的下一步是使用此算法稳定短视频。。谢谢。我在我的系统上运行了你的代码并进行了评测。这是我得到的 正如您所看到的,反转矩阵(pinv)占用了大部分时间。我想你可以尝试将你的代码矢量化,但我不知道怎么做。但是我知道一个提高计算时间的技巧。您必须利用矩阵A的最小方差。也就是说,仅当A的最小方差大于某个阈值时,才计算逆矩阵。这将提高速度,因为您不会反转所有像素的矩阵 您可以通过将代码修改为如下所示的代码来实现这一点
function [du,dv]= LucasKanadeStep(I1,I2,WindowSize)
It = double(I2-I1);
[Ix, Iy] = imgradientxy(I2);
Ixx = imfilter(Ix.*Ix, ones(5));
Iyy = imfilter(Iy.*Iy, ones(5));
Ixy = imfilter(Ix.*Iy, ones(5));
Ixt = imfilter(Ix.*It, ones(5));
Iyt = imfilter(Iy.*It, ones(5));
half_win = floor(WindowSize/2);
du = zeros(size(It));
dv = zeros(size(It));
A = zeros(2);
B = zeros(2,1);
%iterate only on the relevant parts of the images
for i = 1+half_win : size(It,1)-half_win
for j = 1+half_win : size(It,2)-half_win
A(1,1) = Ixx(i,j);
A(2,2) = Iyy(i,j);
A(1,2) = Ixy(i,j);
A(2,1) = Ixy(i,j);
B(1,1) = -Ixt(i,j);
B(2,1) = -Iyt(i,j);
% +++++++++++++++++++++++++++++++++++++++++++++++++++
% Code I added , threshold better be outside the loop.
lambda = eig(A);
threshold = 0.2
if (min(lambda)> threshold)
U = A\B;
du(i,j) = U(1);
dv(i,j) = U(2);
end
% end of addendum
% +++++++++++++++++++++++++++++++++++++++++++++++++++
% U = pinv(A)*B;
% du(i,j) = U(1);
% dv(i,j) = U(2);
end
end
end
我已将阈值设置为0.2。你可以尝试一下。通过使用特征值技巧,我能够得到37秒到10秒的计算时间(如下所示)。使用eigen,pinv几乎不像以前那样占用时间
希望这有帮助。祝你好运:)我在我的系统上运行了你的代码并进行了评测。这是我得到的 正如您所看到的,反转矩阵(pinv)占用了大部分时间。我想你可以尝试将你的代码矢量化,但我不知道怎么做。但是我知道一个提高计算时间的技巧。您必须利用矩阵A的最小方差。也就是说,仅当A的最小方差大于某个阈值时,才计算逆矩阵。这将提高速度,因为您不会反转所有像素的矩阵 您可以通过将代码修改为如下所示的代码来实现这一点
function [du,dv]= LucasKanadeStep(I1,I2,WindowSize)
It = double(I2-I1);
[Ix, Iy] = imgradientxy(I2);
Ixx = imfilter(Ix.*Ix, ones(5));
Iyy = imfilter(Iy.*Iy, ones(5));
Ixy = imfilter(Ix.*Iy, ones(5));
Ixt = imfilter(Ix.*It, ones(5));
Iyt = imfilter(Iy.*It, ones(5));
half_win = floor(WindowSize/2);
du = zeros(size(It));
dv = zeros(size(It));
A = zeros(2);
B = zeros(2,1);
%iterate only on the relevant parts of the images
for i = 1+half_win : size(It,1)-half_win
for j = 1+half_win : size(It,2)-half_win
A(1,1) = Ixx(i,j);
A(2,2) = Iyy(i,j);
A(1,2) = Ixy(i,j);
A(2,1) = Ixy(i,j);
B(1,1) = -Ixt(i,j);
B(2,1) = -Iyt(i,j);
% +++++++++++++++++++++++++++++++++++++++++++++++++++
% Code I added , threshold better be outside the loop.
lambda = eig(A);
threshold = 0.2
if (min(lambda)> threshold)
U = A\B;
du(i,j) = U(1);
dv(i,j) = U(2);
end
% end of addendum
% +++++++++++++++++++++++++++++++++++++++++++++++++++
% U = pinv(A)*B;
% du(i,j) = U(1);
% dv(i,j) = U(2);
end
end
end
我已将阈值设置为0.2。你可以尝试一下。通过使用特征值技巧,我能够得到37秒到10秒的计算时间(如下所示)。使用eigen,pinv几乎不像以前那样占用时间
希望这有帮助。祝你好运:)最终我找到了一个更有效的解决这个问题的方法。 它基于问题中所示的公式。最后三行是区别所在——我们得到了一个无循环的代码,它工作得更快。与循环版本的差异可以忽略不计(结果矩阵之间的绝对差异约为10^-18或更小,忽略填充区域) 代码如下:
function [du,dv]= LucasKanadeStep(I1,I2,WindowSize)
half_win = floor(WindowSize/2);
% pad frames with mirror reflections of itself
I1 = padarray(I1, [half_win half_win], 'symmetric');
I2 = padarray(I2, [half_win half_win], 'symmetric');
% create derivatives (time and space)
It = I2-I1;
[Ix, Iy] = imgradientxy(I2, 'prewitt');
% calculate dP = (du, dv) according to the formula
Ixx = imfilter(Ix.*Ix, ones(WindowSize));
Iyy = imfilter(Iy.*Iy, ones(WindowSize));
Ixy = imfilter(Ix.*Iy, ones(WindowSize));
Ixt = imfilter(Ix.*It, ones(WindowSize));
Iyt = imfilter(Iy.*It, ones(WindowSize));
% calculate the whole du,dv matrices AT ONCE!
invdet = (Ixx.*Iyy - Ixy.*Ixy).^-1;
du = invdet.*(-Iyy.*Ixt + Ixy.*Iyt);
dv = invdet.*(Ixy.*Ixt - Ixx.*Iyt);
end
最终我找到了一个更有效的解决方案。 它基于问题中所示的公式。最后三行是区别所在——我们得到了一个无循环的代码,它工作得更快。与循环版本的差异可以忽略不计(结果矩阵之间的绝对差异约为10^-18或更小,忽略填充区域) 代码如下:
function [du,dv]= LucasKanadeStep(I1,I2,WindowSize)
half_win = floor(WindowSize/2);
% pad frames with mirror reflections of itself
I1 = padarray(I1, [half_win half_win], 'symmetric');
I2 = padarray(I2, [half_win half_win], 'symmetric');
% create derivatives (time and space)
It = I2-I1;
[Ix, Iy] = imgradientxy(I2, 'prewitt');
% calculate dP = (du, dv) according to the formula
Ixx = imfilter(Ix.*Ix, ones(WindowSize));
Iyy = imfilter(Iy.*Iy, ones(WindowSize));
Ixy = imfilter(Ix.*Iy, ones(WindowSize));
Ixt = imfilter(Ix.*It, ones(WindowSize));
Iyt = imfilter(Iy.*It, ones(WindowSize));
% calculate the whole du,dv matrices AT ONCE!
invdet = (Ixx.*Iyy - Ixy.*Ixy).^-1;
du = invdet.*(-Iyy.*Ixt + Ixy.*Iyt);
dv = invdet.*(Ixy.*Ixt - Ixx.*Iyt);
end
你知道这个算法的慢步骤是什么吗?你试过了吗?从来没有听说过
评测,威尔:)你知道这个算法的慢步骤是什么吗?你试过了吗?从来没有听说过评测
,会做:)做得好!看起来结果差不多,现在需要4秒,而不是之前的25秒。。。谢谢!做得好!看起来结果差不多,现在需要4秒,而不是之前的25秒。。。谢谢!这太棒了:)这太棒了:)