【图像配准】基于Horn-Schunck和Lucas-Kanade等光流场实现图像配准matlab源码含GUI界面_function this = ba_optical_flow(varargin)-程序员宅基地

技术标签: matlab  自动驾驶  图像处理  

光流法理论背景

1.什么是光流

光流(optical flow)是空间运动物体在观察成像平面上的像素运动的瞬时速度

光流法是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。

通常将二维图像平面特定坐标点上的灰度瞬时变化率定义为光流矢量

一言以概之:所谓光流就是瞬时速率,在时间间隔很小(比如视频的连续前后两帧之间)时,也等同于目标点的位移

2.光流的物理意义

一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。

当人的眼睛观察运动物体时,物体的景象在人眼的视网膜上形成一系列连续变化的图像,这一系列连续变化的信息不断“流过”视网膜(即图像平面),好像一种光的“流”,故称之为光流。光流表达了图像的变化,由于它包含了目标运动的信息,因此可被观察者用来确定目标的运动情况。

图(1)展示的便是三维空间内物体的运动在二维成像平面上的投影。得到的是一个描述位置变化的二维矢量,但在运动间隔极小的情况下,我们通常将其视为一个描述该点瞬时速度的二维矢量u=(u,v),称为光流矢量。

                   图(1) 三维运动在二维平面内的投影

3.光流场

在空间中,运动可以用运动场描述,而在一个图像平面上,物体的运动往往是通过图像序列中不同图像灰度分布的不同体现的,从而,空间中的运动场转移到图像上就表示为光流场(optical flow field)。

光流场是一个二维矢量场,它反映了图像上每一点灰度的变化趋势,可看成是带有灰度的像素点在图像平面上运动而产生的瞬时速度场。它包含的信息即是各像点的瞬时运动速度矢量信息。

研究光流场的目的就是为了从序列图像中近似计算不能直接得到的运动场。光流场在理想情况下,光流场对应于运动场。

                                              图(2)三维空间的矢量场及其在二维平面内的投影

                                                   图(3)现实场景的可视化光流场

三言以概之:所谓光流场就是很多光流的集合。

                     当我们计算出了一幅图片中每个图像的光流,就能形成光流场。

                     构建光流场是试图重现现实世界中的运动场,用以运动分析。

光流法基本原理

1.基本假设条件

(1)亮度恒定不变。即同一目标在不同帧间运动时,其亮度不会发生改变。这是基本光流法的假定(所有光流法变种都必须满足),用于得到光流法基本方程;

(2)时间连续或运动是“小运动”。即时间的变化不会引起目标位置的剧烈变化,相邻帧之间位移要比较小。同样也是光流法不可或缺的假定。

2.基本约束方程

考虑一个像素I(x,y,t)在第一帧的光强度(其中t代表其所在的时间维度)。它移动了 (dx,dy)的距离到下一帧,用了dt时间。因为是同一个像素点,依据上文提到的第一个假设我们认为该像素在运动前后的光强度是不变的,即:

将(1)式右端进行泰勒展开,得:

其中ε代表二阶无穷小项,可忽略不计。再将(2)代人(1)后同除dt,可得:


       设u,v分别为光流分别为沿X轴与Y轴的速度矢量,得:

       令分别表示图像中像素点的灰度沿X,Y,T方向的偏导数。

    综上,式(3)可以写为:

       其中,Ix,Iy,It均可由图像数据求得,而(u,v)即为所求光流矢量。

       约束方程只有一个,而方程的未知量有两个,这种情况下无法求得u和v的确切值。此时需要引入另外的约束条件,从不同的角度引入约束条件,导致了不同光流场计算方法。按照理论基础与数学方法的区别把它们分成四种:基于梯度(微分)的方法、基于匹配的方法、基于能量(频率)的方法、基于相位的方法和神经动力学方法。

3.几种光流估计算法的简介

1) 基于梯度的方法

基于梯度的方法又称为微分法,它是利用时变图像灰度(或其滤波形式)的时空微分(即时空梯度函数)来计算像素的速度矢量。

由于计算简单和较好的结果,该方法得到了广泛应用和研究。典型的代表是Horn-Schunck算法与Lucas-Kanade(LK)算法。

Horn-Schunck算法在光流基本约束方程的基础上附加了全局平滑假设,假设在整个图像上光流的变化是光滑的,即物体运动矢量是平滑的或只是缓慢变化的。

基于此思想,大量的改进算法不断提出。Nagel采用有条件的平滑约束,即通过加权矩阵的控制对梯度进行不同平滑处理;Black和Anandan针对多运动的估计问题,提出了分段平滑的方法。

2) 基于匹配的方法

基于匹配的光流计算方法包括基于特征和区域的两种。

基于特征的方法不断地对目标主要特征进行定位和跟踪,对目标大的运动和亮度变化具有鲁棒性。存在的问题是光流通常很稀疏,而且特征提取和精确匹配也十分困难。

基于区域的方法先对类似的区域进行定位,然后通过相似区域的位移计算光流。这种方法在视频编码中得到了广泛的应用。然而,它计算的光流仍不稠密。另外,这两种方法估计亚像素精度的光流也有困难,计算量很大。

3)基于能量的方法

基于能量的方法又称为基于频率的方法,在使用该类方法的过程中,要获得均匀流场的准确的速度估计,就必须对输入的图像进行时空滤波处理,即对时间和空间的整合,但是这样会降低光流的时间和空间分辨率。基于频率的方法往往会涉及大量的计算,另外,要进行可靠性评价也比较困难。

4)基于相位的方法

基于相位的方法是由Fleet和Jepson提出的,Fleet和Jepson最先提出将相位信息用于光流计算的思想。当我们计算光流的时候,相比亮度信息,图像的相位信息更加可靠,所以利用相位信息获得的光流场具有更好的鲁棒性。基于相位的光流算法的优点是:对图像序列的适用范围较宽,而且速度估计比较精确,但也存在着一些问题:第一,基于相位的模型有一定的合理性,但是有较高的时间复杂性;第二,基于相位的方法通过两帧图像就可以计算出光流,但如果要提高估计精度,就需要花费一定的时间;第三,基于相位的光流计算法对图像序列的时间混叠是比较敏感的。

5)神经动力学方法

神经动力学方法是利用神经网络建立的视觉运动感知的神经动力学模型,它是对生物视觉系统功能与结构比较直接的模拟。

尽管光流计算的神经动力学方法还很不成熟,然而对它的研究却具有极其深远的意义。随着生物视觉研究的不断深入,神经方法无疑会不断完善,也许光流计算乃至计算机视觉的根本出路就在于神经机制的引入。神经网络方法是光流技术的一个发展方向。

3.稠密光流与稀疏光流

除了根据原理的不同来区分光流法外,还可以根据所形成的光流场中二维矢量的疏密程度将光流法分为稠密光流与稀疏光流两种。

  1. 稠密光流

稠密光流是一种针对图像或指定的某一片区域进行逐点匹配的图像配准方法,它计算图像上所有的点的偏移量,从而形成一个稠密的光流场。通过这个稠密的光流场,可以进行像素级别的图像配准。

Horn-Schunck算法以及基于区域匹配的大多数光流法都属于稠密光流的范畴。

                                      图(4) 基于区域匹配方法生成稠密光流场图例

     由于光流矢量稠密,所以其配准后的效果也明显优于稀疏光流配准的效果。但是其副作用也是明显的,由于要计算每个点的偏移量,其计算量也明显较大,时效性较差。

  1. 稀疏光流

与稠密光流相反,稀疏光流并不对图像的每个像素点进行逐点计算。它通常需要指定一组点进行跟踪,这组点最好具有某种明显的特性,例如Harris角点等,那么跟踪就会相对稳定和可靠。稀疏跟踪的计算开销比稠密跟踪小得多。

上文提到的基于特征的匹配方法是典型的属于稀疏光流的算法。

                                    图(5) 基于特征匹配方法生成稀疏光流场图例

Lucas-Kanade(LK)光流法

LK光流法于1981年提出,最初是用于求稠密光流的,由于算法易于应用在输入图像的一组点上,而成为求稀疏光流的一种重要方法。

LK光流法在原先的光流法两个基本假设的基础上,增加了一个“空间一致”的假设,即所有的相邻像素有相似的行动。也即在目标像素周围m×m的区域内,每个像素均拥有相同的光流矢量。以此假设解决式  无法求解的问题。

  1. LK光流法约束方程

在一个小邻域内,LK光流法通过对下式的加权平方和最小化来估计光流矢量

上式中是一个窗口权重函数,该函数使得邻域中心的加权比周围的大。对于Ω内的n个点X1⋯Xn,设

               

    

故上面方程的解可由最小二乘法得到:

最后得:

通过结合几个邻近像素点的信息,LK光流法通常能够消除光流方程里的多义性。而且,与逐点计算的方法相比,LK方法对图像噪声不敏感。

  1. 金字塔LK光流法

LK算法的约束条件即:小速度,亮度不变以及区域一致性都是较强的假设,并不很容易得到满足。如当物体运动速度较快时,假设不成立,那么后续的假设就会有较大的偏差,使得最终求出的光流值有较大的误差。图像金字塔可以解决这个问题。

考虑物体的运动速度较大时,算法会出现较大的误差。那么就希望能减少图像中物体的运动速度。一个直观的方法就是,缩小图像的尺寸。假设当图像为400×400时,物体速度为[16 16],那么图像缩小为200×200时,速度变为[8,8]。缩小为100*100时,速度减少到[4,4]。所以在源图像缩放了很多以后,原算法又变得适用了。所以光流可以通过生成 原图像的金字塔图像,逐层求解,不断精确来求得。简单来说上层金字塔(低分辨率)中的一个像素可以代表下层的四个。

一段以补充:我灵魂画手在画下图时表达稍微不恰当Σ(っ°Д°;)っ,黑色方块实际上应该为方框。表示的是所选区域的大小在金字塔各层中的不变,而并不代表该区域内像素点保持怎样的状态或是有什么联系。没有!在图像缩放过程中每个区域的像素灰度值情况都会在变化。只是说我们基于LK算法假设的“空间一致”让“一片区域具有相同的运动状态”。这个所谓的区域并不是指某一个有相同特征的像素集合,仅仅只是一个框,一个范围的概念,一个大小的概念而已

 

一段以解释:黑色方块代表两个连续的帧内同一目标的不同位置。为了观察方便我才将其放在一张图里。

面对“大运动”时我光流法的局限是什么?显然是运动距离大原算法不适用。(hhh)那么其实只要通过图片尺寸的不断缩小,而且目标选框大小保持不变,让运动前后两个物体的位置看上去“不断靠近”,直到变成小运动就可以使用光流法了。读者可能会存在很多疑问:1.为什么图片整体尺寸缩减时假定的目标其“尺寸”可以保持不变?2.只在分辨率很小的尺度内计算光流,有什么用?能替代真实的光流矢量的值吗?

我先粗略解释一下,然后下文会展示详细的算法过程,让读者能有更深刻的认识。

1.不论是在什么尺寸(尺度,缩小图片其实是模拟观察者的远近)的情况下,我们都坚持LK光流法的假设,即“空间一致”,不管我们看到图像是1000x1000还是10x10,我们都认为一个像素和它周围的一片区域内的若干个像素具有相同的速度。这是你使用LK光流法就必须承认的一个假设。这一片区域大小不一定是50x50,但始终是存在且不随客观情况改变只由你自己的判断而确定。

2.在低尺度下只计算一次当然不准,为什么?你把图片弄得很模糊又很小,丢失了很多信息,还想检测准确?但是在低尺度下的光流矢量的测量能给我们一个指示,就像是低尺度下它综观全局,告诉你“运动大概是5点钟方向,大小大概是【32,57】”之类的信息。这条信息够粗糙,但是大体上是有用的。它使得你在进入金字塔的下一层时有一个大概的头绪,你由此指示可以在下一层金字塔再一次顺利“靠近”真实目标,强行符合“小运动”。这里可能说得很抽象,大家细细看下面的具体算法再回来看这一段或许会有所启示。

(下面这一部分具体参照程序员宅基地:https://blog.csdn.net/sgfmby1994/article/details/68489944 ,写得非常棒,受益匪浅)

1)算法步骤简介

a.首先,对每一帧建立一个高斯金字塔,最低分辨率图像在最顶层,原始图片在底层。

b.计算光流。从顶层(Lm层)开始,通过最小化每个点的邻域范围内的匹配误差和,得到顶层图像中每个点的光流。

假设图像的尺寸每次缩放为原来的一半,共缩放了Lm层,则第0层为原图像。设已知原图的位移为d,则每层的位移为:

c.顶层的光流计算结果(位移情况)反馈到第Lm-1层,作为该层初始时的光流值的估计g。

d.这样沿着金字塔向下反馈,重复估计动作,直到到达金字塔的底层(即原图像)。

 (准确值=估计值+残差) “残差”即本算法的关键对于每一层L,每个点的光流的计算都是基于邻域内所有点的匹配误差和最小化。

为了更好地理解金字塔LK光流法,下图简单展示了算法的实现过程:

一段以解释:低尺度下找到光流矢量d0,将其扔到下一层去指引我们前行。扔下去后首先要放大两倍,此时你开始抱怨:“上一层找到的d0根本不靠谱,差距好大”(图2中蓝方块与右下角黑色方块的差距)但是你也要庆幸,正是“不靠谱”的d0让你到达了蓝色方块的位置,让你离真实区域前进了很多,否则你还在左上角苦于“小运动”寸步难行呢。在蓝色位置你就满足“小运动”了,继续计算光流,得到d1,然后把(2d0+d1)扔到下一层指导我们继续前行,如此往复。

2)一些实现细节

    金字塔的构建

  1. 利用低通滤波器平滑图像

  1. 对平滑图像进行间隔采样,生成金字塔图像,每一层图像的高度与宽度均是下一层的二分之一。

金字塔跟踪

首先,从顶层开始计算金字塔最顶层图像上的光流。然后,根据最顶层(Lm-1) 光流的计算结果估计次顶层光流的初始值,再计算次顶层图像上光流的精确值。最后,根据次上层光流的计算结果估计下一层(Lm-2) 光流的初始值,计算其精确值后再反馈到下一 层,直至计算出最底层 的原始图像的光流。

  1. 初始化顶层图像光流矢量估计值为0.

  1. 邻域内所有像素点的匹配误差和记为:

  1. 对其进行求导,得:

  1. 对B(x+vx,y+vy)进行泰勒展开:

  1. 导数公式可转化为: 

  1. 带入得:

定义:

  1. 最终得光流矢量最优解为:

观察G与b的组成,可知δI其实是两帧同层图像灰度之间的差值。而Ix,Iy分别是图像在该点处梯度的x方向分量与y方向分量。

根据δIIx,Iy求得空间梯度 矩阵G和b。以此得到Lm层图像的最佳光流dLm

解释一下:前面说得好像很轻松,什么“然后就计算一下光流矢量”。但是具体要怎么做呢?我这里只粗略讲讲思路,具体结合上面的公式再来看或许才能有所感悟。

很简单,我不是知道前一帧目标的具体位置(x,y)吗?我还给它画了个假定范围内速度一致对吧?好,现在我来个遍历,我让光流矢量(速度)取[-100,100]到[100,100]一个一个代(比如取[10,10]),然后到后一帧里让原来的目标x,y加上[10,10],看看得到的这一个点(x+10,y+10)和上一帧的(x,y)点的灰度值差多少(别忘了我们最基础的假设一:同一目标运动过程中灰度值(光强)大小保持恒定,灰度值差当然越小我们就越认为找的没错啦),范围w内的其他像素点小伙伴们也一样加上[10,10]进行比较,看看误差有多大。如果觉得[10,10]误差太大了接受不了,就取[11,10]看看。直到取到一个(例如[73,29])使得误差最小,那么我们就说[73,29]是(x,y)点的光流矢量了。

这种遍历看上去是不是好low?的确如此。所以我们用的并不是这个方法。Σ(っ°Д°;)っΣ(っ°Д°;)っΣ(っ°Д°;)っ

上文中 的其实就像是这样的一个函数:自变量是速度矢量,函数值是误差的大小。我们要求在什么速度矢量的输入下得到的误差最小,直接求导嘛!!!!!就不用一个一个v傻傻代入了呀。求导让导函数等于零,此时的v正是所求的光流矢量。此方法与上一段的“傻方法”效果一样,但是计算十分简便了。思路就是这么个思路,具体一些细节还是看上面。

迭代过程

将上层图像得到的光流矢量累加值传递到下一层做为初始值,即:

    可以看出,最终光流值就是所有层光流矢量的叠加。

最后我们可以总结一下使用金字塔图像计算光流的好处,它对于每一次光流的都会保持很小,但是最终计算出来的光流可以进行放大然后累计。所以利用相对较小的邻域窗口就可以处理较大的像素运动。

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';

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_60703264/article/details/119820608

智能推荐

@Transactional注解超详细-程序员宅基地

文章浏览阅读2.4w次,点赞23次,收藏70次。Transactional注解是Spring框架中用于声明式事务管理的关键注解。本文将深入探讨@Transactional注解的作用、使用方式和常见属性,并结合代码实例演示其在实际项目中的应用,以帮助读者更好地理解和使用该注解。@Transactional注解是Spring框架中用于声明式事务管理的关键注解。通过使用@Transactional注解,我们可以更加方便地管理事务,保障数据的一致性和可靠性。在实际项目中,合理使用@Transactional注解可以提高「开发效率 」和代码「可维护性 」。_@transactional

单独安装node_modules(npm安装node_modules)_npm/inode_modules/nativefier/node_modules/got-程序员宅基地

文章浏览阅读8k次。安装指令:npm install国内镜像:cnpm install注意:有时候使用npm install会出错,直接换成国内镜像安装就可以了_npm/inode_modules/nativefier/node_modules/got

《腾云:云计算和大数据时代网络技术揭秘》.pdf-程序员宅基地

文章浏览阅读598次。关注“Java后端技术全栈”回复“面试”获取全套面试资料什么是大数据?最有名的回答莫过于"5V特点":1)Volume:数据量大,包括采集、存储和计算的量都非常大。大数据..._腾云 云计算

也谈Spring Bean的生命周期 和扩展接口应用-程序员宅基地

文章浏览阅读144次。http://sexycoding.iteye.com/blog/1046775BeanPostProcessor:bean的前置处理和后置处理扩展接口。InitializingBean :初始化构造方式,初始化方法,属性设置后置处理扩展接口。DisposableBean :如果该Bean是单例的,则当容器销毁并且该Bean实现了DisposableBean接口的时候,调用dest..._bean生命周期的扩展定制接口

基于opencv的图像滤波器/vs_箱式滤波器opencv和vs怎么实现-程序员宅基地

文章浏览阅读314次。中值滤波原理:假设一个33的矩阵,中值滤波就是把这个矩阵的值重新排序,将中间的灰度值赋给中心点坐标处的灰度值。例如上图就是重排序为98,98,99,99,99,100,100,100,101,将99赋给中心点。中值滤波很容易处理椒盐噪声,椒盐噪声的存在是因为图像中某些点的灰度值为255或者0,当重新排序后,这些点会忽略掉,同时一幅图像的灰度值是跟临近像素的灰度值有关,不会突然的跃迁,总是有..._箱式滤波器opencv和vs怎么实现

Tensorflow 错误记录(持续更新...)_tensorflow true_fn must be callable.-程序员宅基地

文章浏览阅读284次。1. 使用tf.cond/tf.case:报错:TypeError: true_fn must be callable.解决: tf.cond(a < b, f1, f2) -> tf.cond(a < b, lambda : f1, lambda: f2) ..._tensorflow true_fn must be callable.

随便推点

人工智能实践:TensorFlow笔记学习(一)—— 人工智能概述_ai tensorflow学习-程序员宅基地

文章浏览阅读1w次,点赞7次,收藏58次。概 述 一、 基本概念 1、什么是人工智能 人工智能的概念:机器模拟人的意识和思维 重要人物:艾伦·麦席森·图灵(Alan Mathison Turing) 人物简介:1912年6月23日-1954年6月7日,英国数学家、逻辑学家,被称为计算机科学之父,人工智能之父。 相关事件:(1)1950年在论文《机器能思考吗?》中提出了图灵测试,一种用于判定机器是否具有智能的试验方法:提问者和回答者隔开,..._ai tensorflow学习

centos下通过yum安装svn(1.7及以上版本)_yum svn 查看版本-程序员宅基地

文章浏览阅读340次。今天测试环境svn突然不能更新了,看了下报错,发现是由于测试环境svn版本过低导致的,这边记录一下处理过程:1.新建 /etc/yum.repos.d/wandisco-svn.repo,添加如下内容[WandiscoSVN]name=Wandisco SVN Repobaseurl=http://opensource.wandisco.com/centos/6/svn-1.10/RPMS/x86_64/enabled=1gpgcheck=02.卸载旧版本,安装新版本yu.._yum svn 查看版本

设置apk权限allow_apk --allow-notrunted-程序员宅基地

文章浏览阅读798次。adb shell pm grant com.jane.smscode android.permission.READ_SMS android.permission.RECEIVE_SMS android.permission.WRITE_EXTERNAL_STORAGE ndroid.permission.MOUNT_UNMOUNT_FILESYSTEMS允许读短信、接收短信、写入存储卡权限_apk --allow-notrunted

1000行代码入门python-在知乎上学 Python - 爬虫篇-程序员宅基地

文章浏览阅读746次。知乎是个好地方。虽然近年来,为了吸引更多的用户,知乎的定位与早期略有点偏离。但从内容质量和专业性来说,知乎仍然是国内数一数二的知识型社区。不少同学都是通过知乎发现了我们编程教室,我自己也经常会通过知乎去寻求一些专业知识的解答和参考。之前,为了让大家能更好地挖掘知乎上有价值的信息,我们做了一个索引,把编程入门相关的一些问答和文章做了整理:文中曾立下FLAG说之后会整理爬虫、数据分析、机器学习等方面的..._编写程序,代码行数不少于1000,问题最好是来自学习

深入Springboot启动流程+自动配置原理_静态类怎么知道springboot是用什么配置去启动-程序员宅基地

文章浏览阅读1.2w次,点赞27次,收藏64次。深入Springboot启动流程+自动配置原理写在前面相关常见面试题Springboot启动入口@SpringBootConfiguration解读@ComponentScan解读@EnableAutoConfiguration解读(重点)@AutoConfigurationPackage解读@Import({AutoConfigurationImportSelector.class})解读(重点)写在前面自从SpringBoot问世以来,开发界可以说是乱了套。我还记得我朋友几年前去参加_静态类怎么知道springboot是用什么配置去启动

CMD命令:Command如何查看目录文件_cmd查看c盘所有文件-程序员宅基地

文章浏览阅读1.4w次,点赞4次,收藏8次。前言:cmd的部分命令不同于Linux命令,很多小伙伴在使用cmd命令时会有种在Linux系统上操作的错觉,但是两者之间还是有一些差异的;例如在查看某个目录中的文件就略有不同。打开命令窗口Windows键+R 键入cmd 回车打开某个盘符这里以C盘为例cd C:回车然后切换到根目录cd..这里我们想看下C盘下有什么文件夹或文件,则输入如下命令dir展示目录结..._cmd查看c盘所有文件