运动目标检测代码(帧差、高斯混合、vibe代码实现)

主要介绍四种运动目标检测的算法代码,每段代码博主实测可运行。当前主流的混合高斯背景模型,VIBE算法代码转载自他处。另外GMG算法,KNN算法在朱伟的书中也有讲,opencv3.0中,有专门的背景模型类BackgroundSubtractor。详情请下载朱伟《图像处理编程实例》源代码–下载资源

原理在另一篇文章中有些《运动目标检测
1、帧间差分法求前景
帧间差分主要思想为两帧图像灰度化后相减得绝对值函数矩阵,然后二值化(注意阈值选择),得到前景图像。

#include "stdafx.h"
#include"opencv2\opencv.hpp"
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/imgproc/imgproc.hpp>  
#include <opencv2/core/core.hpp> 
using namespace cv;
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
    Mat img_src1, img_src2, gray1, gray2, gray_diff;
    int thvalue = 30;

    img_src1 = imread("F:\\毕业论文相关\\机场视频\\图片5帧\\density_img_5.jpg");
    img_src2 = imread("F:\\毕业论文相关\\机场视频\\图片5帧\\density_img_30.jpg");
    if (!img_src1.data || !img_src2.data)
        return -1;
    cvtColor(img_src1, gray1, CV_RGB2GRAY);
    cvtColor(img_src2, gray2, CV_RGB2GRAY);
    Mat img_dst(img_src1.rows, img_src1.cols, CV_8UC1);
    IplImage* Tsrcimage = &IplImage(gray1);//取指针
    IplImage* Tdstimage = &IplImage(gray2);
    IplImage* Tdif = &IplImage(img_dst);

    cvAbsDiff(Tsrcimage, Tdstimage, Tdif);//背景相减得灰度图
    cvThreshold(Tdif, Tdif, thvalue, 255, CV_THRESH_BINARY); //如果 src(x,y)>threshold ,dst(x,y) = max_value; 否则,dst(x,y)=0;
    cvShowImage("foreground", Tdif);
    //imshow("foreground", img_dst);
    waitKey();

    return 0;
}

2、三帧差分法求前景
第二帧减第一帧,第三帧减第二帧,结果相加,得到三帧差分图像。

#include "stdafx.h"
#include"opencv2\opencv.hpp"
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/imgproc/imgproc.hpp>  
#include <opencv2/core/core.hpp> 
using namespace cv;
using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
    Mat img_src1, img_src2, img_src3;
    Mat gray1, gray2, gray3;

    int thvalue = 30;

    img_src1 = imread("F:\\毕业论文相关\\机场视频\\图片5帧\\density_img_5.jpg");
    img_src2 = imread("F:\\毕业论文相关\\机场视频\\图片5帧\\density_img_40.jpg");
    img_src3 = imread("F:\\毕业论文相关\\机场视频\\图片5帧\\density_img_65.jpg");
    if (!img_src1.data || !img_src2.data)
        return -1;
    cvtColor(img_src1, gray1, CV_RGB2GRAY);
    cvtColor(img_src2, gray2, CV_RGB2GRAY);
    cvtColor(img_src3, gray3, CV_RGB2GRAY);

    Mat result1(img_src1.rows, img_src1.cols, CV_8UC1);
    Mat result2(img_src1.rows, img_src1.cols, CV_8UC1);
    Mat gray_diff(img_src1.rows, img_src1.cols, CV_8UC1);

    IplImage* Tgray1 = &IplImage(gray1);//取指针
    IplImage* Tgray2 = &IplImage(gray2);
    IplImage* Tgray3 = &IplImage(gray3);
    IplImage* Tresult1 = &IplImage(result1);
    IplImage* Tresult2 = &IplImage(result2);
    IplImage* Tdif = &IplImage(gray_diff);

    cvAbsDiff(Tgray1, Tgray2, Tresult1);//背景相减得灰度图
    cvAbsDiff(Tgray2, Tgray3, Tresult2);//背景相减得灰度图

    cvThreshold(Tresult1, Tresult1, thvalue, 255, CV_THRESH_BINARY); //如果 src(x,y)>threshold ,dst(x,y) = max_value; 否则,dst(x,y)=0;
    cvThreshold(Tresult2, Tresult2, thvalue, 255, CV_THRESH_BINARY);

    cvAdd(Tresult1, Tresult2,Tdif);

    cvShowImage("foreground", Tdif);
    cvErode(Tdif, Tdif);   //腐蚀  
    cvShowImage("腐蚀后", Tdif);
    cvDilate(Tdif, Tdif);  //膨胀  
    cvShowImage("膨胀后", Tdif);

    //imshow("foreground", img_dst);
    waitKey();

    return 0;
}

3、混合高斯背景模型实现

// 功能:代码 9-5 高斯混合背景建模
// 作者:朱伟 [email protected]
// 来源:《OpenCV图像处理编程实例》
// 博客:http://blog.csdn.net/zhuwei1988
// 更新:2016-8-1
// 说明:版权所有,引用或摘录请联系作者,并按照上面格式注明出处,谢谢。// 
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include <opencv2/highgui.hpp>
#include <opencv2/video.hpp>
#include <iostream>
#include <sstream>
using namespace cv;
using namespace std;
Mat frame; 
Mat fgMaskMOG2; 
Ptr<BackgroundSubtractor> pMOG2;
int keyboard; 
void processVideo(string videoFilename) 
{
    // 视频获取
    VideoCapture capture(videoFilename);
    if(!capture.isOpened())
    {
        // 输出视频文件打开错误信息
        cerr << "Unable to open video file: " << videoFilename << endl;
        exit(EXIT_FAILURE);
    }
    // 按下q键和esc退出
    while( (char)keyboard != 'q' && (char)keyboard != 27 )
    {
        // 读取当前帧
        if(!capture.read(frame)) 
        {
            cerr << "Unable to read next frame." << endl;
            cerr << "Exiting..." << endl;
            exit(EXIT_FAILURE);
        }
        // 图像尺寸缩小
        cv::resize(frame, frame,cv::Size(), 0.25,0.25);
        //  背景模型生成
        pMOG2->apply(frame, fgMaskMOG2);
        // 输出当前帧号
        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("FG Mask MOG 2", fgMaskMOG2);
        keyboard = waitKey(30);
    }
    capture.release();
}
int main(int argc, char* argv[])
{
    // 创建背景建模类
    pMOG2 = createBackgroundSubtractorMOG2(); 
    string inputPath = "F:\\毕业论文相关\\机场视频\\机场.avi";
    processVideo(inputPath);
    return 0;
}

4、vibe算法

(算法程序出处找不到了,如果恰好作者看到,留言一下我给加上,实在抱歉。)
主函数代码如下

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include "highgui.h"
#include "hanshu.h"
#include <iostream>

using namespace std;
using namespace cv;

int nFrmNum = 0;//记录帧数
int Width;//记录帧的宽度
int Height;//记录帧的高度
int FrameRate;//记录视频帧率

int main(int argc, char* argv[])
{
    IplImage* pFrame = NULL; CvMat* pFrameMat = NULL;//pFrame对象
    IplImage* pAfter = NULL; CvMat* pAfterMat = NULL;//保存pFrame对应的灰度图像
    IplImage* segMap = NULL; CvMat* segMat = NULL;//保存处理后的信息

    //要读取的视频文件和保存的视频文件路径
    char* openfile = "F:\\毕业论文相关\\机场视频\\密度人群.ts";
    char* outfile = "E:\\View004.avi";//检测结果输出位置
    char filename[100];//保存的图像位置和名称

    //打开视频文件
    CvCapture* pCapture = cvCreateFileCapture(openfile);
    if (pCapture == NULL) {
        cout << "video file open error!" << endl;
        return -1;
    }

    //获取视频相关信息,帧率和大小
    double fps = cvGetCaptureProperty(pCapture, CV_CAP_PROP_FPS);
    CvSize size = cvSize((int)cvGetCaptureProperty(pCapture, CV_CAP_PROP_FRAME_WIDTH) * 2,
        (int)cvGetCaptureProperty(pCapture, CV_CAP_PROP_FRAME_HEIGHT));

    //创建输出视频文件
    CvVideoWriter* Save_result = NULL;
    Save_result = cvCreateVideoWriter(outfile, CV_FOURCC('X', 'V', 'I', 'D'), fps, size, 1);
    IplImage* dstImg = cvCreateImage(size, IPL_DEPTH_8U, 3);//创建要保存的图像

    //创建窗口
    cvNamedWindow("video", CV_WINDOW_AUTOSIZE);

    //创建一个随机数生成器
    RNG rng(0xFFFFFFFF);
    //定义字体
    CvFont font;
    cvInitFont(&font, CV_FONT_HERSHEY_COMPLEX_SMALL, 1, 1, 0, 1, 8);

    //逐帧读取视频并进行处理   pFrame为取出原始帧
    while (pFrame = cvQueryFrame(pCapture)){

        nFrmNum++;

        //如果是第一帧,申请内存并进行初始化
        if (nFrmNum == 1){
            segMap = cvCreateImage(cvSize(pFrame->width, pFrame->height),
                IPL_DEPTH_8U, 1); //保存处理后的信息
            segMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);//保存处理后的信息
            pAfter = cvCreateImage(cvSize(pFrame->width, pFrame->height),
                IPL_DEPTH_8U, 1);//保存pFrame对应的灰度图像
            pAfterMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);//保存pFrame对应的灰度图像

            //转化成单通道图像再处理
            cvCvtColor(pFrame, pAfter, CV_BGR2GRAY);
            cvConvert(pAfter, pAfterMat);
            //
            Initialize(pAfterMat, rng);//以一个随机数生成器初始化灰度图像
        }
        else {
            if (nFrmNum%30==0)//此处为每30帧读取一次
            {
                cvCvtColor(pFrame, pAfter, CV_BGR2GRAY);//RGB空间转换为RAY空间
                cvConvert(pAfter, pAfterMat);//用于图像和矩阵之间的相互转换
                update(pAfterMat, segMat, rng, nFrmNum);//更新背景
                cvConvert(segMat, segMap);//用于图像和矩阵之间的相互转换

                //载入原图像到目标图像
                cvSetImageROI(dstImg, cvRect(0, 0, pFrame->width, pFrame->height));
                cvCopy(pFrame, dstImg);
                cvResetImageROI(dstImg);
                //将segMap转换成三通道图像存在pFrame中
                cvCvtColor(segMap, pFrame, CV_GRAY2BGR);
                //载入检测后的图像到目标图像
                cvSetImageROI(dstImg, cvRect(pFrame->width, 0, pFrame->width * 2, pFrame->height));
                cvCopy(pFrame, dstImg);
                cvResetImageROI(dstImg);
                //显示提示文字
                cvPutText(dstImg, "Input Video", cvPoint(0, pFrame->height - 5), &font, CV_RGB(255, 0, 0));
                cvPutText(dstImg, "Vibe Segmentation", cvPoint(pFrame->width, pFrame->height - 5), &font, CV_RGB(255, 0, 0));

                //保存视频和输出
                cvWriteFrame(Save_result, dstImg);

                /*输出图片
                if(nFrmNum<11)
                sprintf(filename,"E:\\Result\\Vibe\\AVSS_PV_Easy_Divx_Xvid\\000%d_Vibe.jpg",nFrmNum-1);
                else if(nFrmNum<101)
                sprintf(filename,"E:\\Result\\Vibe\\AVSS_PV_Easy_Divx_Xvid\\00%d_Vibe.jpg",nFrmNum-1);
                else if(nFrmNum<1001)
                sprintf(filename,"E:\\Result\\Vibe\\AVSS_PV_Easy_Divx_Xvid\\0%d_Vibe.jpg",nFrmNum-1);
                else if(nFrmNum<10001)
                sprintf(filename,"E:\\Result\\Vibe\\AVSS_PV_Easy_Divx_Xvid\\%d_Vibe.jpg",nFrmNum-1);
                cvSaveImage(filename,dstImg);
                */

                cvShowImage("video", dstImg);

                if (cvWaitKey(5) >= 0) break;
            }

        }
    }
    cvReleaseImage(&pFrame); cvReleaseMat(&pFrameMat);
    cvReleaseImage(&pAfter); cvReleaseMat(&pAfterMat);
    cvReleaseImage(&segMap); cvReleaseMat(&segMat);
    cvReleaseVideoWriter(&Save_result);
    cvReleaseImage(&dstImg);
    cvDestroyWindow("video");
    return 0;
}

类文件hanshu.h

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include "highgui.h"
#include <iostream>

using namespace std;
using namespace cv;

#define defaultNbSamples 20     //每个像素点的样本个数
#define defaultReqMatches 2     //#min指数
#define defaultRadius 20        //Sqthere半径
#define defaultSubsamplingFactor 16 //子采样概率
#define background 0        //背景像素
#define foreground 255      //前景像素

void Initialize(CvMat* pFrameMat,RNG rng);//初始化
void update(CvMat* pFrameMat,CvMat* segMat,RNG rng,int nFrmNum);//更新

类文件hanshu.cpp

#include "stdafx.h"
#include "hanshu.h"
#include <opencv2/opencv.hpp>
#include "highgui.h"
#include <math.h>
#include <iostream>

using namespace std;
using namespace cv;

static int c_xoff[9] = {-1,  0,  1, -1, 1, -1, 0, 1, 0};//x的邻居点
static int c_yoff[9] = {-1,  0,  1, -1, 1, -1, 0, 1, 0};//y的邻居点

float samples[1024][1024][defaultNbSamples+1];//保存每个像素点的样本值


//初始化
void Initialize(CvMat* pFrameMat,RNG rng){

    //记录随机生成的 行(r) 和 列(c)
    int rand,r,c;

    //对每个像素样本进行初始化
    for(int y=0;y<pFrameMat->rows;y++){//Height
        for(int x=0;x<pFrameMat->cols;x++){//Width
            for(int k=0;k<defaultNbSamples;k++){
                //随机获取像素样本值
                rand=rng.uniform( 0, 9 );//b如果是真值,返回a,否则返回(int)(next() % (b - a) + a);
                r=y+c_yoff[rand]; if(r<0) r=0; if(r>=pFrameMat->rows) r=pFrameMat->rows-1;  //行
                c=x+c_xoff[rand]; if(c<0) c=0; if(c>=pFrameMat->cols) c=pFrameMat->cols-1;  //列
                //存储像素样本值
                samples[y][x][k]=CV_MAT_ELEM(*pFrameMat,float,r,c);
            }
            samples[y][x][defaultNbSamples]=0;
        }
    }
}


//更新函数
void update(CvMat* pFrameMat,CvMat* segMat,RNG rng,int nFrmNum){

    for(int y=0;y<pFrameMat->rows;y++){ //Height
        for(int x=0;x<pFrameMat->cols;x++){ //Width

            //用于判断一个点是否是背景点,index记录已比较的样本个数,count表示匹配的样本个数
            int count=0,index=0;float dist=0;
            //
            while((count<defaultReqMatches) && (index<defaultNbSamples)){
                dist=CV_MAT_ELEM(*pFrameMat,float,y,x)-samples[y][x][index];
                if(dist<0) dist=-dist;
                if(dist<defaultRadius) count++;
                index++;
            }
            if(count>=defaultReqMatches){

                //判断为背景像素,只有背景点才能被用来传播和更新存储样本值
                samples[y][x][defaultNbSamples]=0;

                *((float *)CV_MAT_ELEM_PTR(*segMat,y,x))=background;

                int rand=rng.uniform(0,defaultSubsamplingFactor);
                if(rand==0){
                    rand=rng.uniform(0,defaultNbSamples);
                    samples[y][x][rand]=CV_MAT_ELEM(*pFrameMat,float,y,x);
                }
                rand=rng.uniform(0,defaultSubsamplingFactor);
                if(rand==0){
                    int xN,yN;
                    rand=rng.uniform(0,9);yN=y+c_yoff[rand];if(yN<0) yN=0; if(yN>=pFrameMat->rows) yN=pFrameMat->rows-1;
                    rand=rng.uniform(0,9);xN=x+c_xoff[rand];if(xN<0) xN=0; if(xN>=pFrameMat->cols) xN=pFrameMat->cols-1;
                    rand=rng.uniform(0,defaultNbSamples);
                    samples[yN][xN][rand]=CV_MAT_ELEM(*pFrameMat,float,y,x);
                } 
            }
            else {
                //判断为前景像素
                *((float *)CV_MAT_ELEM_PTR(*segMat,y,x))=foreground;

                samples[y][x][defaultNbSamples]++;
                if(samples[y][x][defaultNbSamples]>50){
                    int rand=rng.uniform(0,defaultNbSamples);
                    if(rand==0){
                        rand=rng.uniform(0,defaultNbSamples);
                        samples[y][x][rand]=CV_MAT_ELEM(*pFrameMat,float,y,x);
                    }
                }
            }

        }
    }

}

猜你喜欢

转载自blog.csdn.net/snwang_miss/article/details/72082064
今日推荐