一、 对鼠标选中目标运用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);
}