基于opencv的L-K光流法跟踪运动目标

一、 对鼠标选中目标运用lk光流法做运动目标检测

//---------------------------------【头文件、命名空间包含部分】--------------------------

//描述:包含程序所使用的头文件和命名空间

//---------------------------------------------------------------------------------------------

#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "iostream"
#include "ctype.h"
#include "stdio.h"
#include "stdlib.h"

 using namespace cv;

using namespace std;

//-----------------------------------【全局变量声明】---------------------------------------

//描述:声明全局变量

//---------------------------------------------------------------------------------------------

string window_name = "optical flow tracking";

vector point1, point2;//point1特征点原来的位置,point2特征点新位置

bool left_mouse = false;

Point2f point;

Rect selection;//鼠标选取的矩形框

Mat gray;//当前灰度图 

Mat prevGray;//之前的灰度图 

Mat image;

const Scalar GREEN = Scalar(0,255,0);

Point tmpPoint;

Mat srcImage;

//-----------------------------------【全局函数声明】---------------------------------------

//描述:声明全局函数

//---------------------------------------------------------------------------------------------

void RGBhisting(Mat &srcImage);

//-----------------------------------【鼠标回调函数】---------------------------------------

//描述:鼠标框选待跟踪区域

//---------------------------------------------------------------------------------------------

static void onMouse( int event, int x, int y, int , void* ){

Mat mouse_show;

image.copyTo(mouse_show);

 if(event == CV_EVENT_LBUTTONDOWN){          //鼠标左键按下

 selection.x = x;

 selection.y = y;

left_mouse = true;

}else if(event == CV_EVENT_LBUTTONUP){      //鼠标左键抬起

rectangle(mouse_show, Point( selection.x,  selection.y), Point(x, y), GREEN, 2);

selection.width = abs(x - selection.x);

selection.height =abs(y - selection.y);

x = (selection.x + x) / 2;

y = ( selection.y + y) / 2;

point = Point2f((float)x, (float)y);

point1.clear();

point2.clear();

 point1.push_back(point);               //取框选区域中心点

  imshow(window_name, mouse_show);

left_mouse = false;

}else if((event == CV_EVENT_MOUSEMOVE) && (left_mouse == true)){         //鼠标移动

rectangle(mouse_show, Point(selection.x, selection.y), Point(x, y), GREEN, 2);

        imshow(window_name, mouse_show);

}

}

//-----------------------------------【main( )函数】----------------------------------------

//描述:控制台应用程序的入口函数,我们的程序从这里开始

//---------------------------------------------------------------------------------------------

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(0);

    if(!cap.isOpened())

{

        cout << "Could not initialize capturing...\n";

        return 0;

    }

 

    namedWindow(window_name, 1 );

    setMouseCallback( window_name, onMouse, 0 );       //设置鼠标回调函数

 

    for(;;){

        Mat frame;

        cap >> frame;

        if( frame.empty() )

            break;

        frame.copyTo(image);

       frame.copyTo(srcImage);

        cvtColor(image, gray, COLOR_BGR2GRAY);     //得到灰度图

        if((!point1.empty()))

{

            vector status;//特征点被成功跟踪的标志 

            vector 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-selection.width/2,tmpPoint.y+selection.height/2) ,Point(tmpPoint.x+selection.width/2,tmpPoint.y-selection.height/2),Scalar(255,0,0),3,8,0);

line(image, point1[0],tmpPoint, Scalar(255, 0,0),3);   //标注前后帧特征点之间的连线

   circle(image, tmpPoint, 3, Scalar(0, 0, 255), -1);     //划出当前帧的特征点

        }

 

        imshow(window_name, image);

waitKey(100);

把当前跟踪结果作为下一帧参考

        swap(point2, point1);

        swap(prevGray, gray);

RGBhisting(srcImage);

int c = waitKey(50);

if( (char)c == 27 )

{

break; 

    }

    return 0;

}

//-----------------------------------【RGBhisting(Mat& srcImage)函数】----------------

// 描述:RGB三色直方图绘制

//---------------------------------------------------------------------------------------------

void RGBhisting(Mat& srcImage)

{

    

    

    if (!srcImage.data)

    {

        cout<<"fail to load image"<<endl;

    }

    

    Mat histROI(srcImage,selection);

   //参数准备 

   int bins = 256;

int hist_size[] = {bins};

float range[] = { 0, 256 };

const float* ranges[] = { range};

MatND redHist,grayHist,blueHist;

int channels_r[] = {0};

if (left_mouse == false)

    {

//进行直方图的计算(红色分量部分)

int channels_r[] = {0};

       calcHist( &histROI, 1, channels_r, Mat(), //不使用掩膜

redHist, 1, hist_size, ranges,

true, false );

//进行直方图的计算(绿色分量部分)

int channels_g[] = {1};

calcHist( &histROI, 1, channels_g, Mat(), // do not use mask

grayHist, 1, hist_size, ranges,

true, // the histogram is uniform

false );

//进行直方图的计算(蓝色分量部分)

int channels_b[] = {2};

calcHist( &histROI, 1, channels_b, Mat(), // do not use mask

blueHist, 1, hist_size, ranges,

true, // the histogram is uniform

false );

//-----------------------绘制出三色直方图------------------------

//参数准备

double maxValue_red,maxValue_green,maxValue_blue;

minMaxLoc(redHist, 0, &maxValue_red, 0, 0);

minMaxLoc(grayHist, 0, &maxValue_green, 0, 0);

minMaxLoc(blueHist, 0, &maxValue_blue, 0, 0);

int scale = 1;

int histHeight=256;

Mat histImage = Mat::zeros(histHeight,bins*3, CV_8UC3);

//正式开始绘制

for(int i=0;i

{

//参数准备

float binValue_red = redHist.at(i); 

float binValue_green = grayHist.at(i);

float binValue_blue = blueHist.at(i);

int intensity_red = cvRound(binValue_red*histHeight/maxValue_red);  //要绘制的高度

int intensity_green = cvRound(binValue_green*histHeight/maxValue_green);  //要绘制的高度

int intensity_blue = cvRound(binValue_blue*histHeight/maxValue_blue);  //要绘制的高度

//绘制红色分量的直方图

rectangle(histImage,Point(i*scale,histHeight-1),

Point((i+1)*scale - 1, histHeight - intensity_red),

CV_RGB(255,0,0));

//绘制绿色分量的直方图

rectangle(histImage,Point((i+bins)*scale,histHeight-1),

Point((i+bins+1)*scale - 1, histHeight - intensity_green),

CV_RGB(0,255,0));

//绘制蓝色分量的直方图

rectangle(histImage,Point((i+bins*2)*scale,histHeight-1),

Point((i+bins*2+1)*scale - 1, histHeight - intensity_blue),

CV_RGB(0,0,255));

}

//在窗口中显示出绘制好的直方图

imshow( "图像的RGB直方图", histImage );

}

}

二、利用goodFeaturesToTrack函数得到图像中的强边界作为跟踪的特征点,运用lk光流法做运动目标检测

//---------------------------------【头文件、命名空间包含部分】--------------------------

//描述:包含程序所使用的头文件和命名空间

//---------------------------------------------------------------------------------------------

#include "opencv2/video/video.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/core/core.hpp"
#include "iostream"
#include "cstdio"

using namespace std;

using namespace cv;

//-----------------------------------【全局函数声明】---------------------------------------

//描述:声明全局函数

//---------------------------------------------------------------------------------------------

void tracking(Mat &frame, Mat &output);

bool addNewPoints();

bool acceptTrackedPoint(int i);

//-----------------------------------【全局变量声明】---------------------------------------

//描述:声明全局变量

//---------------------------------------------------------------------------------------------

string window_name = "optical flow tracking";

Mat gray;// 当前图片

Mat gray_prev;// 预测图片

vector points[2];// point0为特征点的原来位置,point1为特征点的新位置

vector initial;// 初始化跟踪点的位置

vector features;// 检测的特征

int maxCount = 500;// 检测的最大特征数

double qLevel = 0.01;// 特征检测的等级

double minDist = 10.0;// 两特征点之间的最小距离

vector status;// 跟踪特征的状态,特征的流发现为1,否则为0

vector err;

//-----------------------------------【main( )函数】----------------------------------------

//描述:控制台应用程序的入口函数,我们的程序从这里开始

//---------------------------------------------------------------------------------------------

int main()

{

Mat frame;

Mat result;

VideoCapture capture(0);

if(capture.isOpened())// 摄像头读取文件开关

{

while(true)

{

capture >> frame;

if(!frame.empty())

tracking(frame, result);

}

else

printf(" --(!) No captured frame -- Break!");

break;

}

int c = waitKey(50);

if( (char)c == 27 )

{

break; 

}

}

return 0;

}

//---------------------------------------------------------------------------------------------

// function: tracking

// brief: 跟踪

// parameter: frame输入的视频帧

//  output 有跟踪结果的视频帧

// return: void

//---------------------------------------------------------------------------------------------

void tracking(Mat &frame, Mat &output)

{

cvtColor(frame, gray, CV_BGR2GRAY);

frame.copyTo(output);

// 添加特征点

if (addNewPoints())

{

goodFeaturesToTrack(gray, features, maxCount, qLevel, minDist);

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);

}

// l-k光流法运动估计

calcOpticalFlowPyrLK(gray_prev, gray, points[0], points[1], status, err);

// 去掉一些不好的特征点

int k = 0;

for (size_t i=0; i

{

if (acceptTrackedPoint(i))

{

initial[k] = initial[i];

points[1][k++] = points[1][i];

}

}

points[1].resize(k);

initial.resize(k);

// 显示特征点和运动轨迹

for (size_t i=0; i

{

line(output, initial[i], points[1][i], Scalar(0, 0, 255));

circle(output, points[1][i], 3, Scalar(0, 255, 0), -1);

}

// 把当前跟踪结果作为下一帧参考

swap(points[1], points[0]);

swap(gray_prev, gray);

imshow(window_name, output);

}

//---------------------------------------------------------------------------------------------

// function: addNewPoints

// brief: 检测新点是否应该被添加

// parameter:

// return: 是否被添加标志

//---------------------------------------------------------------------------------------------

bool addNewPoints()

{

return points[0].size() <= 10;

}

//---------------------------------------------------------------------------------------------

// function: acceptTrackedPoint

// brief: 决定哪些跟踪点被接受

// parameter:

// return:

//---------------------------------------------------------------------------------------------

bool 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);

}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值