一、简介
1 什么是光流
光流(optical flow)是空间运动物体在观察成像平面上的像素运动的瞬时速度。
光流法是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。
通常将二维图像平面特定坐标点上的灰度瞬时变化率定义为光流矢量。
一言以概之:所谓光流就是瞬时速率,在时间间隔很小(比如视频的连续前后两帧之间)时,也等同于目标点的位移。
2 光流的物理意义
一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。
当人的眼睛观察运动物体时,物体的景象在人眼的视网膜上形成一系列连续变化的图像,这一系列连续变化的信息不断“流过”视网膜(即图像平面),好像一种光的“流”,故称之为光流。光流表达了图像的变化,由于它包含了目标运动的信息,因此可被观察者用来确定目标的运动情况。
图(1)展示的便是三维空间内物体的运动在二维成像平面上的投影。得到的是一个描述位置变化的二维矢量,但在运动间隔极小的情况下,我们通常将其视为一个描述该点瞬时速度的二维矢量u=(u,v),称为光流矢量。
图(1) 三维运动在二维平面内的投影
3 光流场
在空间中,运动可以用运动场描述,而在一个图像平面上,物体的运动往往是通过图像序列中不同图像灰度分布的不同体现的,从而,空间中的运动场转移到图像上就表示为光流场(optical flow field)。
光流场是一个二维矢量场,它反映了图像上每一点灰度的变化趋势,可看成是带有灰度的像素点在图像平面上运动而产生的瞬时速度场。它包含的信息即是各像点的瞬时运动速度矢量信息。
研究光流场的目的就是为了从序列图像中近似计算不能直接得到的运动场。光流场在理想情况下,光流场对应于运动场。
图(2)三维空间的矢量场及其在二维平面内的投影
图(3)现实场景的可视化光流场
三言以概之:所谓光流场就是很多光流的集合。
当我们计算出了一幅图片中每个图像的光流,就能形成光流场。
构建光流场是试图重现现实世界中的运动场,用以运动分析。
3 光流法基本原理
3.1 基本假设条件
(1)亮度恒定不变。即同一目标在不同帧间运动时,其亮度不会发生改变。这是基本光流法的假定(所有光流法变种都必须满足),用于得到光流法基本方程;
(2)时间连续或运动是“小运动”。即时间的变化不会引起目标位置的剧烈变化,相邻帧之间位移要比较小。同样也是光流法不可或缺的假定。
3.2 基本约束方程
考虑一个像素I(x,y,t)在第一帧的光强度(其中t代表其所在的时间维度)。它移动了 (dx,dy)的距离到下一帧,用了dt时间。因为是同一个像素点,依据上文提到的第一个假设我们认为该像素在运动前后的光强度是不变的,即:
3.几种光流估计算法的简介
1) 基于梯度的方法
基于梯度的方法又称为微分法,它是利用时变图像灰度(或其滤波形式)的时空微分(即时空梯度函数)来计算像素的速度矢量。
由于计算简单和较好的结果,该方法得到了广泛应用和研究。典型的代表是Horn-Schunck算法与Lucas-Kanade(LK)算法。
Horn-Schunck算法在光流基本约束方程的基础上附加了全局平滑假设,假设在整个图像上光流的变化是光滑的,即物体运动矢量是平滑的或只是缓慢变化的。
基于此思想,大量的改进算法不断提出。Nagel采用有条件的平滑约束,即通过加权矩阵的控制对梯度进行不同平滑处理;Black和Anandan针对多运动的估计问题,提出了分段平滑的方法。
- 基于匹配的方法
基于匹配的光流计算方法包括基于特征和区域的两种。
基于特征的方法不断地对目标主要特征进行定位和跟踪,对目标大的运动和亮度变化具有鲁棒性。存在的问题是光流通常很稀疏,而且特征提取和精确匹配也十分困难。
基于区域的方法先对类似的区域进行定位,然后通过相似区域的位移计算光流。这种方法在视频编码中得到了广泛的应用。然而,它计算的光流仍不稠密。另外,这两种方法估计亚像素精度的光流也有困难,计算量很大。
3)基于能量的方法
基于能量的方法又称为基于频率的方法,在使用该类方法的过程中,要获得均匀流场的准确的速度估计,就必须对输入的图像进行时空滤波处理,即对时间和空间的整合,但是这样会降低光流的时间和空间分辨率。基于频率的方法往往会涉及大量的计算,另外,要进行可靠性评价也比较困难。
4)基于相位的方法
基于相位的方法是由Fleet和Jepson提出的,Fleet和Jepson最先提出将相位信息用于光流计算的思想。当我们计算光流的时候,相比亮度信息,图像的相位信息更加可靠,所以利用相位信息获得的光流场具有更好的鲁棒性。基于相位的光流算法的优点是:对图像序列的适用范围较宽,而且速度估计比较精确,但也存在着一些问题:第一,基于相位的模型有一定的合理性,但是有较高的时间复杂性;第二,基于相位的方法通过两帧图像就可以计算出光流,但如果要提高估计精度,就需要花费一定的时间;第三,基于相位的光流计算法对图像序列的时间混叠是比较敏感的。
5)神经动力学方法
神经动力学方法是利用神经网络建立的视觉运动感知的神经动力学模型,它是对生物视觉系统功能与结构比较直接的模拟。
尽管光流计算的神经动力学方法还很不成熟,然而对它的研究却具有极其深远的意义。随着生物视觉研究的不断深入,神经方法无疑会不断完善,也许光流计算乃至计算机视觉的根本出路就在于神经机制的引入。神经网络方法是光流技术的一个发展方向。
3.稠密光流与稀疏光流
除了根据原理的不同来区分光流法外,还可以根据所形成的光流场中二维矢量的疏密程度将光流法分为稠密光流与稀疏光流两种。
稠密光流
稠密光流是一种针对图像或指定的某一片区域进行逐点匹配的图像配准方法,它计算图像上所有的点的偏移量,从而形成一个稠密的光流场。通过这个稠密的光流场,可以进行像素级别的图像配准。
Horn-Schunck算法以及基于区域匹配的大多数光流法都属于稠密光流的范畴。
图(4) 基于区域匹配方法生成稠密光流场图例
由于光流矢量稠密,所以其配准后的效果也明显优于稀疏光流配准的效果。但是其副作用也是明显的,由于要计算每个点的偏移量,其计算量也明显较大,时效性较差。
二、源代码
function varargout = optical_flow(varargin)
% OPTICAL_FLOW M-file for optical_flow.fig
% OPTICAL_FLOW, by itself, creates a new OPTICAL_FLOW or raises the existing
% singleton*.
%
% H = OPTICAL_FLOW returns the handle to a new OPTICAL_FLOW or the handle to
% the existing singleton*.
%
% OPTICAL_FLOW('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in OPTICAL_FLOW.M with the given input arguments.
%
% OPTICAL_FLOW('Property','Value',...) creates a new OPTICAL_FLOW or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before optical_flow_OpeningFunction gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to optical_flow_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Copyright 2002-2003 The MathWorks, Inc.
% Edit the above text to modify the response to help optical_flow
% Last Modified by GUIDE v2.5 23-Jul-2012 15:10:21
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @optical_flow_OpeningFcn, ...
'gui_OutputFcn', @optical_flow_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before optical_flow is made visible.
function optical_flow_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to optical_flow (see VARARGIN)
% Choose default command line output for optical_flow
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% UIWAIT makes optical_flow wait for user response (see UIRESUME)
% uiwait(handles.figure1);
% --- Outputs from this function are returned to the command line.
function varargout = optical_flow_OutputFcn(hObject, eventdata, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
% --- Executes on button press in pushbutton_start.
function pushbutton_start_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton_start (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global FilePath1
global FilePath2
global version
if ( isequal(FilePath1,'No Picture') || isequal(FilePath2,'No Picture') )
errordlg('选择图片出错!','MATLAB error');
return
end
switch version
case { 0, 1, 2 }
optic_flow_brox(FilePath1, FilePath2);
case 3
Horn_WJY(FilePath2, FilePath1);
case 4
Lucas_Kanade(FilePath2, FilePath1);
otherwise
errordlg('选择算法出错!','MATLAB error');
end
% --- Executes on button press in pushbutton_pic1.
function pushbutton_pic1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton_pic1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global FilePath1
[FileName,PathName] = uigetfile({'*.jpg';'*.bmp'},'Select the picture');
if ~isequal(FileName,0)
FilePath1 = fullfile(PathName,FileName);
set(handles.edit_lj1,'String',FilePath1);
img=imread(FilePath1);
axes(handles.axes_pic1);
imshow(img);
end
guidata(hObject, handles);
% --- Executes on button press in pushbutton_pic2.
function pushbutton_pic2_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton_pic2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global FilePath2
[FileName,PathName] = uigetfile({'*.jpg';'*.bmp'},'Select the picture');
if ~isequal(FileName,0)
FilePath2 = fullfile(PathName,FileName);
set(handles.edit_lj2,'String',FilePath2);
img=imread(FilePath2);
axes(handles.axes_pic2);
imshow(img);
end
guidata(hObject, handles);
function edit_lj1_Callback(hObject, eventdata, handles)
% hObject handle to edit_lj1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: get(hObject,'String') returns contents of edit_lj1 as text
% str2double(get(hObject,'String')) returns contents of edit_lj1 as a double
% --- Executes during object creation, after setting all properties.
function edit_lj1_CreateFcn(hObject, eventdata, handles)
% hObject handle to edit_lj1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc
set(hObject,'BackgroundColor','white');
else
set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor'));
end
function edit_lj2_Callback(hObject, eventdata, handles)
% hObject handle to edit_lj2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: get(hObject,'String') returns contents of edit_lj2 as text
% str2double(get(hObject,'String')) returns contents of edit_lj2 as a double
% --- Executes during object creation, after setting all properties.
function edit_lj2_CreateFcn(hObject, eventdata, handles)
% hObject handle to edit_lj2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc
set(hObject,'BackgroundColor','white');
else
set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor'));
end
function edit_arithmetic_Callback(hObject, eventdata, handles)
% hObject handle to edit_arithmetic (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: get(hObject,'String') returns contents of edit_arithmetic as text
% str2double(get(hObject,'String')) returns contents of edit_arithmetic as a double
% --- Executes during object creation, after setting all properties.
function edit_arithmetic_CreateFcn(hObject, eventdata, handles)
% hObject handle to edit_arithmetic (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc
set(hObject,'BackgroundColor','white');
else
set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor'));
end
% --------------------------------------------------------------------
function uipanel_choice_SelectionChangeFcn(hObject, eventdata, handles)
% hObject handle to uipanel_choice (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global version
if get(handles.radiobutton_horn,'Value')
s=1;
end
if get(handles.radiobutton_lk,'Value')
s=2;
end
if get(handles.radiobutton_brox,'Value')
s=3;
end
if get(handles.radiobutton_bs,'Value')
s=4;
end
if get(handles.radiobutton_bss,'Value')
s=5;
end
switch s
case 1
version = 3;
set(handles.edit_arithmetic,'String','Horn-Schunck');
case 2
version = 4;
set(handles.edit_arithmetic,'String','Lucas-Kanade');
case 3
version = 0;
set(handles.edit_arithmetic,'String','Brox');
case 4
version = 1;
set(handles.edit_arithmetic,'String','Brox 改进版本');
case 5
version = 2;
set(handles.edit_arithmetic,'String','Brox 改进版本 + Sift');
end
guidata(hObject, handles);
% --- Executes during object creation, after setting all properties.
function pushbutton_start_CreateFcn(hObject, eventdata, handles)
% hObject handle to pushbutton_start (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% --- Executes during object creation, after setting all properties.
function figure1_CreateFcn(hObject, eventdata, handles)
% hObject handle to figure1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
addpath('./Brox');
addpath('./Horn_Schunck');
addpath('./Lucas_Kanade');
global version
global FilePath1
global FilePath2
version = 3;
FilePath1 = 'No Picture';
FilePath2 = 'No Picture';
三、运行结果
四、备注
版本:2014a