图像处理之前景检测(四)之自组织背景检测(SOBS)(转载)
       一种基于自组织神经网络(self-Organizing through artificial neural networks)的背景减除算法(简称SOBS算法,全名:Self-Organizing Background Subtraction),用于智能视频监控系统中的目标检测,该算法不仅对光照具有较强的鲁棒性,而且具有较强的实用性。
      具体原理参考下文,其中含有算法作者论文链接,比较详细。
      Belial_2010              基于自组织背景减除的运动目标检测算法
    
      算法代码实现见:
      ZengDong_1991     ackground Modeling and Foreground Detection -- SOBS
    
   这里对于上述代码进行了些许的更改和简单的注释,环境为VS2015+opencv3.2 contrib版。如下:
     
     头文件:BackgroundSubtractorSOBS.h
// Author : zengdong_1991
// Date   : 2016-06-13
// HomePage : http://blog.csdn.net/zengdong_1991
// Email  : 782083852@qq.com#pragma once
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include "math.h"//! defines the parameters
#define WEIGHTS_N   3  //weight vertor 大小 = N^2
#define FRAME_NUM_K 45
#define EPSILON1 1.0
#define EPSILON2 0.008#define PARAM_C1 1.0
#define PARAM_C2 0.05
#define MAX_W 4.0
#define ALPHA_1 (PARAM_C1 / MAX_W)
#define ALPHA_2 (PARAM_C2 / MAX_W)#define GAMA 0.7
#define BEATA 1.0
#define TAU_S 40
#define TAU_H 48static const double m_weightW[WEIGHTS_N*WEIGHTS_N] = { 1.0, 2.0, 1.0, 2.0, 4.0, 2.0, 1.0, 2.0, 1.0 };//高斯权重的选择 class BackgroundSubtractorSOBS {
public://! full constructorBackgroundSubtractorSOBS(int trainFrameNum = FRAME_NUM_K,double epsilon1 = EPSILON1,double epsilon2 = EPSILON2,double c1 = PARAM_C1,double c2 = PARAM_C2,double gama = GAMA,double beta = BEATA,double tauS = TAU_S,double tauH = TAU_H,double maxW = MAX_W);//! default destructorvirtual ~BackgroundSubtractorSOBS();//! virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI);//! virtual void operator()(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = 0);public:int m_trainFrameNum;double m_epsilon1;double m_epsilon2;double m_c1;double m_c2;double m_maxW;double m_alpha1;double m_alpha2;double m_gama;double m_beta;double m_tauS;double m_tauH;cv::Mat m_backgroundModel;   //背景模型:  n*rows, n*colssize_t m_frameNum = 0;cv::Mat m_ImgHSV;cv::Mat m_oROI;//! input image sizecv::Size m_oImgSize;//! input image channel sizesize_t m_nImgChannels;size_t m_height;size_t m_width;size_t m_pixelNum;//! input image typeint m_nImgType;bool findTheMatchVector(const cv::Vec3b& piexlVal, const size_t x, const size_t y, size_t& offSet_x, size_t& offSet_y, double eta); //true 匹配,false没有匹配void updateBackground(const cv::Vec3b& piexlVal, const size_t x, const size_t y, size_t& offSet_x, size_t& offSet_y, double alphaT);double getDistance(const cv::Vec3b& curr, const cv::Vec3b& bg);};
       算法函数主体:BackgroundSubtractorSOBS.cpp
// Author : zengdong_1991
// Date   : 2016-06-13
// HomePage : http://blog.csdn.net/zengdong_1991
// Email  : 782083852@qq.com
#include "BackgroundSubtractorSOBS.h"
#include <iostream>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>BackgroundSubtractorSOBS::BackgroundSubtractorSOBS(int trainFrameNum,double epsilon1, double epsilon2, double c1,double c2,double gama,double beta,double tauS, double tauH,double maxW): m_trainFrameNum(trainFrameNum), m_epsilon1(epsilon1), m_epsilon2(epsilon2), m_c1(c1), m_c2(c2), m_maxW(maxW), m_gama(gama), m_beta(beta), m_tauS(tauS), m_tauH(tauH)
{m_alpha1 = m_c1 / m_maxW;m_alpha2 = m_c2 / m_maxW;std::cout << "#########################Current Parameters Begin###################" << std::endl;std::cout << "m_trainFrameNum = " << m_trainFrameNum << std::endl;std::cout << "m_epsilon1 = " << m_epsilon1 << std::endl;std::cout << "m_epsilon2 = " << m_epsilon2 << std::endl;std::cout << "m_c1 = " << m_c1 << std::endl;std::cout << "m_c2 = " << m_c2 << std::endl;std::cout << "m_maxW = " << m_maxW << std::endl;std::cout << "m_alpha1 = " << m_alpha1 << std::endl;std::cout << "m_alpha2 = " << m_alpha2 << std::endl;std::cout << "m_gama = " << m_gama << std::endl;std::cout << "m_beta = " << m_beta << std::endl;std::cout << "m_tauS = " << m_tauS << std::endl;std::cout << "m_tauH = " << m_tauH << std::endl;std::cout << "#########################Current Parameters End###################" << std::endl;}BackgroundSubtractorSOBS::~BackgroundSubtractorSOBS() {}void BackgroundSubtractorSOBS::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI)//初始化
{// == initCV_Assert(!oInitImg.empty() && oInitImg.cols > 0 && oInitImg.rows > 0);CV_Assert(oInitImg.isContinuous());CV_Assert(oInitImg.type() == CV_8UC3);   //必须是彩色图像if (oInitImg.type() == CV_8UC3){std::vector<cv::Mat> voInitImgChannels;cv::split(oInitImg, voInitImgChannels);if (!cv::countNonZero((voInitImgChannels[0] != voInitImgChannels[1]) | (voInitImgChannels[2] != voInitImgChannels[1])))std::cout << std::endl << "\tBackgroundSubtractorSuBSENSE : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl;}m_oImgSize = oInitImg.size();m_nImgType = oInitImg.type();m_nImgChannels = oInitImg.channels();m_height = oInitImg.rows;m_width = oInitImg.cols;m_pixelNum = m_height * m_width;m_frameNum = 1;//将第一帧转换到 HSV 空间cv::Mat hsv;cv::cvtColor(oInitImg, hsv, CV_BGR2HSV);    //H范围是 【0-->180】//根据hsv初始化背景模型  大小为 (n*rows, n*cols)m_backgroundModel.create(cv::Size(WEIGHTS_N*m_width, WEIGHTS_N*m_height), CV_8UC3);for (size_t x = 0; x < m_height; x++){for (size_t y = 0; y < m_width; y++){cv::Vec3b  val = hsv.at<cv::Vec3b>(x, y);for (size_t i = WEIGHTS_N*x; i < WEIGHTS_N*(x + 1); i++){for (size_t j = WEIGHTS_N*y; j < WEIGHTS_N*(y + 1); j++){m_backgroundModel.at<cv::Vec3b>(i, j) = val;}}}}//cv::Mat debugMat = m_backgroundModel;}void BackgroundSubtractorSOBS::operator()(cv::InputArray _image, cv::OutputArray _fgmask, double learningRateOverride)//对于后续图像进行对比操作,区分前景背景并颜色标注
{// == processcv::Mat oInputImg = _image.getMat();CV_Assert(oInputImg.type() == m_nImgType && oInputImg.size() == m_oImgSize);CV_Assert(oInputImg.isContinuous());_fgmask.create(m_oImgSize, CV_8UC1);cv::Mat oCurrFGMask = _fgmask.getMat();   //外界 mask 矩阵oCurrFGMask = cv::Scalar_<uchar>(0);//转换到HSV空间: cv::cvtColor(oInputImg, m_ImgHSV, CV_BGR2HSV);//cv::Mat debugMat = m_ImgHSV;m_frameNum++;size_t offSet_x = 0, offSet_y = 0;  //匹配偏移量double alphaT = m_alpha1 - (m_frameNum*(m_alpha1 - m_alpha2) / m_trainFrameNum); //公式(3)(4)  a(T)for (size_t x = 0; x < m_height; x++){for (size_t y = 0; y < m_width; y++){cv::Vec3b  val = m_ImgHSV.at<cv::Vec3b>(x, y);//calibration phase  执行 step 2--> 6if (m_frameNum <= m_trainFrameNum){//查找匹配                  if (findTheMatchVector(val, x, y, offSet_x, offSet_y, m_epsilon1)){updateBackground(val, x, y, offSet_x, offSet_y, alphaT);oCurrFGMask.at<uchar>(x, y) = 0;}else{oCurrFGMask.at<uchar>(x, y) = 255;}}//on line phase  执行 step 2-->10             else{if (findTheMatchVector(val, x, y, offSet_x, offSet_y, m_epsilon2)){updateBackground(val, x, y, offSet_x, offSet_y, m_alpha2);oCurrFGMask.at<uchar>(x, y) = 0;}/*else if (isShadow(val, x, y, offSet_x, offSet_y)){oCurrFGMask.at<uchar>(x, y) = 0;}*/else{oCurrFGMask.at<uchar>(x, y) = 255;}}}}}
void BackgroundSubtractorSOBS::updateBackground(const cv::Vec3b& piexlVal, const size_t x, const size_t y, size_t& offSet_x, size_t& offSet_y, double alphaT)//背景更新
{//  cv::Vec3b* ptrVec = m_backgroundModel.ptr<cv::Vec3b>(0);int pad = (WEIGHTS_N - 1) / 2;//当前匹配像素的坐标是    (nx+offset_x, ny+offset_y), 更新其周围的 N*N像素,如下:for (int i = -pad; i <= pad; i++){int coordinateX = WEIGHTS_N*x + offSet_x + i;if (coordinateX < 0 || coordinateX >= WEIGHTS_N*m_height)   //边界保护continue;for (int j = -pad; j <= pad; j++){int coordinateY = WEIGHTS_N*y + offSet_y + j;if (coordinateY < 0 || coordinateY >= WEIGHTS_N*m_width)  //边界保护continue;cv::Vec3b& pixelValBg = m_backgroundModel.at<cv::Vec3b>(coordinateX, coordinateY);double alpha = alphaT * m_weightW[(i + pad)*WEIGHTS_N + j + pad];  //【未解决】 w 怎么归一化...现在是【1,2,1;...】/*防止损失精度还是不这么做好了*///【未解决】 测试以下是否相等...pixelValBg = (1 - alpha)*pixelValBg + alpha*piexlVal;//cv::Vec3b At_1 = (1 - alpha)*pixelValBg;//cv::Vec3b Pt = alpha * piexlVal;//pixelValBg = At_1 + Pt;//cv::Vec3b test = pixelValBg;int a = 0;}}}bool BackgroundSubtractorSOBS::findTheMatchVector(const cv::Vec3b& piexlVal, const size_t x, const size_t y, size_t& offSet_x, size_t& offSet_y, double eta)//判断对应点是否符合属于背景条件
{cv::Mat temp = m_backgroundModel;//9个像素值...for (size_t i = 0; i < WEIGHTS_N; i++){for (size_t j = 0; j < WEIGHTS_N; j++){cv::Vec3b piexlValBg = m_backgroundModel.at<cv::Vec3b>(WEIGHTS_N*x + i, WEIGHTS_N*y + j);//当前像素与背景像素距离小于阈值double dist = getDistance(piexlVal, piexlValBg);if (dist < eta){offSet_x = i;offSet_y = j;return true;}}}return false;
}
double BackgroundSubtractorSOBS::getDistance(const cv::Vec3b& curr, const cv::Vec3b& bg)//求取HSV Color Hexcone距离
{//opencv BGR2HSV中的H分量范围属于【0-->180】,将其隐射回【0-->360°(2*pi)】double hRatio = 2 * CV_PI / 180.0;double sRatio = 1. / 255.;double vRatio = 1. / 255.;double h1 = (double)curr[0] * hRatio;double s1 = (double)curr[1] * sRatio;double v1 = (double)curr[2] * vRatio;double h2 = (double)bg[0] * hRatio;double s2 = (double)bg[1] * sRatio;double v2 = (double)bg[2] * vRatio;double distance = (v1*s1*cos(h1) - v2*s2*cos(h2))*(v1*s1*cos(h1) - v2*s2*cos(h2)) +(v1*s1*sin(h1) - v2*s2*sin(h2))*(v1*s1*sin(h1) - v2*s2*sin(h2)) +(v1 - v2)*(v1 - v2);return (distance);}
       主函数:main.cpp
// Author : zengdong_1991
// Date   : 2016-06-13
// HomePage : http://blog.csdn.net/zengdong_1991
// Email  : 782083852@qq.com
#include <iostream>
#include<opencv.hpp>#include "BackgroundSubtractorSOBS.h"using namespace std;
using namespace cv;int main(int argc, char **argv)
{VideoCapture cap("E:\\素材\\2.mp4");Mat frame;cap >> frame;BackgroundSubtractorSOBS bgs;int key = 0;bool initialized = false;cv::Mat img_mask;cv::Mat img_bkgmodel;while (key != 'q'){cap>>frame ;if (frame.empty() == 1) {std::cerr << "Cannot open video!" << std::endl;return 1;}cv::Mat img_input(frame);if (!initialized){bgs.initialize(img_input, cv::Mat());initialized = true;continue;}bgs(img_input, img_mask);//cv::medianBlur(img_mask, img_mask, 5);if (!img_mask.empty()){//cv::medianBlur(img_mask, img_mask, 5);cv::imshow("output", img_mask);}cv::imshow("input", img_input);cv::waitKey(1);//    key = cvWaitKey(1);}//cvDestroyAllWindows();//cvReleaseCapture(&capture);return 0;
}

运行结果:(现在看,速度确实有些慢)。

图像处理之前景检测(四)之自组织背景检测(SOBS)(转载)相关推荐

  1. OpenCV—python 图像显著性检测算法—鲁棒背景检测

    文章目录 一.鲁棒背景检测的显著性优化 二.代码演示 一.鲁棒背景检测的显著性优化 Saliency Optimization from Robust Background Detection 摘要 ...

  2. matlab多边形检测_Matlab图像处理学习笔记(四):多边形检测

    本文用matlab实现了基本多边形的检测.提取. 本文涉及到的知识点如下: 1.Canny边缘检测.bw = edge(gray,'canny',[0 , 50/256]); 2.细化操作.im=bw ...

  3. 模式识别与图像处理课程实验一:图像处理实验(颜色算子实验、Susan、Harris角点检测实验、 sobel边缘算子检测实验)

    模式识别与图像处理课程实验一:图像处理实验-->> 颜色算子实验.Susan.Harris角点检测实验. sobel边缘算子检测实验 一. 实验内容 二. 颜色算子实验 2.1. 提取红色 ...

  4. 图像处理之前景检测(五)之基于样本一致性背景检测(SACON)(主要为代码升级)

    图像处理之前景检测(五)之基于样本一致性背景检测(SACON) SACON(SAmple CONsensus)算法是基于样本一致性的运动目标检测算法.该算法通过对每个像素进行样本一致性判断来判定像素是 ...

  5. 万字长文告诉新手如何学习Python图像处理(上篇完结 四十四) | 「Python」有奖征文

    该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门.OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子.图像增强技术.图像分割等,后期结合深度学习研究图像识别 ...

  6. 《OpenCv视觉之眼》Python图像处理十六:Opencv图像处理实战一之图像中的硬币检测

    本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的.不同方法的处理,以达到对图像进行去噪.锐 ...

  7. 图像处理基础操作二(边缘检测、轮廓检测、光流估计)

    目录 一.边缘检测 二.图像金字塔 三.图像轮廓检测 1.绘制图像轮廓 2.轮廓近似绘制 3.画轮廓边界矩形框 4.画轮廓外接圆 四.背景建模 五.光流估计 一.边缘检测 边缘检测通常是在保留原有图像 ...

  8. 运动目标检测_单高斯背景建模

    1.运动目标背景建模 背景建模也称为背景估计,其主要目的是根据当前的背景估计,把对序列图像的运动目标检测问题转化为一个二分类问题,将所有像素划分为背景和运动前景两类,进而对分类结果进行后处理,得到最终 ...

  9. 数字图像处理拓展题目——利用Matlab实现动态目标检测 二帧差法、ViBe法、高斯混合模型法,可应用于学生递东西行为检测

    1.二帧差法实现动态目标检测 先上效果图: 利用GUI界面显示出来效果图为: 实现流程 1.利用matlab中的VideoReader函数读取视频流. 2.帧差法:获得视频帧数,用for循环对图像每相 ...

最新文章

  1. 2018未来科学大奖揭晓:袁隆平、马大为、林本坚等7位科学家获奖
  2. POW矿池挖空块原理和解决方案
  3. Android中的相对布局
  4. java后台传一个对象到前台_前台判断对象中的一个布尔值_springMVC面试题
  5. matlab 绘花,【原创】使用matlab绘制菊花和玫瑰花
  6. JS 中对象的简单创建和继承
  7. Python中如何打印空行
  8. 智慧工地视频监控系统解决方案
  9. 关于学习BEX5的问题
  10. kali下如何生成密码字典(在线)
  11. matlab mat转bmp,mat格式转换
  12. 在线生成圣诞帽子的头像HTML源码
  13. hazy的面试小笔记之Spring(持续更新)
  14. 二氧化硅纳米微球光子晶体乳液聚合聚苯乙烯核壳结构/中空二氧化硅/钛纳米微球的制备方法
  15. 蛙蛙推荐:蛙蛙牌关键词提取算法
  16. centos7默认mariadb与mysql官网下载安装问题解决
  17. (转)快商通与商务通将客人网页内文本框输入的内容传到客服端对话界面显示...
  18. 2-44 JQuery
  19. Java,基于简单输入的薪水计算器
  20. window电脑访问Android照片,解决JPEG照片在windows无法打开

热门文章

  1. 煤矿自动化系统指的是什么_煤矿综合自动化系统解决方案
  2. Android端h5不能选择图片,weui公众号开发h5部分手机不能选择图片及拍照问题
  3. 运用STM32对SD卡数据读取
  4. sqlserver SQL Server Management Studio和Transact-SQL创建账户、创建访问指定数据库的只读用户
  5. 如何写出网站策划方案
  6. nslookup默认服务器修改,Windows Server 2008 R2 域控服务器运行nslookup命令默认服务器显示 UnKnown...
  7. 【Python项目】用Python采集球员信息,成功预测到了世界杯球赛胜负?
  8. android jni中的java调c的两种方法
  9. Apache Kafka 在 vivo 的实战
  10. 合资车型挂牌价20万以内带锁全时四驱 长安铃木维特拉越开越上瘾