一、光流法的简介
当前移动摄像头下目标的检测是目标检测领域一个重要的热点,而光流法是进行移动摄像头下目标检测的一个重要工具。光流的概念是Gibson在1950年首先提出来的。它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。计算光流的方法有:
(1)基于区域或者基于特征的匹配方法;
(2)基于频域的方法;
(3)基于梯度的方法;
光流是空间运动物体在观测成像平面上的像素运动的“瞬间速度”。光流的研究是利用图像序列中的像素强度数据的时域变化和相关性来确定各自像素位置的“运动”,研究光流场的目的就是为了从图片序列中近似得到不能直接得到的运动场。
光流法的假设前提:
(1)亮度恒定:随着时间的变换,相邻帧间图像的亮度不发生变化;
(2)相邻帧之间物体的运动比较“微小”:这样灰度才能对位置求导;
(3)保持空间一致性;即,邻近的像素点具有相同的运动,速度一致;
标注:运动场-物体在三维真实世界中的运动; 光流场-运动场在二维图像平面上的投影。
二、光流的计算:
三、光流法的程序:
1、C++程序
#include "stdafx.h"
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
const int MAX_CORNERS = 500;
const double pi = 3.14159265358979323846;
int _tmain(int argc, _TCHAR* argv[])
{
string imgname1 = "person1.jpg";
string imgname2 = "person2.jpg";
Mat img1,img2,img1_gray,img2_gray;
img1 = imread(imgname1);
img2 = imread(imgname2);
cvtColor(img1,img1_gray,CV_RGB2GRAY);
cvtColor(img2,img2_gray,CV_RGB2GRAY);
namedWindow("Result",CV_WINDOW_AUTOSIZE);
imshow("Result",img1_gray);
//-------Shi-Tomasi角点算法参数定义
int number_of_features = MAX_CORNERS;
double qualityLevel = 0.01;
double minDistance = 5.0;
int blockSize = 3;
bool useHarrisDetector = false;
double k = 0.04;
vector<KeyPoint> keypoint1;
GoodFeaturesToTrackDetector detector(number_of_features,qualityLevel,minDistance,blockSize,useHarrisDetector,k);
detector.detect(img1_gray,keypoint1);
Size optical_flow_window = Size(3,3);
CvTermCriteria criteria = cvTermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03 );
vector<Point2f> prePt,nextPt;
for (int i=0; i<keypoint1.size(); i++)
{
prePt.push_back(keypoint1[i].pt);
}
//------金字塔Lucas-Kanande光流法
Mat found_feature;
Mat feature_error;
calcOpticalFlowPyrLK(img1_gray,img2_gray,prePt,nextPt,found_feature,feature_error,Size(3,3),5,criteria,0,1e-4);
for (int i=0; i<MAX_CORNERS; i++)
{
if (found_feature.at<bool>(i,0)==0)
continue;
int line_thickness;
line_thickness = 0.5;
CvScalar line_color;
line_color = CV_RGB(0,255,0);
Point p,q;
p.x = (int)prePt[i].x;
p.y = (int)prePt[i].y;
q.x = (int)nextPt[i].x;
q.y = (int)nextPt[i].y;
double angle;
angle = atan2( (double)p.y - q.y, (double)p.x - q.x);
double hypotenuse;
hypotenuse = sqrt((double)(p.y - q.y)*(p.y - q.y) + (double)(p.x - q.x)*(p.x - q.x));
q.x = (int)(p.x - 3 * hypotenuse * cos(angle));
q.y = (int)(p.y - 3 * hypotenuse * sin(angle));
line(img1, p, q, line_color, line_thickness, CV_AA,0);
p.x = (int)(q.x + 9 * cos(angle + pi/4));
p.y = (int)(q.y + 9 * sin(angle + pi/4));
line(img1, p, q, line_color, line_thickness, CV_AA, 0);
p.x = (int)(q.x + 9 * cos(angle - pi / 4));
p.y = (int)(q.y + 9 * sin(angle - pi / 4));
line(img1, p, q, line_color, line_thickness, CV_AA, 0);
}
namedWindow("光流图",CV_WINDOW_AUTOSIZE);
imshow("光流图",img1);
waitKey(0);
return 0;
}