由于要做SLAM的project,而KLT是这个项目中第一个算法,做个记录顺便让自己记住。

定义一个矩阵frame,用于盛放caputure对象发过来的每一帧图像,gray是frame对应的灰度图,features中盛放着通过detectFeatures()在gray中识别出来的特征的坐标。
frame——当前帧(彩色)
gray——当前帧(灰度)
prev_frame,prev_gray盛放着上一帧的彩色图和灰度图。
prev_frame——上一帧(彩色)
prev_gray——上一帧(灰度)

fpts中存放着通过KLT算法筛选过的角点,这些点首先得是角点features,而这些点中,会运动的点且在当前帧中仍然存在着的点才回保存在fpts中。
fpts[0]——上一帧KLT算法筛选过的特征点的上一帧坐标的集合
fpts[1]——当前帧KLT算法筛选过的特征点的当前坐标的集合

先考虑一般的情况,最后考虑第一帧和第二帧。
首先capture会一直在读取视频或者录像中的每一帧,当前帧,给frame和gray,现在会判断上一帧KLT算法筛选过的特征点fpts[0]的数量是否大于40。先考虑大于40的情况,那接下来就会进行KLT特征点跟踪了,在klTrackFeature()中,首先给calcOpticalFlowPyrLK()输入上一帧和当前帧的灰度图,prev_gray,gray,同时也输入fpts[0],这个封装的函数会输出当前特征点fpts[1](一定要注意fpts[1]是calcOpticalFlowPyrLK()计算得到的输出值),然后一个个的比对这两帧对应特征点fpts[0][i]和fpts[1][i],如果位移大于2且能被calcOpticalFlowPyrLK()识别(status标志符为1),则在fpts[1]和initPoint保留这些点,其余的点都删掉(也就是一些从图像中消失或者不再运动的点)。

Status——特征点跟踪成功标志位

initPoint——保存着所有被KLT算法筛选过的特征点的初始坐标。它的作用就是在画轨迹线的时候和fpts[1]中的点一一连起来,显示出特征点位移特性。

当前帧的历史作用完成了,那么接下来,把当前帧的所有信息,都赋值给上一帧,把frame,gray,fpts[1],给prev_frame,prev_gray和fpts[0],下一帧来的时候,frame,gray会继续由capture提供,fpts[1]会由calcOpticalFlowPyrLK()计算得到。接下来capture会读取下一帧,重复上面的循环。随着循环的进行,一些点会出画面,特征点越来越少,少于40的时候,我们要对特征进行重新识别。对当前帧gray进行特征提取,得到features,把这些特征点放在fpts[0]和initPoints的后面,然后再重复klTrackFeature()。

对于第一帧,我们要把第一帧的信息同时给frame和pre_frame,这个是时候,信息都是一样的。在第二帧来的时候,才是真正的开始进行对比。

#include<opencv2/opencv.hpp>
#include<iostream>using namespace cv;
using namespace std;Mat frame,gray; //当前帧的彩色图和灰色图
Mat prev_frame,prev_gray; //上一帧的彩色图和灰色图
vector<Point2f> features;//当前帧的使用tomasi角点检测-特征数据vector<Point2f> iniPoints;//初始化(每次重采样时的)特征数据,作用是为了绘制跟踪轨迹
vector<Point2f> fpts0,fpts1;// 保存当前帧和前一帧特征点位置vector<uchar> status; //特征点跟踪成功标志位
vector<float> errors;//跟踪时候区域误差和void featureGet(Mat &frame,Mat &gray,Mat &prev_frame,Mat &prev_gray,vector<Point2f> &initPoints,vector<Point2f> &fpts0,vector<Point2f> &fpts1);
void detectFeatures(Mat &inFrame, Mat &ingray, int addPoint);
void klTrackFeature();
void drawTrackLines();
//以上为声明全局变量int main(int argc, char** argv){//VideoCapture capture(0);识别摄像头VideoCapture capture; //实例化一个capture对象,对video进行每一帧采样capture.open("./V91017-133736.mp4");if(!capture.isOpened()){ //判断该目录下是否存在目标视频printf("Could not load video \n");return -1;}namedWindow("camera_input",CV_WINDOW_NORMAL); //创建一个显示窗口resizeWindow("camera_input",640,480);Mat frame;int i = 0;Mat R;Mat t;while(capture.read(frame)){//flip(frame,frame,1);featureGet(frame,gray,prev_frame,prev_gray,initPoints,fpts0,fpts1);//pose_estimation_2d2d (fpts0,fpts1,R,t);char c = waitKey(50);if (c==27){break;} i++;}waitKey(0);return 0;
} void featureGet(Mat &frame,Mat &gray,Mat &prev_frame,Mat &prev_gray,vector<Point2f> &initPoints,vector<Point2f> &fpts0,vector<Point2f> &fpts1){cvtColor(frame,gray,COLOR_BGR2GRAY); //把frame转换成灰度图赋值给grayif(fpts0.size() < FEATURE_NUMBER){ //如果现存的特征点数量小于规定值,则对当前帧进行重新特征提取给initpoint(因为每出现新的一帧,就会有特征点损失)detectFeatures(frame,gray,fpts0.size()); //从灰度图中识别出特征赋值给featuresfpts0.insert(fpts0.end(),features.begin(),features.end()); //把features中全部元素放到fpts[0]的结尾initPoints.insert(initPoints.end(),features.begin(),features.end()); //把features中全部元素放到initPoints的结尾}else{//printf("当前正在跟踪现有特征点\n");}if(prev_gray.empty()){gray.copyTo(prev_gray);}//find_feature_matches ( prev_gray, gray,dynamic_cast(fpts0),dynamic_cast(fpts1),matches );klTrackFeature();drawFeature(frame);//更新前一帧数据:把现在的帧赋值给前一帧gray.copyTo(prev_gray);frame.copyTo(prev_frame);imshow("camara_input",frame); //在之前创建的显示窗口显示当前帧图像}void detectFeatures(Mat &inFrame, Mat &ingray, int addPoint){double maxCorners = FEATURE_NUMBER;double qualitylevel = 0.01;double minDistance = 30; //两个特征点最小距离double blockSize = 3;double k = 0.04;goodFeaturesToTrack(ingray,features,maxCorners-addPoint,qualitylevel,minDistance,Mat(),blockSize,false,k);//cout<<"detect features:"<<features.size()<<endl;
}void drawFeature(Mat &inFrame){for (size_t t=0;t<fpts0.size();t++){ //???????????circle(inFrame,fpts0[t],2,Scalar(0,0,255),2,8,0);}
}void klTrackFeature(){ //不太懂啊//KLT光流法跟踪calcOpticalFlowPyrLK(prev_gray,gray,fpts0,fpts1,status,errors); //输入前一帧图像,输入后一帧图像,输入前一帧特征点,输出后一帧特征点int k=0;//特征点过滤for(int i=0;i<fpts1.size();i++){//double dist = abs(fpts0[i].x-fpts1[i].x) + abs(fpts0[i].y-fpts1[i].y);if(status[i]){//if(dist > 2 && status[i]){ //作用:过滤掉不动的点,和跟踪失败的点。status[i]表示第i个特征点还处于跟踪状态initPoints[k] = initPoints[i]; //删除损失跟踪点和不动的特征点fpts0[k++] = fpts1[i];  //保存跟踪特征点(和上一句话一个意思)//上一句不好理解,这么写fpts[1][k] = fpts[1][i];k++;}}//保存特征点并绘制跟踪轨迹initPoints.resize(k);fpts1.resize(k);drawTrackLines();std::swap(fpts1,fpts0); //之所以是交换,是因为现在一直在考察现有的特征点,
}void drawTrackLines(){for (size_t t=0;t<fpts1.size();t++){line(frame,initPoints[t],fpts1[t],Scalar(0,255,0),2,8,0);circle(frame,fpts1[t],2,Scalar(0,0,255),2,8,0);}
}//1.输入第一帧图片,保存到frame,pre_frame,gray,pre_gray中去
//2.把gray中识别的特征点加到iniPoints,fpts[0]输入第二帧图片,保存到frame,gray中去
//3.用KLT算法,得到fpts[1],过滤掉iniPoints,fpts[1]中运动量小的点和没有识别到光流的点,交换fpts[0],fpts[1],画出跟踪轨迹
//4.画出特征点
//5.把当前帧图像赋值给上一帧
//6.采样下一帧图片,如果特征点数量少于阙值,返回步骤2,否则返回步骤3

1.输入第一帧图片,保存到frame,pre_frame,gray,pre_gray中去
2.把gray中识别的特征点加到iniPoints,fpts[0]输入第二帧图片,保存到frame,gray中去
3.用KLT算法,得到fpts[1],过滤掉iniPoints,fpts[1]中运动量小的点和没有识别到光流的点,交换fpts[0],fpts[1],画出跟踪轨迹
4.画出特征点
5.把当前帧图像赋值给上一帧
6.采样下一帧图片,如果特征点数量少于阙值,返回步骤2,否则返回步骤3

CMakeLists如下,

cmake_minimum_required( VERSION 2.8 )
project( useKLT )# 添加c++ 11标准支持
set( CMAKE_CXX_FLAGS "-std=c++11" )
#set(CMAKE_BUILD_TYPE "Release")
#set(CMAKE_CXX_FLAGS "-o3")# 寻找OpenCV库
find_package( OpenCV 3.1 REQUIRED )# 添加头文件
include_directories( ${OpenCV_INCLUDE_DIRS} )
include_directories( "/usr/include/eigen3" )add_executable( useKLT useKLT.cpp )
# 链接OpenCV库
target_link_libraries( useKLT ${OpenCV_LIBS} )

由网上视频学习整理。

光流法在工程上的运用:

【SLAM】VINS-MONO解析——feature_tracker

KLT稀疏光流法跟踪特征点详解相关推荐

  1. 视觉SLAM笔记(42) 光流法跟踪特征点

    视觉SLAM笔记(42) 光流法跟踪特征点 1. 使用 TUM 公开数据集 2. 使用 LK 光流 1. 使用 TUM 公开数据集 准备了若干张数据集图像,存放在程序目录中的 VSLAM_note/0 ...

  2. 对于KLT稀疏光流法的理解

    VINS前端使用KLT稀疏光流跟踪算法(使用KLT特征点检测方法的LK跟踪算法)来跟踪抓取特征点(稀疏光流法只计算部分像素的运动,计算所有像素的称为稠密光流法) KLT中的角点检测方法是用于满足LK光 ...

  3. OpenCV4每日一练day14:光流法跟踪移动物体

    一.稠密光流法跟踪移动物体 例1 #include <opencv2/opencv.hpp> #include <iostream>using namespace cv; us ...

  4. 浅谈光流跟踪之KLT稀疏光流跟踪算法

    文章目录 0 简介 1 光流的三大假设条件 2 LK光流跟踪算法原理 3 LK-金字塔光流 3.1 金字塔创建 3.2 金字塔跟踪 4 KLT光流跟踪 5 Harris角点检测 6 Shi-Tomas ...

  5. opencv c++ 光流法、稀疏光流法、稠密光流法、均值迁移追踪(meanshift、camshift)

    1.概念 参考: (70条消息) 什么是光流法_张年糕慢慢走的博客-CSDN博客_光流法 (70条消息) 计算机视觉--光流法(optical flow)简介_T-Jhon的博客-CSDN博客_光流法 ...

  6. 跟踪算法(一)光流法跟踪

    COPY FROM:http://blog.csdn.net/crzy_sparrow/article/details/7407604 BTW:原文作者是我学习的榜样! 本文目录: 一.基于特征点的目 ...

  7. 使用方差阈值过滤(VarianceThreshold)进行特征选择、删除方差低于某一阈值的特征、详解及实战

    使用方差阈值过滤(VarianceThreshold)进行特征选择.删除方差低于某一阈值的特征.详解及实战 方差阈值(VarianceThreshold)法是一种过滤特征选择法. 我们有一组数值特性, ...

  8. t检验特征筛选详解及实战

    t检验特征筛选详解及实战 数据的种类 我们都知道,一般数据可以分为两类,即定量数据(数值型数据)和定性数据(非数值型数据),定性数据很好理解,例如人的性别,姓名这些都是定性数据.定量数据可以分为以下几 ...

  9. 使用RFECV、递归特征消除 (Recursive Feature Elimination)进行特征筛选详解及实战

    使用RFECV.递归特征消除 (Recursive Feature Elimination)进行特征筛选详解及实战 包装法,根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征. 所 ...

最新文章

  1. sem_我知道的关键词1
  2. MapReduce的shuffle阶段
  3. 数据处理——数据编码
  4. 架构师必备之最全最系统的 Android 界面性能调优资料
  5. PKIX path building failed
  6. oracle bpm 教学视频,oracle BPM直接更新流程
  7. 玩转Light Blue之添加设备信息
  8. Java编程输出你的年龄和姓名
  9. 关于:XP精简版装IIS 添加/删除windows组件中找不到IIS
  10. 什么是全文搜索引擎?
  11. iOS上线 ERROR ITMS-4238
  12. 怎么判断冠词用a还是an_冠词a/an/the:的用法和区别
  13. 什么是线程安全问题 及怎么解决线程安全问题
  14. 访韩家炜教授记录(部分)
  15. 如何找到winRE.wim (Win10无法重置电脑找 不到恢复环境,需要重装介质)
  16. 高速互联仿真-Spice模型和IBIS模型的区别
  17. 自动驾驶汽车如何有助于可持续移动规划?
  18. 四川大学计算机学院现代软件工程(双语 百度云,四川大学2012软件工程导论(双语) (A 闭 )...
  19. 一、JQuery选择器
  20. 程序员如何提高影响力 2.0

热门文章

  1. 进制转化(c 语言实现)
  2. 状态压缩初探(包含蓝桥算法训练 和为T,牛客 csl的校园卡)
  3. 三菱5U摆盘机程序六轴此程序包含组态
  4. 简历无亮点?应用之星教你72变!
  5. 从G_BEGIN_DECLS和 G_END_DECLS说起
  6. 2021年GameFi风口已来,带你解读链游平台DPK
  7. DbVisualizer9 解决中文乱码问题
  8. Qt Creator cuda动态并行工程配置
  9. CSS sprites原理,和优缺点
  10. 信息收集——根据图中信息找到图中的餐厅