内容:
二者关系
光流法
直接法
一、二者关系
引出原因:关键点和描述子计算非常耗时,可以保留特征点,使用光流法跟踪特征点运动。
关系:光流法描述像素在图像中运动,直接法利用相机运动模型计算特征点在下一时刻图像中位置。
使用条件:直接法利用图像的像素灰度信息计算相机运动,需要场景中存在明暗变化。
二、LK光流法
光流法常用来跟踪角点的运动。之后用跟踪的特征点,用ICP、PnP或对极几何估计相机运动。
适用场景:要求相机运动缓慢,采集频率高
调用函数calcOpticalFlowPyrLK
void cv::calcOpticalFlowPyrLK(InputArray prevImg,nextImg,prevPts,nextPts,
OutputArray status,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
)
1、对第一帧提取FAST特征点存到keypoints中(list类型,之后还会删除)
2、对其他帧用LK跟踪特征点
3. 更新keypoints列表,从prev_keypoints到next_keypoints
4. 画出 keypoints出为圆圈
int main(int argc, char** argv)
{
string path_to_dataset = argv[1];
string associate_file = path_to_dataset + "/associate.txt";
//读入txt文本到fin中
ifstream fin(associate_file);
string rgb_file, depth_file, time_rgb, time_depth;
// 因为要删除跟踪失败的点,keypoints使用list,元素类型是Point2f,坐标
// 逐帧操作的将color承接为last_color,然后color读取新的图
list< cv::Point2f > keypoints;
cv::Mat color, depth, last_color;
for (int index = 0; index<100; index++)
{
//读入颜色和深度图像
fin >> time_rgb >> rgb_file >> time_depth >> depth_file;
color = cv::imread(path_to_dataset + "/" + rgb_file);
depth = cv::imread(path_to_dataset + "/" + depth_file, -1);
// 1. 对第一帧提取FAST特征点存到keypoints中
if (index == 0)
{
vector<cv::KeyPoint> kps;
cv::Ptr<cv::FastFeatureDetector> detector = cv::FastFeatureDetector::create();
detector->detect(color, kps);
for (auto kp : kps)
keypoints.push_back(kp.pt);
last_color = color;
continue;
}
//实际只有10张图,后面10-99没有数据所以一直continue掉,index秒到99
if (color.data == nullptr || depth.data == nullptr)
continue;
// 2. 对其他帧用LK跟踪特征点
vector<cv::Point2f> next_keypoints;
vector<cv::Point2f> prev_keypoints;
for (auto kp : keypoints)
prev_keypoints.push_back(kp);
//调用calcOpticalFlowPyrLK函数
//status匹配状态,匹配上赋1,否则赋0;
vector<unsigned char> status;
vector<float> error;
cv::calcOpticalFlowPyrLK(last_color, color, prev_keypoints, next_keypoints, status, error);
// 3. 更新keypoints列表,从prev_keypoints到next_keypoints
int i = 0;
for (auto iter = keypoints.begin(); iter != keypoints.end(); i++)
{
//跟丢了删除,iter保持当前位置,不会++,但i会++;
//跟踪失败,next_keypoints中数据被跳过
if (status[i] == 0)
{
iter = keypoints.erase(iter);
continue;
}
//跟踪上的好点,才会让iter指向,
*iter = next_keypoints[i];
iter++;
}
cout << "tracked keypoints: " << keypoints.size() << endl;
if (keypoints.size() == 0)
{
cout << "all keypoints are lost." << endl;
break;
}
// 4. 画出 keypoints出为圆圈
cv::Mat img_show = color.clone();
for (auto kp : keypoints)
cv::circle(img_show, kp, 10, cv::Scalar(0, 240, 0)