opencv实现跟踪鼠标选取的目标

简介

  本篇讲解opencv video鼠标选中的物体跟踪,使用的是opencv提供的calcOpticalFlowPyrLK。

calcOpticalFlowPyrLK介绍

  void 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 );
    prevImg:前一帧video图像。
    nextImg:当前video图像。
    prevPts:前一帧video图像中被跟踪的坐标点。
    nextPts:prevPts保存的坐标点,在当前帧video图像中计算出来的对应坐标,也就是跟踪到的坐标点。
    winSize:在每层的搜索窗口的大小。
    criteria:算法递归停止的条件。
    。。。。。

具体实现

实现代码

#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
 
#include <iostream>
#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
 
using namespace cv;
using namespace std;
 
vector<Point2f> point1, point2;
bool left_mouse = false;
Point2f point;
int pic_info[4];
Mat gray, prevGray, image;
const Scalar GREEN = Scalar(0,255,0);
int rect_width = 0, rect_height = 0;
Point tmpPoint;
 
static void onMouse( int event, int x, int y, int /*flags*/, void* /*param*/ ){
	Mat mouse_show;
	image.copyTo(mouse_show);
 
	if(event == CV_EVENT_LBUTTONDOWN){
		pic_info[0] = x;
		pic_info[1] = y;
		left_mouse = true;
	}else if(event == CV_EVENT_LBUTTONUP){
		rectangle(mouse_show, Point(pic_info[0], pic_info[1]), Point(x, y), GREEN, 2);
		rect_width = <a href="http://www.opengroup.org/onlinepubs/%3Cspan%20class=" nu19"="" style="text-decoration: none; color: rgb(11, 0, 128); background-image: none; background-position: initial initial; background-repeat: initial initial;">009695399/functions/abs.html">abs(x - pic_info[0]);
		rect_height = <a href="http://www.opengroup.org/onlinepubs/%3Cspan%20class=" nu19"="" style="text-decoration: none; color: rgb(11, 0, 128); background-image: none; background-position: initial initial; background-repeat: initial initial;">009695399/functions/abs.html">abs(y - pic_info[1]);
		x = (pic_info[0] + x) / 2;
		y = (pic_info[1] + y) / 2;
		point = Point2f((float)x, (float)y);
		point1.clear();
		point2.clear();
        point1.push_back(point);
        imshow("LK Demo", mouse_show);
		left_mouse = false;
	}else if((event == CV_EVENT_MOUSEMOVE) && (left_mouse == true)){
		rectangle(mouse_show, Point(pic_info[0], pic_info[1]), Point(x, y), GREEN, 2);
        imshow("LK Demo", mouse_show);
	}
}
 
int main( int argc, char** argv )
{
    VideoCapture cap;
    TermCriteria termcrit(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 20, 0.03); //迭代算法的终止条件
    Size winSize(31,31);
 
    cap.open(argv[1]);
    if(!cap.isOpened()){
        cout << "Could not initialize capturing...\n";
        return 0;
    }
 
    namedWindow( "LK Demo", 1 );
    setMouseCallback( "LK Demo", onMouse, 0 );
 
    for(;;){
        Mat frame;
        cap >> frame;
        if( frame.empty() )
            break;
        frame.copyTo(image);
        cvtColor(image, gray, COLOR_BGR2GRAY);
        if((!point1.empty())){
            vector<uchar> status;
            vector<float> err;
            if(prevGray.empty())
                gray.copyTo(prevGray);
            calcOpticalFlowPyrLK(prevGray, gray, point1, point2, status, err, winSize,
                                 3, termcrit, 0, 0.001); //使用金字塔Lucas&Kanade方法计算一个稀疏特征集的光流
			tmpPoint = point2[0];
			rectangle(image, Point(tmpPoint.x - 20, tmpPoint.y - 20), Point(tmpPoint.x + 20, tmpPoint.y + 20), GREEN, 2);
        }
 
        imshow("LK Demo", image);
		waitKey(100);
        std::swap(point2, point1);
        cv::swap(prevGray, gray);
    }
    return 0;
}

代码讲解

  1、首先设置了算法calcOpticalFlowPyrLK将会使用到的递归停止条件(termcrit),关于termcrit的具体讲解,可以看这里有具体讲解:
http://blog.csdn.net/yang_xian521/article/details/6905244 ,接着打开视频文件,句柄保存在cap中。然后设置了显示窗口,已经它的鼠标响应函数。
 VideoCapture cap;
    TermCriteria termcrit(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 20, 0.03); //迭代算法的终止条件
    Size winSize(31,31);
 
    cap.open(argv[1]);
    if(!cap.isOpened()){
        cout << "Could not initialize capturing...\n";
        return 0;
    }
 
    namedWindow( "LK Demo", 1 );
    setMouseCallback( "LK Demo", onMouse, 0 );
  2、鼠标响应函数,主要做的就是,在当前video帧中画一个矩形,然后计算出该矩形的中心位置坐标,保存到point1中。这个位置坐标就是在
calcOpticalFlowPyrLK算法中用来跟踪的点。
static void onMouse( int event, int x, int y, int /*flags*/, void* /*param*/ ){
	Mat mouse_show;
	image.copyTo(mouse_show);
 
	if(event == CV_EVENT_LBUTTONDOWN){
		pic_info[0] = x;
		pic_info[1] = y;
		left_mouse = true;
	}else if(event == CV_EVENT_LBUTTONUP){
		rectangle(mouse_show, Point(pic_info[0], pic_info[1]), Point(x, y), GREEN, 2);
		rect_width = <a href="http://www.opengroup.org/onlinepubs/%3Cspan%20class=" nu19"="" style="text-decoration: none; color: rgb(11, 0, 128); background-image: none; background-position: initial initial; background-repeat: initial initial;">009695399/functions/abs.html">abs(x - pic_info[0]);
		rect_height = <a href="http://www.opengroup.org/onlinepubs/%3Cspan%20class=" nu19"="" style="text-decoration: none; color: rgb(11, 0, 128); background-image: none; background-position: initial initial; background-repeat: initial initial;">009695399/functions/abs.html">abs(y - pic_info[1]);
		x = (pic_info[0] + x) / 2;
		y = (pic_info[1] + y) / 2;
		point = Point2f((float)x, (float)y);
		point1.clear();
		point2.clear();
        point1.push_back(point);
        imshow("LK Demo", mouse_show);
		left_mouse = false;
	}else if((event == CV_EVENT_MOUSEMOVE) && (left_mouse == true)){
		rectangle(mouse_show, Point(pic_info[0], pic_info[1]), Point(x, y), GREEN, 2);
        imshow("LK Demo", mouse_show);
	}
}
  3、当用户还没有鼠标框选跟踪目标时候,软件会不断的读取出video的数据,保存到frame中,接着copy一份当前帧数据到gray中,并将gray中的
图像灰阶化,然后显示出video frame数据。最后交换了point2和point1中的坐标信息和保存了当前灰阶化后的帧率到prevGray中。
    for(;;){
        Mat frame;
        cap >> frame;
        if( frame.empty() )
            break;
        frame.copyTo(image);
        cvtColor(image, gray, COLOR_BGR2GRAY);
        ...........
        imshow("LK Demo", image);
		waitKey(100);
        std::swap(point2, point1);
        cv::swap(prevGray, gray);
    }
  4、最后当用户框选了跟踪目标之后,也就是point1不为空之后,开始用calcOpticalFlowPyrLK跟踪计算,注意传入该函数的参数:prevGray相当于
之前保存的前一帧的数据;gray是当前帧数据;point1是前一帧中被跟踪的目标位置;point2是计算出来的被跟踪目标在当前帧的位置。
  最后用计算出来的在当前帧中,跟踪目标坐标point2作为中心,在当前帧中画出一个40X40的矩形作为标记,最后显示出来。
        if((!point1.empty())){
            vector<uchar> status;
            vector<float> err;
            if(prevGray.empty())
                gray.copyTo(prevGray);
            calcOpticalFlowPyrLK(prevGray, gray, point1, point2, status, err, winSize,
                                 3, termcrit, 0, 0.001); //使用金字塔Lucas&Kanade方法计算一个稀疏特征集的光流
			tmpPoint = point2[0];
			rectangle(image, Point(tmpPoint.x - 20, tmpPoint.y - 20), Point(tmpPoint.x + 20, tmpPoint.y + 20), GREEN, 2);
        }

效果演示

  对应的效果演示如下:
                                        
时间: 2024-08-22 10:16:25

opencv实现跟踪鼠标选取的目标的相关文章

如何用OpenCV跟踪鼠标操作

转载:如何用OpenCV跟踪鼠标操作 http://blog.skyoung.org/2014/05/01/how-to-track-mouse/ 在视频第一帧手动标记出目标的位置是在线视觉跟踪中最基本的一个操作,实现这个操作需要检测鼠标的移动和点击事件.OpenCV提供了setMouseCallback这个函数来响应鼠标的动作,并返回鼠标在绑定窗口上的坐标位置.下面就这个函数的使用做一个简单的介绍. 首先,setMouseCallback的C++函数声明如下: 1 void onMouse(i

用opencv读取图像鼠标点的像素,更正一个Bug

作者:skyseraph 出处:http://www.cnblogs.com/skyseraph/ 以下代码在网上流传很广. 不过,调试运行之后发现,功能是正确的,但是内存很快就耗尽,导致死机.经过查找,加上: cvReleaseImage(&img1);    //释放源图像占用的内存 这一行是我(szliug)加的,否则内存很快就会耗尽,会死机的. 之后运行正常. /*===============================================// 功能:OpenCV Ut

关于Unity中鼠标选取物体的解决方案

今天修改了之前写的飞机大战的代码,原来的不足之处是点击屏幕的任意一点都可以移动飞机,也就是没有检测鼠标到底有没有点到飞机上. 我先是用之前的3D拾取技术,发现没有反应,才意识到我这个plane飞机节点挂载的是Box Collier2D的碰撞器组件,不是Box Collier,3D射线拾取技术在2D游戏里面还用不了. 后来我百度了一下,才知道用UGUI写的2D游戏用鼠标选取物体不用射线检测,要用事件系统.但是我不会用OnMouseEnter()和OnPointerEnter(),所以还是想用射线来

VB6/VBA中跟踪鼠标移出窗体控件事件(类模块成员函数指针CHooker类应用)

前几天发了一篇博文,是关于获取VB类模块成员函数指针的内容(http://www.cnblogs.com/alexywt/p/5880993.html):今天我就发一下我的应用实例. VB中默认是没有鼠标移出事件响应的,而这个事件其实在项目开发中,实用性很强,很多时候需要在鼠标移出窗体或控件时做些事情:没有这个事件会感觉很费力: 今天我所说的实际案例就是,在窗体上,设计一个SplitterBar控件,窗体的最终用户使用这个控件可以在运行程序时任意调整其内部控件大小. 我在第二篇参考博文作者开发的

OpenCV中响应鼠标消息 (转)

1 #include <cv.h> 2 #include <highgui.h> 3 #include <stdio.h> 4 5 #pragma comment(lib,"C:\\Program Files\\OpenCV1.0\\lib\\cv.lib") 6 #pragma comment(lib,"C:\\Program Files\\OpenCV1.0\\lib\\cxcore.lib") 7 #pragma comme

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

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

opencv视频跟踪2

在前面的报告中我们实现了用SURF算法计算目标在移动摄像机拍摄到的视频中的位置.由于摄像机本身像素的限制,加之算法处理时间会随着图像质量的提高而提高,实际实验发现在背景复杂的情况下,结果偏差可能会很大. 本次改进是预备在原先检测到的特征点上加上某种限制条件,以提高准确率. 问题:如何判定检测到的特征点是否是我们需要的点(也就是目标区域上的点)? 可行方案:用形态学找出目标的大致区域,然后对特征点判定. 特征点(SURF算法或者其他的算法)已有,我们来一步步实现找到目标大致区域. 下图假设为视频中

OpenCV之响应鼠标(四):在图像上绘制出矩形并标出起点的坐标

涉及到两方面的内容:1. 用鼠标画出矩形.2.在图像上绘制出点的坐标 用鼠标绘制矩形,涉及到鼠标的操作,opencv中有鼠标事件的介绍.需要用到两个函数:回调函数CvMouseCallback和注册回调函数cvSetMouseCallback. 当回调函数被调用时,opencv会传入合适的值,当鼠标有动作时,有所反应,比如画线,描点. void CvMouseCallback(int event,int x,int y,int flags,void * param); event 为鼠标事件类型

OpenCV中响应鼠标信息

转自:http://blog.csdn.net/haihong84/article/details/6599838 程序代碼如下: #include <cv.h>#include <highgui.h>#include <stdio.h> void onMouse(int event,int x,int y,int flags,void* param ); int main(int argc, char** argv){     CvCapture *capture;