对于单层光流法,每次迭代求解增量方程使用了8x8窗口的所有像素点的信息,当运动较大,使得估计点在下一帧图像的位置超出了这个窗口,这时光流法就会跟丢这个点
多层光流法基于图像金字塔,通过对上层图像使用光流法得到估计值(同样的8x8窗口,但是上层图像分辨率较小,因此可以估计更大的运动),再将估计值反馈到下层作为计算的初始值,从而解决单层光流法无法估计较大运动等问题
多层光流法的过程
1、寻找GFTT角点
2、计算图像金字塔
3、对图像金字塔,从上至下使用单层光流法
验证时可以与opencv的光流金字塔估计的位置进行对比,opencv提供的光流金字塔接口:
void cv::calcOpticalFlowPyrLK (
InputArray prevImg,
InputArray nextImg,
InputArray prevPts,
InputOutputArray nextPts,
OutputArray status,
OutputArray err,
Size winSize = Size(21, 21),
int maxLevel = 3,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01),
int flags = 0,
double minEigThreshold = 1e-4
)
#include <iostream>
#include <string>
using namespace std;
//#include <list>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
using namespace cv;
#include <Eigen/Core>
#include <Eigen/Dense>
//定义一个用于光流跟踪的类
class OpticalFlowTracker
{
public:
OpticalFlowTracker(
const Mat &img1,
const Mat &img2,
const vector<KeyPoint> &kp1,
vector<KeyPoint> &kp2,
vector<bool> &success,
bool inverse = true,
bool has_initial = false
) : _img1(img1), _img2(img2), _kp1(kp1), _kp2(kp2), _success(success), _inverse(inverse), _has_initial(has_initial){};
void calculateOpticalFlow(const Range &range);
private:
const Mat &_img1;
const Mat &_img2;
const vector<KeyPoint> &_kp1;
vector<KeyPoint> &_kp2;
vector<bool> &_success;
bool _inverse = true; //_inverse = true 使用反向光流法
bool _has_initial = false; //单目相机初始化后,这个标志置为true
};
//下面使用了源码,没有修改
inline float GetPixelValue(const cv::Mat &img, float x, float y) {
//不严谨的边界检测
//1:后面使用了多个像素进行平滑处理,如果传入点在最后一行会导致指针越界
//2:如果传入点在最后一列,不再是使用2*2方块进行平滑处理(其中一个点位于下一行的第一列)
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x >= img.cols) x = img.cols

本文介绍了光流法在处理大运动场景时的问题,即单层光流法由于窗口限制可能导致跟踪丢失。多层光流法通过图像金字塔解决了这一问题,通过对上层图像的光流估计来改善下层的跟踪效果。文中详细阐述了多层光流法的步骤,并给出了OpenCV中的光流金字塔接口。此外,还提供了一个自定义的光流跟踪类实现,包括反向光流法和单层光流法的计算过程。最后,通过实例展示了不同光流方法的跟踪结果,并与OpenCV的光流估计进行了比较。
最低0.47元/天 解锁文章
6402





