• opencv学习之路(37)、运动物体检测(二)


    一、运动物体轮廓椭圆拟合及中心

     1 #include "opencv2/opencv.hpp"
     2 #include<iostream>
     3 using namespace std;
     4 using namespace cv;
     5 
     6 Mat MoveDetect(Mat frame1, Mat frame2)
     7 {
     8     Mat result = frame2.clone();
     9     Mat gray1, gray2;
    10     cvtColor(frame1, gray1, CV_BGR2GRAY);
    11     cvtColor(frame2, gray2, CV_BGR2GRAY);
    12 
    13     Mat diff;
    14     absdiff(gray1, gray2, diff);
    15     imshow("absdiss", diff);
    16     threshold(diff, diff, 45, 255, CV_THRESH_BINARY);
    17     imshow("threshold", diff);
    18  
    19     Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
    20     Mat element2 = getStructuringElement(MORPH_RECT, Size(25, 25));
    21     erode(diff, diff, element);
    22     imshow("erode", diff);
    23  
    24     dilate(diff, diff, element2);
    25     imshow("dilate", diff);
    26 
    27     vector<vector<Point>> contours;
    28     vector<Vec4i> hierarcy;
    29     //画椭圆及中心
    30     findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    31     cout<<"num="<<contours.size()<<endl;
    32     vector<RotatedRect> box(contours.size());
    33     for(int i=0; i<contours.size(); i++)
    34     {
    35         box[i] = fitEllipse(Mat(contours[i]));
    36         ellipse(result, box[i], Scalar(0, 255, 0), 2, 8);    
    37         circle(result, box[i].center, 3, Scalar(0, 0, 255), -1, 8);
    38     }    
    39     return result;    
    40 }
    41 
    42 void main()
    43 {     
    44     VideoCapture cap("E://man.avi");
    45     if(!cap.isOpened()) //检查打开是否成功
    46          return;
    47     Mat frame;
    48     Mat result;
    49     Mat background;
    50     int count=0;
    51     while(1)
    52     {
    53         cap>>frame;
    54         if(frame.empty())
    55             break;
    56         else{            
    57             count++;
    58             if(count==1)
    59                  background = frame.clone(); //提取第一帧为背景帧
    60             imshow("video", frame);
    61             result = MoveDetect(background, frame);
    62             imshow("result", result);
    63             if(waitKey(50)==27)
    64                break;
    65         }
    66     }
    67     cap.release();  
    68 }

    和上一篇文章代码的不同点在30-38行,天台行人视频适合用背景减法处理,自行车视频适合帧差法处理

    二、滤波方法去除噪声

     上篇文章中使用腐蚀膨胀消除噪声,这次使用滤波方法去除噪声

    中值滤波

      //二值化后使用中值滤波+膨胀
      Mat element = getStructuringElement(MORPH_RECT, Size(11, 11)); medianBlur(diff, diff, 5);//中值滤波 imshow("medianBlur", diff); dilate(diff, diff, element); imshow("dilate", diff);

    均值滤波

    #include "opencv2/opencv.hpp"
    #include<iostream>
    using namespace std;
    using namespace cv;
    
    //int to string helper function
    string intToString(int number)
    {
        stringstream ss;
        ss << number;
        return ss.str();
    }
    
    Mat MoveDetect(Mat background, Mat img)
    {
        Mat result = img.clone();
        Mat gray1, gray2;
        cvtColor(background, gray1, CV_BGR2GRAY);
        cvtColor(img, gray2, CV_BGR2GRAY);
    
        Mat diff;
        absdiff(gray1, gray2, diff);
        threshold(diff, diff, 20, 255, CV_THRESH_BINARY);
        imshow("threshold", diff);
        blur(diff, diff, Size(10, 10));//均值滤波
        imshow("blur", diff);
    
        vector<vector<Point>> contours;  
        vector<Vec4i> hierarcy;
        findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE); //查找轮廓
        vector<Rect> boundRect(contours.size()); //定义外接矩形集合
        //drawContours(img2, contours, -1, Scalar(0, 0, 255), 1, 8);  //绘制轮廓
        int x0=0, y0=0, w0=0, h0=0;
        for(int i=0; i<contours.size(); i++)
        {
            boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形
        
            x0 = boundRect[i].x;  //获得第i个外接矩形的左上角的x坐标
            y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
            w0 = boundRect[i].width; //获得第i个外接矩形的宽度
            h0 = boundRect[i].height; //获得第i个外接矩形的高度
            //rectangle(result, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
            circle(result, Point(x0+w0/2, y0+h0/2), 15, Scalar(0, 255, 0), 2, 8);
            line(result, Point(x0+w0/2-15, y0+h0/2), Point(x0+w0/2+15, y0+h0/2), Scalar(0, 255, 0), 2, 8);
            line(result, Point(x0+w0/2, y0+h0/2-10), Point(x0+w0/2, y0+h0/2+15), Scalar(0, 255, 0), 2, 8);
            putText(result,"(" + intToString(x0+w0/2)+","+intToString(y0+h0/2)+")",Point(x0+w0/2+15, y0+h0/2), 1, 1,Scalar(255,0,0),2);
        }
        return result;
    }
    
    void main()
    {     
        VideoCapture cap("E://ball.avi");
        if(!cap.isOpened()) //检查打开是否成功
             return;
        Mat frame;
        Mat result;
        Mat background;
        int count=0;
        while(1)
        {
            cap>>frame;
            if(frame.empty())
                break;
            else{            
                count++;
                if(count==1)
                     background = frame.clone(); //提取第一帧为背景帧
                imshow("video", frame);
                result = MoveDetect(background, frame);
                imshow("result", result);
                if(waitKey(50)==27)
                   break;
            }
        }
        cap.release();  
    }

    三、轮廓筛选去除噪声(效果挺好的)

        //其余代码相同
        int x0=0, y0=0, w0=0, h0=0;
        for(int i=0; i<contours.size(); i++)
        {
            boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形
            
            x0 = boundRect[i].x;  //获得第i个外接矩形的左上角的x坐标
            y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
            w0 = boundRect[i].width; //获得第i个外接矩形的宽度
            h0 = boundRect[i].height; //获得第i个外接矩形的高度
            //筛选
            if(w0>30 && h0>30)
                rectangle(result, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
        }    

    四、运动轨迹绘制

    #include "opencv2/opencv.hpp"
    #include<iostream>
    using namespace std;
    using namespace cv;
    
    Point center;
    Point fre_center;//存储前一帧中心坐标
    int num=0;
    vector<Point> points;
    
    Mat MoveDetect(Mat background, Mat img)
    {
        Mat result = img.clone();
        Mat gray1, gray2;
        cvtColor(background, gray1, CV_BGR2GRAY);
        cvtColor(img, gray2, CV_BGR2GRAY);
    
        Mat diff;
        absdiff(gray1, gray2, diff);
        imshow("absdiss", diff);
        threshold(diff, diff, 45, 255, CV_THRESH_BINARY);
        imshow("threshold", diff);
     
        Mat element = getStructuringElement(MORPH_RECT, Size(1, 1));
        Mat element2 = getStructuringElement(MORPH_RECT, Size(9, 9));
        erode(diff, diff, element);
        imshow("erode", diff);
        dilate(diff, diff, element2);
        imshow("dilate", diff);
    
        vector<vector<Point>> contours;  
        vector<Vec4i> hierarcy;
        findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE); //查找轮廓
        vector<Rect> boundRect(contours.size()); //定义外接矩形集合
        //drawContours(img2, contours, -1, Scalar(0, 0, 255), 1, 8);  //绘制轮廓
        vector<RotatedRect> box(contours.size());
        int x0=0, y0=0, w0=0, h0=0;
        for(int i=0; i<contours.size(); i++)
        {
            boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形
            
            x0 = boundRect[i].x;  //获得第i个外接矩形的左上角的x坐标
            y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
            w0 = boundRect[i].width; //获得第i个外接矩形的宽度
            h0 = boundRect[i].height; //获得第i个外接矩形的高度
            if(w0>30 && h0>30)//筛选长宽大于30的轮廓
            {
                num++;
                //rectangle(result, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
                box[i] = fitEllipse(Mat(contours[i]));
                ellipse(result, box[i], Scalar(255, 0, 0), 2, 8);            //椭圆轮廓
                circle(result, box[i].center, 3, Scalar(0, 0, 255), -1, 8); //画中心
                center = box[i].center;//当前帧的中心坐标
                points.push_back(center);//中心塞进points向量集
                if(num !=1)
                {
                    //line(result, fre_center, center, Scalar(255, 0, 0), 2, 8);
                    for(int j=0; j<points.size()-1; j++)
                        line(result, points[j], points[j+1], Scalar(0, 255, 0), 2, 8);
                }
                //fre_center = center;
            }
        }
        return result;
    }
    
    void main()
    {     
        VideoCapture cap("E://man.avi");
        if(!cap.isOpened()) //检查打开是否成功
             return;
        Mat frame;
        Mat background;
        Mat result;
        int count=0;
        while(1)
        {
            cap>>frame;
            if(!frame.empty())
            {
                count++;
                if(count==1)
                    background = frame.clone(); //提取第一帧为背景帧
                imshow("video", frame);
                result = MoveDetect(background, frame);
                imshow("result", result);
                if(waitKey(30)==27)
                   break;
            }
            else
                break;
        }
        cap.release();  
    }

    五、车辆数量检测

    1.帧差法检测运动目标

    2.预处理:a.转灰度图,绝对值做差  b.二值化,腐蚀,中值滤波,膨胀  c.查找轮廓,筛选轮廓,绘制外接矩形,计数,输出

     1 #include "opencv2/opencv.hpp"
     2 #include<iostream>
     3 using namespace std;
     4 using namespace cv;
     5 
     6 int CarNum = 0;
     7 //int to string helper function
     8 string intToString(int number)
     9 {
    10     //this function has a number input and string output
    11     stringstream ss;
    12     ss << number;
    13     return ss.str();
    14 }
    15 
    16 Mat MoveDetect(Mat frame1, Mat frame2) {
    17     Mat result = frame2.clone();
    18     Mat gray1, gray2;
    19     cvtColor(frame1, gray1, CV_BGR2GRAY);
    20     cvtColor(frame2, gray2, CV_BGR2GRAY);
    21 
    22     Mat diff;
    23     absdiff(gray1, gray2, diff);
    24     //imshow("absdiss", diff);
    25     threshold(diff, diff, 25, 255, CV_THRESH_BINARY);
    26     imshow("threshold", diff);
    27 
    28     Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
    29     Mat element2 = getStructuringElement(MORPH_RECT, Size(19, 19));
    30     erode(diff, diff, element);
    31     //imshow("erode", dst);
    32     medianBlur(diff, diff, 3);
    33     imshow("medianBlur", diff);
    34     dilate(diff, diff, element2);
    35     imshow("dilate", diff);
    36 
    37     vector<vector<Point>> contours;
    38     vector<Vec4i> hierarcy;
    39     findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));//查找轮廓
    40     vector<vector<Point>>contours_poly(contours.size());
    41     vector<Rect> boundRect(contours.size()); //定义外接矩形集合
    42                                              //drawContours(img2, contours, -1, Scalar(0, 0, 255), 1, 8);  //绘制轮廓
    43     int x0 = 0, y0 = 0, w0 = 0, h0 = 0;
    44     for (int i = 0; i<contours.size(); i++)
    45     {
    46         approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);//对图像轮廓点进行多边形拟合:轮廓点组成的点集,输出的多边形点集,精度(即两个轮廓点之间的距离),输出多边形是否封闭
    47         boundRect[i] = boundingRect(Mat(contours_poly[i]));
    48         if (boundRect[i].width>55 && boundRect[i].width<180 && boundRect[i].height>55 && boundRect[i].height<180) {//轮廓筛选
    49             x0 = boundRect[i].x;
    50             y0 = boundRect[i].y;
    51             w0 = boundRect[i].width;
    52             h0 = boundRect[i].height;
    53 
    54             rectangle(result, Point(x0, y0), Point(x0 + w0, y0 + h0), Scalar(0, 255, 0), 2, 8, 0);
    55             if ((y0 + h0 / 2 + 1) >= 138 && (y0 + h0 / 2 - 1) <= 142) {//经过这条线(区间),车辆数量+1
    56                 CarNum++;
    57             }
    58         }
    59         line(result, Point(0, 140), Point(568, 140), Scalar(0, 0, 255), 1, 8);//画红线
    60         Point org(0, 35);
    61         putText(result, "CarNum=" + intToString(CarNum), org, CV_FONT_HERSHEY_SIMPLEX, 0.8f, Scalar(0, 255, 0), 2);
    62     }
    63     return result;
    64 }
    65 
    66 void main()
    67 {
    68     VideoCapture cap("E://2.avi");
    69     if (!cap.isOpened()) //检查打开是否成功
    70         return;
    71     Mat frame;
    72     Mat tmp;
    73     Mat result;
    74     int count = 0;
    75     while (1)
    76     {
    77         cap >> frame;
    78         if(frame.empty())//检查视频是否结束
    79             break;
    80         else{
    81             count++;
    82             if (count == 1)    
    83                 result = MoveDetect(frame, frame);
    84             else    result = MoveDetect(tmp, frame);
    85             imshow("video", frame);
    86             imshow("result", result);
    87             tmp = frame.clone();
    88             if (waitKey(20) == 27)        
    89                 break;
    90         }
    91     }
    92     cap.release();
    93 }

  • 相关阅读:
    数据透视表快速按年月分组
    会计-汇兑损益账务处理
    vs Mvc晋级
    sql语句建立新表SMFIELD
    access左侧导航栏拉窄后,鼠标悬停时无法拉宽。
    SQL函数min和max用法
    转发一个很齐全的gridview应用帖子
    循环
    JavaScript的进阶学习
    JavaScript的学习
  • 原文地址:https://www.cnblogs.com/little-monkey/p/7637130.html
Copyright © 2020-2023  润新知