基于DCT系数的实时监控中运动目标检测
2013-07-06 17:11
417 查看
本文的主要内容来自2009 Advanced Video and Signal Based Surveillance会议的一篇论文“Real-Time Moving Object Detection for Video Surveillance”,要看原文内容请参考文后给出的链接。申明二点:① 本文是根据提到的论文翻译过来的,但不完全与原文相同;②代码实现部分,在detect函数部分,逻辑有问题,没达到预期的要求,勿吐槽。废话少说,下面开始来介绍该论文。
初步查阅该文献,是由于网上的一篇博文,对该文进行了大肆的褒扬,遂对该文产生了一定的兴趣,这或许也和自己的背景相关,一直以来也在从事这方面的研究和工作。论文的思想很简单,大致描述如下:将图像分成4×4互不重叠的patches,然后对每一patch进行dct(离散余弦变换)变换(DCT与ICA和PCA的区别请参考相关文献),接着提取dct系数的低频成分作为特征,进行背景建模;而对于新输入的图像帧,则做同样处理,与抽取的背景模型特征进行比较,判断是否相似,采取空间邻域机制对噪声进行控制,达到准确前景提取的目的。下面根据论文的框架对每一部分进行详细介绍。
1)背景建模(Background Modelling)
背景模型是由多个dct系数向量组成的,不同空间的背景Patches可能有不同的coefficient vectors。对于每一patche,按照DCT公式进行变换,如式(1):
变换后,则可以得到DCT系数矩阵,如图1所示:
根据DCT变换的特点,抽取位置为(1,2)、(1,3)、(2,1)、(2,2)、(3,1)五个系数构成系数矩阵,作为背景模型。对每一Patch依次这样处理,则完成了背景模型的建立。
2)背景模型自适应 (Background Adaptation)
考虑到场景的动态变化以及噪声的影响,根据上面建立的背景模型难以对噪声和动态场景具有适应性,为了满足动态场景的需求,有必要对背景模型的自适应进行深入的研究。对于一个
newly coming patch,提取系数向量(Coefficient Vector),与背景模型进行比较,判断是否相似,相似的判断依据是两个向量的夹角是否大于某一阈值,如果匹配,则找到最匹配的模型,并对该模型对应的权重系数进行如下更新:
其中Tinc和Tdec是常量,alphai是该模型对应的权重,每个模型初始化的权重为Tinc。如果没有匹配上,这后面的就是重点,这时就需要判断该Patch在上一帧的邻域范围内是否有最可能的前景(Almost
Foreground)Patch,如果没有,则判为Almost Foreground Patch,并将其融入背景模型中。
3)前景检测(Foreground Detection)
前景Patch的判断与前景的背景自适应差不多,这里不再细说。只是提下,文章中将长期滞留在场景中的运动目标融入了背景模型,这样能提高算法的性能,当然有特殊需求的(如遗留物检测等)可能需要保留滞留在场景中的物体。
最后,加点个人见解。我们常规的对背景进行建模都是在空间域进行的,而作者将图像分成Patches,对每一Patch都采用DCT变换,对每一块在频率域内进行建模,在思路上也是一大创新;另外,作者没有保留全部DCT系数,而是抽取了变换后的表示低频信息的系数(这样能减少细节信息,保留结构信息,提高对噪声和光照的影响)对背景进行建模,减少了计算量。当然,这篇文章也存在不足,基于Patch的检测对于检测精度要求较高的场合是不适应,而且在对于一些本来就不相连的目标,通过Patch-based的检测后,可能就粘连在了一起,尤其是对于还后面多目标跟踪或目标识别等影响还是比较大的。
本人也对原文算法进行了实验,但能力有限,算法实现过程中,存在一些问题,有兴趣的朋友可以进行分析下(问题主要在DctDetect类的detect()函数中),当然也可以通过文后的链接来直接下载。
头文件DctDetect.hpp如下:
程序代码下载地址:基于DCT系数背景建模与运动目标检测算法V1.0
初步查阅该文献,是由于网上的一篇博文,对该文进行了大肆的褒扬,遂对该文产生了一定的兴趣,这或许也和自己的背景相关,一直以来也在从事这方面的研究和工作。论文的思想很简单,大致描述如下:将图像分成4×4互不重叠的patches,然后对每一patch进行dct(离散余弦变换)变换(DCT与ICA和PCA的区别请参考相关文献),接着提取dct系数的低频成分作为特征,进行背景建模;而对于新输入的图像帧,则做同样处理,与抽取的背景模型特征进行比较,判断是否相似,采取空间邻域机制对噪声进行控制,达到准确前景提取的目的。下面根据论文的框架对每一部分进行详细介绍。
1)背景建模(Background Modelling)
背景模型是由多个dct系数向量组成的,不同空间的背景Patches可能有不同的coefficient vectors。对于每一patche,按照DCT公式进行变换,如式(1):
变换后,则可以得到DCT系数矩阵,如图1所示:
根据DCT变换的特点,抽取位置为(1,2)、(1,3)、(2,1)、(2,2)、(3,1)五个系数构成系数矩阵,作为背景模型。对每一Patch依次这样处理,则完成了背景模型的建立。
2)背景模型自适应 (Background Adaptation)
考虑到场景的动态变化以及噪声的影响,根据上面建立的背景模型难以对噪声和动态场景具有适应性,为了满足动态场景的需求,有必要对背景模型的自适应进行深入的研究。对于一个
newly coming patch,提取系数向量(Coefficient Vector),与背景模型进行比较,判断是否相似,相似的判断依据是两个向量的夹角是否大于某一阈值,如果匹配,则找到最匹配的模型,并对该模型对应的权重系数进行如下更新:
其中Tinc和Tdec是常量,alphai是该模型对应的权重,每个模型初始化的权重为Tinc。如果没有匹配上,这后面的就是重点,这时就需要判断该Patch在上一帧的邻域范围内是否有最可能的前景(Almost
Foreground)Patch,如果没有,则判为Almost Foreground Patch,并将其融入背景模型中。
3)前景检测(Foreground Detection)
前景Patch的判断与前景的背景自适应差不多,这里不再细说。只是提下,文章中将长期滞留在场景中的运动目标融入了背景模型,这样能提高算法的性能,当然有特殊需求的(如遗留物检测等)可能需要保留滞留在场景中的物体。
最后,加点个人见解。我们常规的对背景进行建模都是在空间域进行的,而作者将图像分成Patches,对每一Patch都采用DCT变换,对每一块在频率域内进行建模,在思路上也是一大创新;另外,作者没有保留全部DCT系数,而是抽取了变换后的表示低频信息的系数(这样能减少细节信息,保留结构信息,提高对噪声和光照的影响)对背景进行建模,减少了计算量。当然,这篇文章也存在不足,基于Patch的检测对于检测精度要求较高的场合是不适应,而且在对于一些本来就不相连的目标,通过Patch-based的检测后,可能就粘连在了一起,尤其是对于还后面多目标跟踪或目标识别等影响还是比较大的。
本人也对原文算法进行了实验,但能力有限,算法实现过程中,存在一些问题,有兴趣的朋友可以进行分析下(问题主要在DctDetect类的detect()函数中),当然也可以通过文后的链接来直接下载。
头文件DctDetect.hpp如下:
#pragma once #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <cmath> #include <iostream> using namespace std; using namespace cv; //Bounding Boxes struct BoundingBox : public cv::Rect { BoundingBox(){} BoundingBox(cv::Rect r): cv::Rect(r){} public: int status; // 状态:0 表示背景,1表示前景,2表示可能前景 int count; // 标注为前景的次数 int prev_status; // 上次的状态 }; typedef struct _Elem { vector<float> m_data; float m_weight; }ELEM; // 定义新的数据结构 typedef vector<ELEM> DATA; // 冲定义数据类型 class DctDetect { public: DctDetect(void); DctDetect(Mat& frame ); void detect( Mat& frame); // 检测 Mat& getForeground(){ return m_foreground;} ~DctDetect(void); private: void calcDct(Mat& frame, vector<float>& coff); float calcDist( vector<float>& coff1, vector<float>& coff2); void buildGrid( Mat& frame, Rect& box); float dotProduct( vector<float>& coff1, vector<float>& coff2); bool checkNeighbor(int r,int c); void chageGridStatus(); private: int m_height; int m_width; Rect m_rect; int m_frmNum; int m_gridRows; // 模型的行数 int m_gridCols; // 模型的列数 Mat m_foreground; float m_threshold; // 阈值 float m_inc; float m_dec; vector<vector<BoundingBox>> m_grid; vector<vector<DATA>> m_model; };实现DctDetect.cpp文件如下:
#include "DctDetect.h" DctDetect::DctDetect(void) { } DctDetect::DctDetect(Mat& frame ) { m_frmNum = 0; m_gridCols = 0; m_gridRows = 0; m_inc = 1.0; m_dec = 0.1; //m_threshold = 0.50; m_threshold = sqrtf(3.0)/2.0; // cos(45°)= sqrtf(2.0)/2 m_height = frame.rows; m_width = frame.cols; m_rect.x = 0; m_rect.y = 0; m_rect.width = 4; m_rect.height = 4; m_foreground.create( m_height, m_width, CV_8UC1 ); buildGrid(frame, m_rect); vector<float> coff; ELEM _elem; vector<ELEM> _data; vector<DATA> v_data; for ( int i=0; i< m_gridRows; ++i ) { v_data.clear(); for ( int j=0; j< m_gridCols; ++j ) { _data.clear(); calcDct(frame(m_grid[i][j]), coff ); _elem.m_data = coff; _elem.m_weight = m_inc; _data.push_back( _elem ); v_data.push_back(_data); } m_model.push_back(v_data); } } void DctDetect::buildGrid(Mat& frame, Rect& box) { int width = box.width; int height = box.height; BoundingBox bbox; vector<BoundingBox> inGrid; for (int y=1;y<frame.rows-height;y+= height ) { inGrid.clear(); m_gridCols = 0; for (int x=1;x<frame.cols-width;x+=width) { bbox.x = x; bbox.y = y; bbox.width = width; bbox.height = height; bbox.status = -1; bbox.prev_status = 0; bbox.count = 0; inGrid.push_back(bbox); m_gridCols++; } m_grid.push_back(inGrid); m_gridRows++; } } // 计算DCT系数 void DctDetect::calcDct(Mat& frame, vector<float>& coff) { if ( frame.empty() ) return; Mat temp; if ( 1 == frame.channels()) frame.copyTo( temp); else cvtColor( frame, temp, CV_BGR2GRAY); Mat tempMat( frame.rows, frame.cols, CV_64FC1); Mat tempDct( frame.rows, frame.cols, CV_64FC1); temp.convertTo( tempMat, tempMat.type()); dct( tempMat, tempDct, CV_DXT_FORWARD ); // DCT变换 coff.clear(); coff.push_back((float)tempDct.at<double>(0,1) ); // 取值 ( 0,1 )、( 0,2 )、( 1,0 )、( 1,1 )、( 2,0 ) coff.push_back((float)tempDct.at<double>(0,2) ); coff.push_back((float)tempDct.at<double>(1,0) ); coff.push_back((float)tempDct.at<double>(1,1) ); coff.push_back((float)tempDct.at<double>(2,0) ); if ( !temp.empty()) temp.release(); if ( !tempMat.empty()) tempMat.release(); if ( !tempDct.empty()) tempDct.release(); } // 计算距离 float DctDetect::calcDist(vector<float>& coff1, vector<float>& coff2) { float d1 = norm( coff1 ); float d2 = norm( coff2 ); float d3 = dotProduct( coff1,coff2 ); if ( d2 <0.0001 ) return 1.0; else return d3/(d1*d2); } // 点积 float DctDetect::dotProduct( vector<float>& coff1, vector<float>& coff2) { size_t i = 0, n = coff1.size(); assert(coff1.size() == coff2.size()); float s = 0.0f; const float *ptr1 = &coff1[0], *ptr2 = &coff2[0]; for( ; i < n; i++ ) s += (float)ptr1[i]*ptr2[i]; return s; } // 检测邻域是否有前景,有则返回true bool DctDetect::checkNeighbor(int r,int c) { int count = 0; if ( (r-1) >=0 && m_grid[r-1][c].prev_status == 1) // 上面patch count++; if ( (c+1) < m_gridCols && m_grid[r][c+1].prev_status == 1) // 右边patch count++; if ( (r+1) < m_gridRows && m_grid[r+1][c].prev_status == 1) // 下面patch count++; if ( (c-1) >= 0 && m_grid[r][c-1].prev_status == 1) // 左边patch count++; if ( count > 1 ) return true; else return false; } void DctDetect::detect(Mat& frame) { m_foreground = 0; float dist = 0.0f; vector<float> coff; ELEM _elem; // 单个数据 vector<ELEM> _data; // 模型数据 for ( int i=0; i< m_gridRows; ++i ) { for ( int j=0; j< m_gridCols; ++j ) { calcDct(frame(m_grid[i][j]), coff ); _data = m_model[i][j]; int mNum = _data.size(); // 模型的个数 float fmax = FLT_MIN; int idx = -1; for ( int k=0; k<mNum; ++k ) { dist = calcDist( coff, _data[k].m_data ); if ( dist > fmax ) { fmax = dist; idx = j; } } // 匹配完成 if ( fmax > m_threshold ) // 匹配上 { for ( int k=0; k<mNum; ++k ) { if ( idx ==j ) // 匹配上的模型权重增加 m_model[i][j][k].m_weight +=m_inc ; else m_model[i][j][k].m_weight -=m_dec; } } else // 如果没有匹配上,则检测上次邻域内是否有前景 { bool isNeighbor = checkNeighbor(i,j); if ( isNeighbor ) // 如果邻域内有前景,则标注为前景区域 { m_foreground(m_grid[i][j]) =255; m_grid[i][j].count +=1; } else { m_grid[i][j].status = 1; _data = m_model[i][j]; // 加入背景模型 _elem.m_data = coff; _elem.m_weight = m_inc; _data.push_back( _elem ); m_model[i][j]= _data; } } // 剔除背景中值为负数的模型 vector<ELEM> _temp; _data = m_model[i][j]; mNum = _data.size(); for ( int k=0; k<mNum; ++k ) { if ( _data[k].m_weight<0) continue; else { if ( _data[k].m_weight>20.0 ) _data[k].m_weight = 20.0; _temp.push_back( _data[k] ); } } _data.clear(); _data.insert( _data.begin(), _temp.begin(), _temp.end()); m_model[i][j]= _data; } // end for j } // end for i chageGridStatus(); } void DctDetect::chageGridStatus() { for ( int i=0; i<m_gridRows; ++i ) { for ( int j=0; j<m_gridCols; ++j ) { m_grid[i][j].prev_status = m_grid[i][j].status ; m_grid[i][j].status = 0; } } } DctDetect::~DctDetect(void) { }论文下载地址:Real-Time Moving Object Detection for Video Surveillance
程序代码下载地址:基于DCT系数背景建模与运动目标检测算法V1.0
相关文章推荐
- 基于DCT系数的实时监控中运动目标检测
- C++基于OpenCV实现实时监控和运动检测记录
- 运动目标检测--基于YUV颜色空间检测
- 一种基于边缘的运动目标检测与跟踪算法
- 基于光流分析的运动目标快速检测与跟踪融合算法
- OpenCV之基于GMM的运动目标检测
- 基于坐标变换与随机Hough 变换的抛物线运动目标检测算法
- OpenCV_基于混合高斯模型GMM的运动目标检测
- 运动目标检测--基于YUV颜色空间检测
- 【计算机视觉】基于局部二值相似性模式(LBSP)的运动目标检测算法
- 基于BP算法的3维马尔可夫随机场运动目标检测
- 基于平均背景建模的运动目标检测
- 基于OpenCV的运动目标检测跟踪系统在PC上的软件设计流程
- 基于自组织背景减除的运动目标检测算法
- 基于OpenCV和Android的运动目标检测系统
- 基于Vibe算法的运动目标检测
- 我的OpenCV学习笔记(3):基于混合高斯模型GMM的运动目标检测
- 基于opencV的动态背景下运动目标检测及跟踪(修改版)
- 目标检测 - SSD MultiBox 理解 - 基于深度学习的实时目标检测
- OpenCV_基于混合高斯模型GMM的运动目标检测