您的位置:首页 > 运维架构

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

2016-08-10 18:24 453 查看
一、 对鼠标选中目标运用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 );

}

}









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

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

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

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

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

}



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  opencv 光流法