利用Harris方法找到了特征点后,就可以对特征点进行跟踪了。
所谓“跟踪”,实际上是在下一帧图像中寻找与本图像特征点最相似的点。
何为“相似”?这就需要对每个特征点进行一种描述,这样才能在下一帧图像中寻找(或者说搜索)描述最相似的点。
而搜索的过程显然是比较慢的。早期的计算机速度慢,如果进行“地毯式搜索”,则达不到实时处理速度,因此一些近似方法就这样产生了。
首先是光流法。光流法假定在两帧之间的微小时间间隔内,每个点周围的微小区域是完全一致,不发生任何变化的。
也就是说,假定I为图像的亮度,(x,y)为点的位置,t为当前帧时间,那么
而根据泰勒公式
高阶无穷小
所以
或者
注意到这里出现了物体移动速度的项,可以写成:
其中为物体(点)移动的速度,也成为”光流“。
更简单可以写成方程:
因为, 和 均可直接用减法求出,因此计算光流是非常高效的。
这个方程的未知数超过一个,所以实际计算时是取每个特征点周围5X5的25个点,用最小二乘法计算最优光流。
OpenCV中提供了光流法的函数,使用方便。
其中比较重要的函数是goodFeaturesToTrack和calcOpticalFlowPyrLK,前一个用来获取特征点,后一个进行光流跟踪。
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
VideoCapture cap(0);
cap.set( CV_CAP_PROP_FRAME_WIDTH,320);
cap.set( CV_CAP_PROP_FRAME_HEIGHT,240 );
if (!cap.isOpened()) {
cout << "open camera error." << endl;
exit(-1);
}
namedWindow("disp");
Mat img, gray, prevGray;
vector<Point2f> pts, prevPts;
vector<unsigned char> status;
vector<float> err;
int maxCorners = 20;
int iFrame = 0;
while (true) {
cap >> img;
cvtColor(img, gray, CV_RGB2GRAY);
if (iFrame == 0) {
goodFeaturesToTrack(gray, pts, maxCorners, 0.1, 5);
if (pts.size() == 0){
iFrame = 0;
continue;
} else {
TermCriteria termcrit(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03);
Size subPixWinSize(10,10);
cornerSubPix(gray, pts, subPixWinSize, Size(-1,-1), termcrit);
}
} else {
calcOpticalFlowPyrLK(prevGray, gray, prevPts, pts, status, err);
}
for (int i = 0; i < pts.size(); i++) {
circle(img, pts[i], 2, Scalar(255, 255, 0), 1);
}
imshow("disp", img);
swap(prevGray, gray);
swap(prevPts, pts);
iFrame++;
if (waitKey(30) >= 0)
break;
}
}