赞
踩
【算法的步骤】
1、首先画出感兴趣区域
2、对进入感兴趣区域的车辆进行前灯的检测,跟踪和计数
感兴趣区域的划分,在视频处理中有着重要应用,在视频中标注感兴趣区域的方法:
暂停视频或者在视频流的第一帧中,画出感兴趣区域
#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
using namespace cv;
#include<iostream>
#include<vector>
using namespace std;
/*----定义鼠标事件--画矩形区域:作用当两个车灯----*/
//第一步:全局变量
bool drawing_box = false;
bool gotBox = false;
Rect box;
Point downPoint;
/*
void mouseRectHandler(int event, int x, int y, int flags, void *param)
{
switch (event)
{
case CV_EVENT_MOUSEMOVE:
if (drawing_box)
{
box.width = x - box.x;
box.height = y - box.y;
}
break;
case CV_EVENT_LBUTTONDOWN:
drawing_box = true;
box = Rect(x, y, 0, 0);
break;
case CV_EVENT_LBUTTONUP:
drawing_box = false;
gotBox = true;
if (box.width < 0)
{
box.x += box.width;
box.width *= -1;
}
if( box.height < 0 )
{
box.y += box.height;
box.height *= -1;
}
break;
default:
break;
}
}
*/
void mouseRectHandler(int event, int x, int y, int flags, void *param)
{
switch (event)
{
case CV_EVENT_MOUSEMOVE:
if (drawing_box)
{
//鼠标的移动到downPoint的右下角
if( x >=downPoint.x && y >= downPoint.y)
{
box.x = downPoint.x;
box.y = downPoint.y;
box.width = x - downPoint.x;
box.height = y - downPoint.y;
}
//鼠标的移动到downPoint的右上角
if( x >= downPoint.x && y <= downPoint.y)
{
box.x = downPoint.x;
box.y = y;
box.width = x - downPoint.x;
box.height = downPoint.y - y;
}
//鼠标的移动到downPoint的左上角
if( x <= downPoint.x && y <= downPoint.y)
{
box.x = x;
box.y = y;
box.width = downPoint.x - x;
box.height = downPoint.y - y;
}
//鼠标的移动到downPoint的左下角
if( x <= downPoint.x && y >= downPoint.y)
{
box.x = x;
box.y = downPoint.y;
box.width = downPoint.x -x;
box.height = y - downPoint.y;
}
}
break;
case CV_EVENT_LBUTTONDOWN:
//按下鼠标,代表可以可以开始画矩形
drawing_box = true;
//记录起点
downPoint = Point(x,y);
break;
case CV_EVENT_LBUTTONUP:
//松开鼠标,代表结束画矩形
drawing_box = false;
gotBox = true;
break;
default:
break;
}
}
int main(int argc,char*argv[])
{
//读取视频
VideoCapture video(argv[1]);
//判断视频是否打开
if( !video.isOpened())
return 0;
//视频中的第一帧
Mat firstFrame;
Mat frame;
//读取视频的第一帧
video>>frame;
//复制到firstFrame中
frame.copyTo(firstFrame);
//register
namedWindow("video",1);
setMouseCallback("video",mouseRectHandler,NULL);
//画感兴趣区域
while(!gotBox)
{
firstFrame.copyTo(frame);
rectangle(frame,box,Scalar(255,0,0),2);//画出感兴趣区域
imshow("video",frame);
if(waitKey(50) == 'q')//---------很重要
break;
}
//remove callback
setMouseCallback("video",NULL,NULL);
//视频继续
for(;;)
{
//读取视频
video>>frame;
//判断是否有当前帧
if(!frame.data)
break;
//画出感兴趣区域
rectangle(frame,box,Scalar(255,255,0),2);
imshow("video",frame);
if(waitKey(33) == 'q')
break;
}
return 0;
}
框定感兴趣区域之后开始检测,计数,完整代码如下:
#include<iostream>
using namespace std;
#include<string>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
//Trackbar控制的变量及该值的最大值
int thresh = 200;
const int MAX_THRESH = 255;
//Trackbar控制的函数
void thresh_callback(int,void*);
int w_h = 25;
const int MAX_W_H = 100;
int vehicleFrequency = 2;//这个值不能过于大,否则拍到的车辆里,没有车牌
const int MAX_VEHICLEFREQUENCY = 15;
//全局标量
Mat frame;//原视频流的帧
Mat grayFrame;//颜色空间转化
Mat binaryFrame;//二值化
Mat kernel;//进行形态学处理的核函数
Rect box_vehicle;
bool vehicleBool;//判断是否有车辆
//存储边缘
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Rect vehicleRect;//通过前灯检测,定位出来的车辆
/*----定义鼠标事件--画矩形区域:作用当两个车灯----*/
//第一步:全局变量
bool drawing_box = false;
bool gotBox = false;
Rect box;
Point downPoint;
void mouseRectHandler(int event, int x, int y, int flags, void *param)
{
switch (event)
{
case CV_EVENT_MOUSEMOVE:
if (drawing_box)
{
//鼠标的移动到downPoint的右下角
if( x >=downPoint.x && y >= downPoint.y)
{
box.x = downPoint.x;
box.y = downPoint.y;
box.width = x - downPoint.x;
box.height = y - downPoint.y;
}
//鼠标的移动到downPoint的右上角
if( x >= downPoint.x && y <= downPoint.y)
{
box.x = downPoint.x;
box.y = y;
box.width = x - downPoint.x;
box.height = downPoint.y - y;
}
//鼠标的移动到downPoint的左上角
if( x <= downPoint.x && y <= downPoint.y)
{
box.x = x;
box.y = y;
box.width = downPoint.x - x;
box.height = downPoint.y - y;
}
//鼠标的移动到downPoint的左下角
if( x <= downPoint.x && y >= downPoint.y)
{
box.x = x;
box.y = downPoint.y;
box.width = downPoint.x -x;
box.height = y - downPoint.y;
}
}
break;
case CV_EVENT_LBUTTONDOWN:
//按下鼠标,代表可以可以开始画矩形
drawing_box = true;
//记录起点
downPoint = Point(x,y);
break;
case CV_EVENT_LBUTTONUP:
//松开鼠标,代表结束画矩形
drawing_box = false;
gotBox = true;
break;
default:
break;
}
}
int main()
{
//视频流的输入
VideoCapture video("1.avi");
if( !video.isOpened())
return -1;
//得到形态学处理的kernel
kernel = getStructuringElement(MORPH_CROSS,Size(3,3),Point(-1,-1));
//register,注册鼠标事件
namedWindow("video",CV_WINDOW_AUTOSIZE);
setMouseCallback("video",mouseRectHandler,NULL);
//输出视频流,并同时画出感兴趣区域
for(;;)
{
video>>frame;
if(!frame.data)
break;
//控制阈值
createTrackbar("前灯检测:","video",&thresh,MAX_THRESH,thresh_callback);
thresh_callback( 0, 0 );//这一行很重要
//去除面积过小的
createTrackbar("面积:","video",&w_h,MAX_W_H,thresh_callback);
thresh_callback( 0, 0 );
//代表一辆车,如果出现的频数大于
createTrackbar("频数:","video",&vehicleFrequency,MAX_VEHICLEFREQUENCY,NULL);
//当得到box时,去除setMouseCallback
if(gotBox)
{
setMouseCallback("video",NULL,NULL);
break;
}
rectangle(frame,box,Scalar(255,0,0),2);//画出感兴趣区域
imshow("video",frame);
if(waitKey(33) == 'q')
break;
}
//用于跟踪算法和计数
bool currentVehicleBool = false;
bool previousVehicleBool = false;
int numberVehicle = 0;
//用于记录每一辆车的的帧数,避免是一闪而过的,可能不是车辆
int numberVehicleFrame = 1;
int currentVehicleNumber = 0;
int previousVehicleNumber = 0;
//以上画出感兴趣区域,以下可以判断是否为车辆
for(;;)
{
vehicleRect.width = 0;
vehicleRect.height = 0;
video >> frame;
if(!frame.data)
break;
//颜色空间转换
CV_Assert(frame.channels() == 3);
cvtColor(frame,grayFrame,COLOR_BGR2GRAY);
//控制阈值
createTrackbar("前灯检测:","video",&thresh,MAX_THRESH,thresh_callback);
thresh_callback( 0, 0 );//这一行很重要
//去除面积过小的
createTrackbar("面积:","video",&w_h,MAX_W_H,thresh_callback);
thresh_callback( 0, 0 );
createTrackbar("频数:","video",&vehicleFrequency,MAX_VEHICLEFREQUENCY,NULL);
//画出感兴趣区域
rectangle(frame,box,Scalar(255,255,0),2);
//画出检测到的前灯
rectangle(frame,vehicleRect,Scalar(0,255,0),2);
//判断vehicleRect和box是否相交,来判断是否有车辆
box_vehicle = box & vehicleRect;
//显示二值化
imshow("二值化",binaryFrame);
if(box_vehicle.width >0 && vehicleRect.height > 0)
{
currentVehicleBool = true;
if( previousVehicleBool ==false )
{
//代表这是第几辆车
numberVehicle++;
//记录当前帧的车辆的标号
currentVehicleNumber = numberVehicle;
}
//用于计数,该辆车出现的帧数
if( currentVehicleNumber == previousVehicleNumber )
{
numberVehicleFrame ++;
if( numberVehicleFrame == vehicleFrequency+1)
{
cout << "抓拍" << endl;
//imshow("抓拍",frame);//保存图片
}
}
}
else
{
currentVehicleBool = false;
//将归为1,重新计数
numberVehicleFrame = 1;
}
//记录上一帧的是否有车辆
previousVehicleBool = currentVehicleBool;
//记录上一帧,车辆的标号(number)
previousVehicleNumber = currentVehicleNumber;
//显示图片
imshow("video",frame);
cout<<currentVehicleNumber;
if(waitKey(33) == 'q')
break;
}
return 0;
}
void thresh_callback(int,void*)//得到新的vehicleRect
{
if(!grayFrame.data)
return;
//阈值处理
threshold(grayFrame,binaryFrame,double(thresh),255.0,THRESH_BINARY);
//均值滤波
medianBlur(binaryFrame,binaryFrame,5);
//形态学处理
morphologyEx(binaryFrame,binaryFrame,MORPH_OPEN,kernel,Point(-1,-1),7,BORDER_REPLICATE);
//存储边缘
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
//找到边缘,注意为什么先把binaryFrame克隆一遍
Mat tempBinaryFrame = binaryFrame.clone();
findContours( tempBinaryFrame,contours,hierarchy, CV_RETR_TREE , CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );//注意这个findContours中binaryImage既是输入又是输出
vector<vector<Point> > contours_poly( contours.size() );
//存储
vector<Rect> boundRect;
boundRect.clear();
for(int index = 0;index < contours.size(); index++)
{
approxPolyDP( Mat(contours[index]), contours_poly[index], 3, true );
Rect rect = boundingRect( Mat(contours_poly[index]) );
//做筛选(去除较小的w_h)
continue;
boundRect.push_back(rect);
}
//得到整个汽车前灯轮廓
for(int index = 0;index < boundRect.size() ;index++)
{
if(index ==0)
vehicleRect = boundRect[0];
else
vehicleRect = vehicleRect | boundRect[index];//得到最大的矩形
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。