使用OpenCV实现简单的移动物体检测和追踪

简介

这篇文章使用了OpenCV中的BackgroundSubtractor,实现了对移动物体的简单检测及追踪。

由于我参考的是OpenCV 3.1官方文档中提供的实例代码,所以如果你使用的是OpenCV 2.X,那应该会出现问题,不妨参考这篇文章http://blog.csdn.net/u011630458/article/details/45895649

BackgroundSubtractor介绍

BackgroundSubtractor一共给我们提供了三种具体方法,分别是BackgroundSubtractorMOG, BackgroundSubtractorMOG2和BackgroundSubtractorGMG

这三种方法的具体区别及使用方法可以参考这篇官方文档http://docs.opencv.org/3.1.0/db/d5c/tutorial_py_bg_subtraction.html

本文采用的是BackgroundSubtractorMOG2这种方法

下面附上代码:

//
//  main.cpp
//  移动物体识别
//
//  Created by ywy on 2016/10/10.
//  Copyright © 2016年 Swallow. All rights reserved.
//


#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include <opencv2/highgui.hpp>
#include <opencv2/video.hpp>

#include <stdio.h>
#include <iostream>
#include <sstream>

using namespace cv;
using namespace std;


Mat frame; //当前帧
Mat fgMaskMOG2; //通过MOG2方法得到的掩码图像fgmask
Mat segm;      //frame的副本

vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Ptr<BackgroundSubtractor> pMOG2; //MOG2 Background subtractor

//处理输入视频函数定义
void processVideo();

int main()
{
    //namedWindow("Original Frame");
    //namedWindow("After MOG2");

    //create Background Subtractor objects
    pMOG2 = createBackgroundSubtractorMOG2();

    processVideo();

    destroyAllWindows();
    return 0;
}


void processVideo() {

    VideoCapture capture(0); //参数为0,默认从摄像头读取视频

    if(!capture.isOpened()){
        cout << "Unable to open the camera! " << endl;
        exit(EXIT_FAILURE); //EXIT_FAILURE 可以作为exit()的参数来使用,表示没有成功地执行一个程序,其值为1
    }

    while( true ){

        if(!capture.read(frame)) {
            cout << "Unable to read next frame." << endl;
            exit(0);
        }

        //对画面进行一定的缩放,方便处理
        double scale = 1.3;         //缩放比例
        Mat smallImg(frame.rows / scale,frame.cols / scale,CV_8SC1);
        resize(frame, frame, smallImg.size(),0,0,INTER_LINEAR);


        pMOG2->apply(frame, fgMaskMOG2);    //更新背景模型
        frame.copyTo(segm);             //建立一个当前frame的副本
        findContours(fgMaskMOG2, contours, hierarchy,
                     CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE,Point(0,0)); //检测轮廓

        vector <vector<Point> > contours_poly( contours.size());
        vector <Point2f> center( contours.size());
        vector <float> radius( contours.size());
        for( int i = 0; i < contours.size(); i++){
            //findContours后的轮廓信息contours可能过于复杂不平滑,可以用approxPolyDP函数对该多边形曲线做适当近似
            approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true);
            //得到轮廓的外包络圆
            minEnclosingCircle( contours_poly[i], center[i], radius[i]);
        }
        //对所得到的轮廓进行一定的筛选
        for(int i = 0; i < contours.size(); i++ ){
            if (contourArea(contours[i]) > 500){
                circle(segm, center[i], (int)radius[i], Scalar(100, 100, 0), 2, 8, 0);
                break;
            }
        }

        //get the frame number and write it on the current frame
        stringstream ss;
//        rectangle(frame, cv::Point(10, 2), cv::Point(100,20),
//                  cv::Scalar(255,255,255), -1);
        ss << capture.get(CAP_PROP_POS_FRAMES);
        string frameNumberString = ss.str();
        putText(frame, frameNumberString.c_str(), cv::Point(15, 15),
                FONT_HERSHEY_SIMPLEX, 0.5 , cv::Scalar(0,0,0));

        //显示
        imshow("frame", frame);
        imshow("Segm", segm);
        imshow("FG Mask MOG 2", fgMaskMOG2);


        int key;
        key = waitKey(5);
        if (key == 'q' || key == 'Q' || key == 27)
            break;


    }

    capture.release();
}

效果演示

其中,frame窗口显示的是从摄像头采集到的原始画面,FG Mask MOG2窗口显示的是经过BackgroundSubtractorMOG2处理过的中间图像,Segm窗口显示的则是最终结果,移动的物体会被圆圈标记,但每一帧画面仅显示一个圆圈,所以识别准确率不是很高,有待改进。

移动物体识别

猜你喜欢

转载自blog.csdn.net/qq_32925781/article/details/52878465