光流法+FAST特征点

转自http://blog.csdn.net/qianxin_dh/article/details/42810073

一.光流法回顾

       光流作为飞行昆虫对外界光学信息感知,处理的方式,其概念在1950年有Gibson首次提出,80年代初期Horn和Schunck以及Lucas和Kanade做了奠基性工作,之后光流法被广泛研究,很多种方法被相继提出。1994年,Barron等对当时的有代表性光流法进行了详细的分类和评价,对光流法的发展起到了关键性作用。Barron按照理论基础和数学方法的区别把光流法分成五类:基于偏微分(梯度)的方法,基于特征匹配法的方法,基于能量的方法,基于相位的方法,其中最常用的方法为基于偏微分的方法和基于特征匹配的方法。2011年,S.Baker等研究发现大多数的光流法都是对数据项和平滑项的和的优化,并参考Barron-Fleet的分类法,根据数据项和平滑项及系数的不同取法分亮度约束法,变分法,一阶法,二阶法,空间约束法等等,并建立了Middlebury Flow数据库,包含图像序列,真实光流和对光流算法的评价。

      根据光流计算的约束条件,可分为全局光流法局部光流法,前者的代表是Horn & Schunck(HS)法及其衍生方法,后者的代表是Lucas & Kanade(LK)法及其衍生方法。使用全局光流法直接利用了整幅图像的稠密光流,免去了提取“good feature”的过程,但是由于计算量过大,影响了算法的实时性。此外,全局光流法的全局约束也会使误差在整幅图像上传播,影响光流估计准确性。相比之下,局部光流法可以在计算光流之前提取特征点,利用这些特征点的稀疏光流代表整幅图像的稠密光流,可以同时提高光流的准确性并减少计算时间。Chaos对使用光流进行视觉导航的8种系统进行了统计,LK法由于其计算的简便性及时间消耗少而最为常用。生物学家也指出果蝇也是靠特征点和光流进行导航。因此,特征点的选取对于稀疏光流的运动估计非常关键。

       基于特征点的光流法只在第一帧提取特征点,然后计算特征点的光流,所以用于光流计算的特征点应该不仅可以代表图像信息,而且能够提高光流的准确性。传统的特征点是针对一副图像提取角点或纹理,如图像梯度的极值处以及Laplacian的零点,但它们可能是深度不连续点或是光滑表面上的亮度异常点,会导致光流计算不准确。SIFT或SURF特征点利用了高斯差分金字塔的局部极值点具有尺度不变性的特点,提取的特征点对图像信息具有很强的代表性。基于光流运动方程的Shi & Tomasi法提取的good feature,以包含两幅图像信息的局部邻域的矩阵的特征值为量度,易于利用光流进行跟踪,具有局部性和仿射不变形。

       

二.Fast特征点

         文章应该是《Machine Learning for high-speed corner detection》,FAST特征顾名思义,就是快,它快于现有其它角点的检测速度,在一些对实时性要求较高的条件下,可以考虑使用该特征。FAST特征是基于特征点周围的图像灰度值,检测候选特征点周围一圈的像素值,若该像素点圆形邻域圆周上有3/4的点和该像素点灰度值差足够大,则认为该像素点为一个特征点。如下入所示:


三.代码

       Fast特征和LK光流法相结合,实现对摄像头里运动物体的特征点跟踪。(配置:vs2008 + opencv2.3.1)


头文件:

  1. #include <opencv2/highgui/highgui.hpp>  
  2. #include <opencv2/core/core.hpp>  
  3. #include <opencv2/imgproc/imgproc.hpp>  
  4. #include <opencv2/features2d/features2d.hpp>  
  5. #include <opencv2/video/tracking.hpp>  
  6.   
  7. class FeatureTracker  
  8. {  
  9. private:  
  10.     cv::Mat gray;  //当前灰度图像  
  11.     cv::Mat gray_prev; //之前灰度图像  
  12.     //两幅图像间跟踪的特征点 0->1  
  13.     std::vector<cv::Point2f>points[2];  
  14.     //跟踪的点初始位置  
  15.     std::vector<cv::Point2f>initial;  
  16.     std::vector<cv::Point2f>features;       //检测到的特征  
  17.     std::vector<uchar> status;      //检测到的特征的状态  
  18.     std::vector<float> err;           //跟踪过程中的错误  
  19. public:  
  20.     FeatureTracker();  
  21.     ~FeatureTracker();  
  22.   
  23.     void process(cv::Mat& frame ,cv::Mat& output);  
  24.     void detectFeaturePoints(cv::Mat& frame);  
  25.     bool addNewPoints();  
  26.     bool acceptTrackedPoint(int i);  
  27.     void handleTrackedPoints(cv::Mat& frame,cv::Mat& output);  
  28. };  
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/video/tracking.hpp>

class FeatureTracker
{
private:
    cv::Mat gray;  //当前灰度图像
    cv::Mat gray_prev; //之前灰度图像
    //两幅图像间跟踪的特征点 0->1
    std::vector<cv::Point2f>points[2];
    //跟踪的点初始位置
    std::vector<cv::Point2f>initial;
    std::vector<cv::Point2f>features;       //检测到的特征
    std::vector<uchar> status;      //检测到的特征的状态
    std::vector<float> err;           //跟踪过程中的错误
public:
	FeatureTracker();
	~FeatureTracker();

	void process(cv::Mat& frame ,cv::Mat& output);
	void detectFeaturePoints(cv::Mat& frame);
	bool addNewPoints();
	bool acceptTrackedPoint(int i);
	void handleTrackedPoints(cv::Mat& frame,cv::Mat& output);
};


函数实现:

  1. #include "FeatureTracker.h"  
  2.   
  3. FeatureTracker:: FeatureTracker()  
  4. {  
  5. }  
  6.   
  7. FeatureTracker:: ~FeatureTracker()  
  8. {  
  9.   
  10. }  
  11.   
  12. void FeatureTracker::detectFeaturePoints(cv::Mat& frame)  
  13. {  
  14.     std::vector<cv::KeyPoint> keyPoints;  
  15.   
  16.     cv::FastFeatureDetector fast(10);  //检测阈值  
  17.     fast.detect(frame,keyPoints);  
  18.     features.clear();  
  19.   
  20.     for (int i=0;i<keyPoints.size();i++)  
  21.     {  
  22.         features.push_back(cv::Point2f(keyPoints[i].pt.x,keyPoints[i].pt.y));  
  23.     }  
  24. }  
  25.   
  26. bool FeatureTracker::addNewPoints()  
  27. {  
  28.     return points[0].size()<=10;  
  29. }  
  30.   
  31. bool FeatureTracker::acceptTrackedPoint(int i)  
  32. {  
  33.     return status[i] &&  
  34.         //如果移动  
  35.         (abs(points[0][i].x - points[1][i].x)+  
  36.         (abs(points[0][i].y - points[1][i].y))>2);  
  37. }  
  38.   
  39. void FeatureTracker::handleTrackedPoints(cv::Mat& frame,cv::Mat& output)  
  40. {  
  41.     for(int i=0;i<points[1].size();i++){  
  42.         //绘制直线和圆  
  43.         cv::line(output,  
  44.                     initial[i],                //初始位置  
  45.                     points[1][i],               //新位置  
  46.                     cv::Scalar(255,0,0));  
  47.         cv::circle(output,points[1][i],3,cv::Scalar(0,0,255),-1);  
  48.     }  
  49. }  
  50.   
  51. void FeatureTracker::process(cv::Mat& frame,cv::Mat& output)  
  52. {  
  53.     cv::cvtColor(frame,gray,CV_BGR2GRAY);  
  54.     frame.copyTo(output);  
  55.   
  56.     if (addNewPoints())  
  57.     {  
  58.         detectFeaturePoints(frame);  
  59.         points[0].insert(points[0].end(),features.begin(),features.end());  
  60.         initial.insert(initial.end(),features.begin(),features.end());  
  61.     }  
  62.   
  63.     if (gray_prev.empty())  
  64.         gray.copyTo(gray_prev);  
  65.   
  66.     //lk法跟踪特征点  
  67.     cv::calcOpticalFlowPyrLK(  
  68.         gray_prev,gray,        //两幅连续图像  
  69.         points[0],                //图1中的输入点坐标  
  70.         points[1],                //</span><span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size:12px;">图2中的输入点坐标</span></span><span style="font-size:14px;">  
  71.         status,                    //跟踪成功  
  72.         err);                     //跟踪错误  
  73.   
  74.     //遍历所有跟踪的点进行筛选  
  75.     int k=0;  
  76.     for(int i=0;i<points[1].size();i++){  
  77.         //是否需要保留该点  
  78.         if (acceptTrackedPoint(i))  
  79.         {  
  80.             //进行保留  
  81.             initial[k] = initial[i];  
  82.             points[1][k++] = points[1][i];  
  83.         }  
  84.     }  
  85.       
  86.     //去除不成功的点  
  87.     points[1].resize(k);  
  88.     initial.resize(k);  
  89.   
  90.     //处理接受的跟踪点  
  91.     handleTrackedPoints(frame,output);  
  92.   
  93.     //当前帧的点和图像变为前一帧的点和图像  
  94.     std::swap(points[1],points[0]);  
  95.     cv::swap(gray_prev,gray);  
  96. }  
#include "FeatureTracker.h"

FeatureTracker:: FeatureTracker()
{
}

FeatureTracker:: ~FeatureTracker()
{

}

void FeatureTracker::detectFeaturePoints(cv::Mat& frame)
{
	std::vector<cv::KeyPoint> keyPoints;

	cv::FastFeatureDetector fast(10);  //检测阈值
	fast.detect(frame,keyPoints);
	features.clear();

	for (int i=0;i<keyPoints.size();i++)
	{
		features.push_back(cv::Point2f(keyPoints[i].pt.x,keyPoints[i].pt.y));
	}
}

bool FeatureTracker::addNewPoints()
{
	return points[0].size()<=10;
}

bool FeatureTracker::acceptTrackedPoint(int i)
{
	return status[i] &&
		//如果移动
		(abs(points[0][i].x - points[1][i].x)+
		(abs(points[0][i].y - points[1][i].y))>2);
}

void FeatureTracker::handleTrackedPoints(cv::Mat& frame,cv::Mat& output)
{
	for(int i=0;i<points[1].size();i++){
		//绘制直线和圆
		cv::line(output,
			        initial[i],                //初始位置
					points[1][i],               //新位置
					cv::Scalar(255,0,0));
		cv::circle(output,points[1][i],3,cv::Scalar(0,0,255),-1);
	}
}

void FeatureTracker::process(cv::Mat& frame,cv::Mat& output)
{
	cv::cvtColor(frame,gray,CV_BGR2GRAY);
	frame.copyTo(output);

	if (addNewPoints())
	{
		detectFeaturePoints(frame);
		points[0].insert(points[0].end(),features.begin(),features.end());
		initial.insert(initial.end(),features.begin(),features.end());
	}

	if (gray_prev.empty())
		gray.copyTo(gray_prev);

	//lk法跟踪特征点
	cv::calcOpticalFlowPyrLK(
		gray_prev,gray,        //两幅连续图像
		points[0],                //图1中的输入点坐标
		points[1],                //</span><span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size:12px;">图2中的输入点坐标</span></span><span style="font-size:14px;">
		status,                    //跟踪成功
		err);                     //跟踪错误

	//遍历所有跟踪的点进行筛选
	int k=0;
	for(int i=0;i<points[1].size();i++){
		//是否需要保留该点
		if (acceptTrackedPoint(i))
		{
			//进行保留
			initial[k] = initial[i];
			points[1][k++] = points[1][i];
		}
	}
	
	//去除不成功的点
	points[1].resize(k);
	initial.resize(k);

	//处理接受的跟踪点
	handleTrackedPoints(frame,output);

	//当前帧的点和图像变为前一帧的点和图像
	std::swap(points[1],points[0]);
	cv::swap(gray_prev,gray);
}

主函数:

  1. // OpticlaTracking.cpp   
  2. //created by qianxin_dh   
  3.   
  4. #include "stdafx.h"  
  5. #include "FeatureTracker.h"  
  6.   
  7. using namespace cv ;  
  8. using namespace std;  
  9.   
  10.   
  11. const char* winname="LK  Tracking";  
  12.   
  13. int main()  
  14. {  
  15.     VideoCapture capture;  
  16.     capture.open(1);  
  17.   
  18.     namedWindow(winname,CV_WINDOW_AUTOSIZE);  
  19.   
  20.     Mat frame;  
  21.     Mat output;  
  22.     FeatureTracker lk;  
  23.   
  24.     while (capture>>frame)  
  25.     {  
  26.         lk.process(frame,output);  
  27.         imshow(winname, output);  
  28.         char c=waitKey(33);  
  29.         if (c==27) {  
  30.             break;  
  31.         }  
  32.     }  
  33.     return 0;  
  34. }  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值