使用流光法实现物体跟踪

简介

  本篇讲解使用opencv提供的流光法算法接口,实现物体跟踪。范例代码为参考修改tvl1_optical_flow.cpp实现。

具体实现

实现代码

#include <iostream>
#include <fstream>
 
#include "opencv2/video/tracking.hpp"
#include "opencv2/highgui/highgui.hpp"
 
using namespace cv;
using namespace std;
 
inline bool isFlowCorrect(Point2f u)
{
    return !cvIsNaN(u.x) && !cvIsNaN(u.y) && fabs(u.y) < 1e9;
}
 
static Vec3b computeColor(float fx, float fy)
{
    static bool first = true;
 
    // relative lengths of color transitions:
    // these are chosen based on perceptual similarity
    // (e.g. one can distinguish more shades between red and yellow
    //  than between yellow and green)
    const int RY = 15;
    const int YG = 6;
    const int GC = 4;
    const int CB = 11;
    const int BM = 13;
    const int MR = 6;
    const int NCOLS = RY + YG + GC + CB + BM + MR;
    static Vec3i colorWheel[NCOLS];
 
    if (first){
        int k = 0;
 
        for (int i = 0; i < RY; ++i, ++k)
            colorWheel[k] = Vec3i(255, 255 * i / RY, 0);
 
        for (int i = 0; i < YG; ++i, ++k)
            colorWheel[k] = Vec3i(255 - 255 * i / YG, 255, 0);
 
        for (int i = 0; i < GC; ++i, ++k)
            colorWheel[k] = Vec3i(0, 255, 255 * i / GC);
 
        for (int i = 0; i < CB; ++i, ++k)
            colorWheel[k] = Vec3i(0, 255 - 255 * i / CB, 255);
 
        for (int i = 0; i < BM; ++i, ++k)
            colorWheel[k] = Vec3i(255 * i / BM, 0, 255);
 
        for (int i = 0; i < MR; ++i, ++k)
            colorWheel[k] = Vec3i(255, 0, 255 - 255 * i / MR);
 
        first = false;
    }
 
    const float rad = sqrt(fx * fx + fy * fy);
    const float a = atan2(-fy, -fx) / (float)CV_PI;
 
    const float fk = (a + 1.0f) / 2.0f * (NCOLS - 1);
    const int k0 = static_cast<int>(fk);
    const int k1 = (k0 + 1) % NCOLS;
    const float f = fk - k0;
 
    Vec3b pix;
 
    for (int b = 0; b < 3; b++)
    {
        const float col0 = colorWheel[k0][b] / 255.f;
        const float col1 = colorWheel[k1][b] / 255.f;
 
        float col = (1 - f) * col0 + f * col1;
 
        if (rad <= 1)
            col = 1 - rad * (1 - col); // increase saturation with radius
        else
            col *= .75; // out of range
 
        pix[2 - b] = static_cast<uchar>(255.f * col);
    }
 
    return pix;
}
 
static void drawOpticalFlow(const Mat_<Point2f>& flow, Mat& dst, float maxmotion = -1)
{
    dst.create(flow.size(), CV_8UC3);
    dst.setTo(Scalar::all(0));
 
    // determine motion range:
    float maxrad = maxmotion;
 
    if (maxmotion <= 0)
    {
        maxrad = 1;
        for (int y = 0; y < flow.rows; ++y)
        {
            for (int x = 0; x < flow.cols; ++x)
            {
                Point2f u = flow(y, x);
 
                if (!isFlowCorrect(u))
                    continue;
 
                maxrad = max(maxrad, sqrt(u.x * u.x + u.y * u.y));
            }
        }
    }
 
    for (int y = 0; y < flow.rows; ++y)
    {
        for (int x = 0; x < flow.cols; ++x)
        {
            Point2f u = flow(y, x);
 
            if (isFlowCorrect(u))
                dst.at<Vec3b>(y, x) = computeColor(u.x / maxrad, u.y / maxrad);
        }
    }
}
 
int main(int argc, const char* argv[])
{
	Mat frame0;
	Mat frame1;
	Mat_<Point2f> flow;
	Ptr<DenseOpticalFlow> tvl1 = createOptFlow_DualTVL1();
	Mat out;
 
	if (argc < 2){
		cerr << "Usage : " << argv[0] << "<video>" << endl;
		return -1;
	}
	VideoCapture cap;
	cap.open(argv[1]);
 
	while(1){
		cap >> frame0;
		if(frame0.empty()){
			cerr<< "video is over!!" << endl;
			break;
		}
		cvtColor(frame0, frame0, CV_BGR2GRAY);
		if(!frame1.empty()){
			const double start = (double)getTickCount();
			tvl1->calc(frame0, frame1, flow);
			const double timeSec = (getTickCount() - start) / getTickFrequency();
			cout << "calcOpticalFlowDual_TVL1 : " << timeSec << " sec" << endl;
			drawOpticalFlow(flow, out);
			imshow("out", out);
			imshow("src", frame0);
			waitKey(10);
		}
		frame0.copyTo(frame1);
	}
    waitKey();
 
    return 0;
}

代码讲解

  1、创建了一个DenseOpticalFlow实例,同时获得打开了需要跟踪处理的video视频到cap中。
        Ptr<DenseOpticalFlow> tvl1 = createOptFlow_DualTVL1();
	Mat out;
 
	if (argc < 2){
		cerr << "Usage : " << argv[0] << "<video>" << endl;
		return -1;
	}
	VideoCapture cap;
	cap.open(argv[1]);
  2、在循环中,不断的读取video的帧数据到frame0中,接着cvtColor将frame0中的数据,灰阶化。判断到存储前一帧数据为空,也就是表示
刚刚读取到第一帧数据时候,不进入处理函数中,直接跳过。最后将frame0中的帧数据,保存到frame1中。frame0进入下一次循环,获得新一帧
数据。
     while(1){
	cap >> frame0;
	if(frame0.empty()){
		cerr<< "video is over!!" << endl;
		break;
	}
	cvtColor(frame0, frame0, CV_BGR2GRAY);
	if(!frame1.empty()){
                ...........
                ...........
	}
	frame0.copyTo(frame1);
     }
  3、当检测到frame1保存了前一帧数据之后,进入到流光法计算中。首先获得当前时钟getTickCount。使用tvl1->calc分别传入当前
帧(frame0)和前一帧(frame1),将获得的位置偏移保存到flow中。接着计算出calc函数处理花费的时间,之后使用函数
drawOpticalFlow,利用flow中的位置偏移,根据偏移位置的方向和速度,从而在out图像,对应位置赋予不同的颜色和饱和度。最后将
当前帧图像和处理之后的out图像分别显示出来。
        const double start = (double)getTickCount();
	tvl1->calc(frame0, frame1, flow);
	const double timeSec = (getTickCount() - start) / getTickFrequency();
	cout << "calcOpticalFlowDual_TVL1 : " << timeSec << " sec" << endl;
	drawOpticalFlow(flow, out);
	imshow("out", out);
	imshow("src", frame0);
	waitKey(10);

效果演示

 对应的效果演示如下:
        

        
时间: 2024-08-02 07:16:14

使用流光法实现物体跟踪的相关文章

OpenCv_背景差分结合LK金字塔进行运动物体跟踪

前面我们看到通过光流法进行运动物体跟踪的实际例子,其实现的基本原理就是: 一.获取前一帧,然后转换为灰度图,利用cvGoodFeaturesToTrack 函数寻找这一帧视频流的强角点 二.获取当前帧,然后转换为灰度图,利用LK金字塔算法 cvCalcOpticalFlowPyrLK 函数结合第一帧寻找到的角点A,寻找当前帧的角点B 三.画出角点和运动轨迹 背景差分法进行运动物体检测的基本原理就是: 一.取前一帧的视频流作为运动背景 二.将当前帧的视频流中的每个像素与前一帧的每个像素做差,得出每

Emgu-WPF 激光雷达研究-移动物体跟踪2

原文:Emgu-WPF 激光雷达研究-移动物体跟踪2 初步实现了去燥跟踪,并用圆点标注障碍物 https://blog.csdn.net/u013224722/article/details/80780205 测试过程中发现,当存在两个障碍物相对于雷达扫描射线重叠时,距离教远的障碍物信息会丢失.即获取不到数据,不重叠时,重新检测到数据.但由于数据帧丢失,被算法判断为移除一个. 添加一个新的,造成跟踪失败或较大误差.如下图: 当障碍物重叠时,被遮挡的信息丢失,造成误处理(障碍物标记颜色改变---

OpenCV粒子滤波器用于物体跟踪

1.引言 这个项目是由俄亥俄州立大学(OSU)一位博士生所写,http://web.engr.oregonstate.edu/~hess/,这位博士在其个人主页上对该项目进行了如下描述: Object tracking is a tricky problem. A general, all-purpose object tracking algorithm must deal with difficulties like camera motion, erratic object motion,

基于粒子滤波的物体跟踪

先上图: Rob Hess(http://web.engr.oregonstate.edu/~hess/)实现的这个粒子滤波. 从代码入手,一下子就明白了粒子滤波的原理. 根据维基百科上对粒子滤波的介绍(http://en.wikipedia.org/wiki/Particle_filter),粒子滤波其实有很多变种,Rob Hess实现的这种应该是最基本的一种,Sampling Importance Resampling (SIR),根据重要性重采样. 算法原理的粗浅理解: 1)初始化阶段-提

目标跟踪之光流法---光流法简单介绍

光流的概念是Gibson在1950年首先提出来的.它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法.一般而言,光流是由于场景中前景目标本身的移动.相机的运动,或者两者的共同运动所产生的.其计算方法可以分为三类: (1)基于区域或者基于特征的匹配方法: (2)基于频域的方法: (3)基于梯度的方法: 简单来说,光流是空间运动物体在观测成像平面上的像素运

模式识别之目标跟踪---最简单的目标跟踪方法--------模板匹配与相关系数法

前言 模板匹配和相关系数法是目标跟踪的经典方法,它的优点有很多:简单准确,适用面广,抗噪性好,而且计算速度快.缺点是不能适应剧烈光照变化和目标剧烈形变. 所谓模板匹配法,就是指在一帧图像内寻找目标模板的位置,和模板最像的地方就是目标了.只要把全图的所有子区域和目标模板比较一下,找到最像目标模板的子区域,它就是目标的位置.如何度量子区域和目标模板的相似程度呢?最简单的办法就是计算这二者的相关系数. 相关系数 相关系数(r)是一种数学距离,可以用来衡量两个向量的相似程度.它起源于余弦定理:cos(A

运动跟踪之CMT算法

CMT(Clustering of Static-Adaptive Correspondences for Deformable Object Tracking),是一套比较新的跟踪算法,诞生于2014年,原名叫Consensus-based Tracking and Matching of Keypoints for Object Tracking ,当时在计算机视觉应用(Application of Computer Vision)的冬季会议上获得了最佳论文奖,随后于2015年发表在了CVP

运动目标跟踪算法综述

运动目标跟踪是视频监控系统中不可缺少的环节.在特定的场景中,有一些经典的算法可以实现比较好的目标跟踪效果.本文介绍了一般的目标跟踪算法,对几个常用的算法进行对比,并详细介绍了粒子滤波算法和基于轮廓的目标跟踪算法.最后简单介绍了目标遮挡的处理.多摄像头目标跟踪和摄像头运动下的目标跟踪. 一.一般的目标跟踪算法 一般将目标跟踪分为两个部分:特征提取.目标跟踪算法.其中提取的目标特征大致可以分为以下几种: 1) 以目标区域的颜色直方图作为特征,颜色特征具有旋转不变性,且不受目标物大小和形状的变化影响,

光流法与KLT

一 光流 光流的概念是Gibson在1950年首先提出来的.它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法.一般而言,光流是由于场景中前景目标本身的移动.相机的运动,或者两者的共同运动所产生的.其计算方法可以分为三类: (1)基于区域或者基于特征的匹配方法: (2)基于频域的方法: (3)基于梯度的方法: 简单来说,光流是空间运动物体在观测成像平面