光流(optical flow)是运动物体运动带来的像素变化,表示 像素空间的运动速度,直观也可以理解为 光的流动。一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。
光流是通过 像素在时域上的变化来计算的,通过相邻帧之间的相关性来找到上一帧跟当前帧之间的对应关系。
光流分为 稀疏光流 和 稠密光流。
• 稀疏光流
所谓 稀疏光流,是指 金字塔Lucas-Kanade 方法(简称 LK 方法),算法分为两步:
1. 通过 goodFeaturesToTrack() 来寻找角点,也就是稀疏的概念;
2. 针对获得的两组Corner角点,通过 calcOpticalFlowPyrLK() 来 进行跟踪 Match。
这一步是LK光流的关键,里面用到了复杂的多尺度特征(金字塔),此处不再展开,大家可以看OpenCV源码。
相对于稠密光流, 稀疏光流 只需要对关键点进行计算,计算量较小,经常被用于 图像配准 和目标跟踪。
下图是 特征点检测 goodFeaturesToTrack 和光流计算 calcOpticalFlowPyrLK 效果(代码会在最后给出):
• 稠密光流
稠密光流 需要针对整副图计算像素偏移量(PS:确实够稠密的),可以对整幅图进行像素级别的配准,其效果要优于 稀疏光流,在某些要求比较高的场合下有应用,可以参考 Facebook 开源的 Surround360 VR全景相机。
稠密光流 的缺点在于计算量较大(机器好,任性的朋友可以忽略)。
OpenCV的 稠密光流 计算采用 Gunnar Farnebak算法,对应函数为calcOpticalFlowFarneback(),效果:
Ok,主要的两种光流法都讲过了,如果不需要深入研究的话(偏工程的童鞋就喜欢这个,哈哈:)),应该够了,看代码吧:
#include
#include "opencv2/video/tracking.hpp"
#include "opencv2/highgui/highgui.hpp"
#pragma comment(lib,"opencv_core2410.lib")
#pragma comment(lib,"opencv_highgui2410.lib")
#pragma comment(lib,"opencv_video2410d.lib")
#pragma comment(lib,"opencv_imgproc2410.lib")
#pragma comment(lib,"opencv_features2d2410.lib")
#define MAX_CORNERS 1000
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
// 初始化载入图片
vector imgs,grayImgs;
Mat img = imread("11.jpg"); imgs.push_back(img);
img = imread("22.jpg"); imgs.push_back(img);
for(size_t i=0; i vecCorners[2];
double qualityLevel = 0.01;//or 0.01
double minDistance = 10;
goodFeaturesToTrack(grayImgs[0], vecCorners[0], MAX_CORNERS, qualityLevel, minDistance);
//// 角点显示测试
//for(size_t i=0; i status;
vector err;
// 稀疏光流
calcOpticalFlowPyrLK(imgs[0], imgs[1], vecCorners[0], vecCorners[1], status, err, cvSize(21,21),3, termcrit, 0, 0.001);
for(size_t i=0; i(y, x);
line(imgs[0], Point(x, y), Point(cvRound(x+fxy.x), cvRound(y+fxy.y)), CV_RGB(0,255,0));
//circle(imgs[0], Point(x,y), 2, CV_RGB(255, 0, 0), -1);
}
}
imshow("Farneback",imgs[0]);
cvWaitKey(1);
system("pause");
return 0;
}