当前位置:   article > 正文

车辆的检测、跟踪和计数_跟踪计数

跟踪计数

【算法的步骤】
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;   
    } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162

划分区域之后视频这里写图片描述这里写图片描述
框定感兴趣区域之后开始检测,计数,完整代码如下:

#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];//得到最大的矩形
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235

检测结果视频

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/358348
推荐阅读
相关标签
  

闽ICP备14008679号