【opencv450】Vibe算法进行前景检测

0981e5f9c45775fb83b433d56e0b200c.png

2f8b01c0e2a954c75b99aada2e54374d.png

981d6a917a47f1528b24b2a8987121f5.png

效果

vibe是一种像素级的前景检测算法,实时性高,内存占有率低,前景检测准确率高。但是会出现“鬼影”,当然基于对鬼影的处理,也会有相应的对vibe算法的改进。


main.cpp

#include<opencv2/imgproc.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/types_c.h>
#include <opencv2/objdetect/objdetect.hpp>
#include "Vibe.h"


int main(int argc, char* argv[])
{
    Mat frame, frame2, gray, gray2, FGModel;
    frame = imread("7.bmp");
    ViBe vibe;
    cvtColor(frame, gray, CV_RGB2GRAY);
    vibe.init(gray);
    vibe.ProcessFirstFrame(gray);
    cout << "Training ViBe Success." << endl;
    //程序运行时间统计变量
    double time;
    double start;


    frame2 = imread("8.bmp");
    cvtColor(frame2, gray2, CV_RGB2GRAY);


    start = static_cast<double>(getTickCount());
    vibe.Run(gray2);
    time = ((double)getTickCount() - start) / getTickFrequency() * 1000;
    cout << "Time of Update ViBe BAckground:" << time << "ms" << endl << endl;
    FGModel = vibe.getFGModel();
   // resize(FGModel, FGModel, Size(717, 600));
   // resize(frame, frame, Size(717, 600));
   // resize(frame2, frame2, Size(717, 600));
    resize(FGModel, FGModel, Size(478, 400));
    resize(frame, frame, Size(478, 400));
    resize(frame2, frame2, Size(478, 400));
    imshow("FGModel", FGModel);


    imshow("frame1", frame);
    imshow("frame2", frame2);


    if (waitKey(0) == 27)
    {
        destroyAllWindows();
    }
    system("pause");
    destroyAllWindows();
    //if (waitKey(25) == 27) break;


    //VideoCapture capture;
    //capture = VideoCapture("./Video/cs2.mp4");
    //if (!capture.isOpened())
    //{
    //    capture = VideoCapture("../Video/cs2.mp4");
    //    if (!capture.isOpened())
    //    {
    //        capture = VideoCapture("../../Video/cs2.mp4");
    //        if (!capture.isOpened())
    //        {
    //            cout << "ERROR:Didn't find thid video!" << endl;
    //            return 0;
    //        }
    //    }
    //}


    //capture.set(CAP_PROP_FRAME_WIDTH, 160);
    //capture.set(CAP_PROP_FRAME_HEIGHT, 120);


    //if (!capture.isOpened())
    //{
    //    cout << "No camera or video input!" << endl;
    //    return -1;
    //}


    程序运行时间统计变量
    //double time;
    //double start;


    //ViBe vibe;
    //bool count = true;
    //while (1)
    //{
    //    capture >> frame;
    //    if (frame.empty())
    //        continue;


    //    cvtColor(frame, gray, CV_RGB2GRAY);
    //    if (count)
    //    {
    //        vibe.init(gray);
    //        vibe.ProcessFirstFrame(gray);
    //        cout << "Training ViBe Success." << endl;
    //        count = false;
    //    }
    //    else
    //    {
    //        start = static_cast<double>(getTickCount());
    //        vibe.Run(gray);
    //        time = ((double)getTickCount() - start) / getTickFrequency() * 1000;
    //        cout << "Time of Update ViBe BAckground:" << time << "ms" << endl << endl;


    //        FGModel = vibe.getFGModel();
    //        imshow("FGModel", FGModel);
    //    }
    //    imshow("input", frame);


    //    if (waitKey(25) == 27)
    //        break;
    //}
   // return 0;
}

Vibe.h

#include<iostream>
#include<cstdio>
#include<opencv2/opencv.hpp>


using namespace cv;
using namespace std;


//每个像素点的样本个数默认值
#define DEFAULT_NUM_SAMPLES 20


//#min指数默认值
#define DEFAULT_MIN_MATCHES 2


//Sqthere半径默认值
#define DEFAULT_RADIUS 20


//子采样概率默认值
#define DEFAULT_RANDOM_SAMPLE 16


class ViBe
{
public:
    ViBe(int num_sam = DEFAULT_NUM_SAMPLES,
        int min_match = DEFAULT_MIN_MATCHES,
        int r = DEFAULT_RADIUS,
        int rand_sam = DEFAULT_RANDOM_SAMPLE);
    ~ViBe(void);


    //背景模型初始化
    void init(Mat img);


    //处理第一帧图像
    void ProcessFirstFrame(Mat img);


    //运行ViBe算法,提取前景区域并更新背景模型样本库
    void Run(Mat img);


    //获取前景模型二值图像
    Mat getFGModel();


    //删除样本库
    void deleteSamples();


    //x的邻居点
    int c_xoff[9];


    //y的邻居点
    int c_yoff[9];


private:
    //样本库
    unsigned char*** samples;


    //前景模型二值图像
    Mat FGModel;


    //每个像素点的样本个数
    int num_samples;


    //#min指数
    int num_min_matches;


    //Sqthere半径
    int radius;


    //子采样概率
    int random_sample;


};

Vibe.cpp

#include"Vibe.h"
/*
构造函数ViBe
参数:
int num_sam:每个像素点的样本个数
int min_match:#min 指数
int r: Sqthere 半径
int rand_sam:子采样概率
*/


ViBe::ViBe(int num_sam, int min_match, int r, int rand_sam)
{
    num_samples = num_sam;
    num_min_matches = min_match;
    radius = r;
    random_sample = rand_sam;
    int c_off[9] = { -1,0,1,-1,1,-1,0,1,0 };
    for (int i = 0; i < 9; i++) {
        c_xoff[i] = c_yoff[i] = c_off[i];
    }
}


/*析构函数:~ViBe
  说明:释放样本库内存
*/


ViBe::~ViBe(void)
{
    deleteSamples();
}


/*
  函数名init
  说明:背景模型初始化
       为样本库分配空间


  参数:Mat img:源图像
  返回值:void
*/


void ViBe::init(Mat img)
{
    //动态分配三维数组,samples[][][num_samples]存储前景被连续检测的次数
    //
    samples = new unsigned char** [img.rows];
    for (int i = 0; i < img.rows; i++)
    {
        samples[i] = new uchar * [img.cols];
        for (int j = 0; j < img.cols; j++)
        {
            //数组中,在num_samples之外多增加的一个值,用于统计该像素点连续成为前景的次数
            samples[i][j] = new uchar[num_samples + 1];
            for (int k = 0; k < num_samples + 1; k++)
            {
                //创建样本库是,所有样本全部初始化为0
                samples[i][j][k] = 0;


            }
        }


    }


    FGModel = Mat::zeros(img.size(), CV_8UC1);
}
/*
     函数名 ProcessFirstFrame
     说明:处理第一帧图像
         读取视频序列第一帧,并随机选取像素点邻域内像素填充样本库,初始化背景模型
    参数:
    Mat img:源图像
    返回值:void


     */


void ViBe::ProcessFirstFrame(Mat img)
{
    RNG rng;
    int row, col;


    for (int i = 0; i < img.rows; i++)
    {
        for (int j = 0; j < img.cols; j++)
        {
            for (int k = 0; k < num_samples; k++)
            {
                //随机选择num_samples个邻域像素点,构建背景模型
                int random;
                random = rng.uniform(0, 9); row = i + c_yoff[random];
                random = rng.uniform(0, 9); col = j + c_xoff[random];


                //防止选取的像素点越界
                if (row < 0)
                    row = 0;
                if (row >= img.rows)
                    row = img.rows - 1;
                if (col < 0)
                    col = 0;
                if (col >= img.cols)
                    col = img.cols - 1;


                //为样本库赋值随机值
                samples[i][j][k] = img.at<uchar>(row, col);
            }
        }
    }
}


/*
函数名:Run
说明:运行ViBe算法,提取前景区域并更新背景模型样本库
参数:
Mat img 源图像
返回值:void


*/


void ViBe::Run(Mat img)
{
    RNG rng;
    int k = 0, dist = 0, matches = 0;
    for (int i = 0; i < img.rows; i++)
    {
        for (int j = 0; j < img.cols; j++)
        {
            //前景提取
            //说明:计算当前像素值与样本库的匹配情况
            //参数:
            //int matches:当前像素值与   样本库中值之差小于阈值范围RADIUS的个数
            //int count: 遍历样本库的缓存变量
            for (k = 0, matches = 0; matches < num_min_matches && k < num_samples; k++)
            {
                dist = abs(samples[i][j][k] - img.at<uchar>(i, j));
                if (dist < radius)
                    matches++;


            }
            //说明:当前像素值与样本库中值匹配次数较高,则认为是背景像素点;
            //此时更新前景统计次数、更新前景模型、更新该像素模型样本值、更新该像素点邻域像素点
            if (matches >= num_min_matches)
            {
                //已经认为是背景像素,故该像素前景统计次数置0
                samples[i][j][num_samples] = 0;


                //该像素点的前景模型像素值置0
                FGModel.at<uchar>(i, j) = 0;
            }
            //说明:当前像素值与样本库中值匹配次数较低,则认为是前景像素点
            //此时需要更新前景统计次数,判断更新前景模型
            else {
                //已经认为是前景像素,故该像素的前景统计次数+1
                samples[i][j][num_samples]++;


                //该像素点的前景模型像素值置255
                FGModel.at<uchar>(i, j) = 255;


                //如果某个像素点连续50次被检测为前景,则认为一块静止区域被误判为运动,将其更新为背景点
                if (samples[i][j][num_samples] > 50)
                {
                    int random = rng.uniform(0, num_samples);
                    samples[i][j][random] = img.at<uchar>(i, j);
                }
            }
            //更新模型样本库
            if (matches >= num_min_matches)
            {
                //已经认为该像素是背景像素,那么它有1/φ的概率去更新自己的模型样本值
                int random = rng.uniform(0, random_sample);
                if (random == 0)
                {
                    random = rng.uniform(0, num_samples);
                    samples[i][j][random] = img.at<uchar>(i, j);
                }
                //同时也有1/φ的概率去更新它的邻居点的模型样本值
                random = rng.uniform(0, random_sample);
                if (random == 0)
                {
                    int row, col;
                    random = rng.uniform(0, 9); row = i + c_yoff[random];
                    random = rng.uniform(0, 9); col = j + c_xoff[random];


                    //防止选取的像素点越界
                    if (row < 0)
                        row = 0;
                    if (row >= img.rows)
                        row = img.rows - 1;
                    if (col < 0)
                        col = 0;
                    if (col >= img.cols)
                        col = img.cols - 1;


                    //为样本库赋值随机值


                    random = rng.uniform(0, num_samples);
                    samples[row][col][random] = img.at<uchar>(i, j);




                }
            }
        }


    }
}


/*
函数名 :getFGModel
说明:获取前景模型二值图像
返回值:Mat


*/


Mat ViBe::getFGModel()
{
    return FGModel;
}


/*
函数名:deletesamples
说明:删除样本库
返回值:void


*/


void ViBe::deleteSamples()
{
    delete samples;
}

参考:

https://blog.csdn.net/weixin_44219242/article/details/115139247

https://www.jianshu.com/p/48baa72c6e5f

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值