基于DCT系数的实时监控中运动目标检测

 本文的主要内容来自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如下:

 

[cpp]  view plaincopy
  1. #pragma once  
  2. #include <opencv2/core/core.hpp>  
  3. #include <opencv2/highgui/highgui.hpp>  
  4. #include <opencv2/imgproc/imgproc.hpp>  
  5. #include <cmath>  
  6. #include <iostream>  
  7. using namespace std;  
  8. using namespace cv;  
  9.   
  10. //Bounding Boxes  
  11. struct BoundingBox : public cv::Rect {  
  12.     BoundingBox(){}  
  13.     BoundingBox(cv::Rect r): cv::Rect(r){}  
  14. public:   
  15.     int status; // 状态:0 表示背景,1表示前景,2表示可能前景  
  16.     int count; // 标注为前景的次数  
  17.     int prev_status; // 上次的状态  
  18. };  
  19.   
  20. typedef struct _Elem   
  21. {  
  22.     vector<float> m_data;  
  23.     float m_weight;  
  24. }ELEM;  // 定义新的数据结构  
  25.   
  26. typedef vector<ELEM> DATA;  // 冲定义数据类型  
  27.   
  28. class DctDetect  
  29. {  
  30. public:  
  31.     DctDetect(void);  
  32.     DctDetect(Mat& frame );  
  33.     void detect( Mat& frame); // 检测  
  34.     Mat& getForeground(){ return m_foreground;}  
  35.   
  36.     ~DctDetect(void);  
  37.   
  38. private:  
  39.     void calcDct(Mat& frame, vector<float>& coff);  
  40.     float calcDist( vector<float>& coff1, vector<float>& coff2);  
  41.     void buildGrid( Mat& frame, Rect& box);  
  42.     float dotProduct( vector<float>& coff1, vector<float>& coff2);  
  43.     bool checkNeighbor(int r,int c);  
  44.     void chageGridStatus();  
  45.   
  46. private:  
  47.     int m_height;  
  48.     int m_width;  
  49.     Rect m_rect;  
  50.     int m_frmNum;  
  51.     int m_gridRows; // 模型的行数  
  52.     int m_gridCols; // 模型的列数  
  53.     Mat m_foreground;  
  54.     float m_threshold;  // 阈值  
  55.     float m_inc;  
  56.     float m_dec;  
  57.     vector<vector<BoundingBox>> m_grid;  
  58.     vector<vector<DATA>> m_model;  
  59. };  

        实现DctDetect.cpp文件如下:

 

 

[cpp]  view plaincopy
  1. #include "DctDetect.h"  
  2.   
  3. DctDetect::DctDetect(void)  
  4. {  
  5.   
  6. }  
  7.   
  8. DctDetect::DctDetect(Mat& frame )  
  9. {  
  10.     m_frmNum = 0;  
  11.     m_gridCols = 0;  
  12.     m_gridRows = 0;  
  13.     m_inc = 1.0;  
  14.     m_dec = 0.1;  
  15.     //m_threshold = 0.50;  
  16.     m_threshold = sqrtf(3.0)/2.0;  // cos(45°)= sqrtf(2.0)/2      
  17.     m_height = frame.rows;  
  18.     m_width = frame.cols;  
  19.     m_rect.x = 0;  
  20.     m_rect.y = 0;  
  21.     m_rect.width = 4;  
  22.     m_rect.height = 4;  
  23.     m_foreground.create( m_height, m_width, CV_8UC1 );  
  24.     buildGrid(frame, m_rect);  
  25.   
  26.     vector<float> coff;     
  27.     ELEM _elem;  
  28.     vector<ELEM> _data;  
  29.     vector<DATA> v_data;  
  30.       
  31.     for ( int i=0; i< m_gridRows; ++i )  
  32.     {  
  33.         v_data.clear();  
  34.         for ( int j=0; j< m_gridCols; ++j )  
  35.         {  
  36.             _data.clear();  
  37.             calcDct(frame(m_grid[i][j]), coff );      
  38.             _elem.m_data = coff;  
  39.             _elem.m_weight = m_inc;  
  40.             _data.push_back( _elem );     
  41.             v_data.push_back(_data);  
  42.         }     
  43.         m_model.push_back(v_data);        
  44.     }  
  45. }  
  46.   
  47.   
  48. void DctDetect::buildGrid(Mat& frame, Rect& box)  
  49. {  
  50.     int width =  box.width;  
  51.     int height = box.height;      
  52.     BoundingBox bbox;  
  53.     vector<BoundingBox> inGrid;  
  54.     for (int y=1;y<frame.rows-height;y+= height )  
  55.     {  
  56.         inGrid.clear();  
  57.         m_gridCols = 0;  
  58.         for (int x=1;x<frame.cols-width;x+=width)  
  59.         {  
  60.             bbox.x = x;  
  61.             bbox.y = y;  
  62.             bbox.width = width;  
  63.             bbox.height = height;  
  64.             bbox.status = -1;  
  65.             bbox.prev_status = 0;  
  66.             bbox.count = 0;  
  67.             inGrid.push_back(bbox);  
  68.             m_gridCols++;  
  69.         }  
  70.         m_grid.push_back(inGrid);  
  71.         m_gridRows++;  
  72.     }     
  73. }  
  74.   
  75.   
  76. // 计算DCT系数  
  77. void DctDetect::calcDct(Mat& frame, vector<float>& coff)  
  78. {  
  79.     if ( frame.empty() )      
  80.         return;  
  81.   
  82.     Mat temp;  
  83.     if ( 1 == frame.channels())  
  84.         frame.copyTo( temp);  
  85.     else  
  86.         cvtColor( frame, temp, CV_BGR2GRAY);  
  87.   
  88.     Mat tempMat( frame.rows, frame.cols, CV_64FC1);  
  89.     Mat tempDct( frame.rows, frame.cols, CV_64FC1);  
  90.     temp.convertTo( tempMat, tempMat.type());     
  91.     dct( tempMat, tempDct, CV_DXT_FORWARD );    // DCT变换  
  92.   
  93.     coff.clear();  
  94.     coff.push_back((float)tempDct.at<double>(0,1) );  // 取值 ( 0,1 )、( 0,2 )、( 1,0 )、( 1,1 )、( 2,0 )  
  95.     coff.push_back((float)tempDct.at<double>(0,2) );   
  96.     coff.push_back((float)tempDct.at<double>(1,0) );   
  97.     coff.push_back((float)tempDct.at<double>(1,1) );   
  98.     coff.push_back((float)tempDct.at<double>(2,0) );   
  99.   
  100.     if ( !temp.empty())  
  101.         temp.release();  
  102.     if ( !tempMat.empty())  
  103.         tempMat.release();    
  104.     if ( !tempDct.empty())  
  105.         tempDct.release();    
  106. }  
  107.   
  108. // 计算距离  
  109. float DctDetect::calcDist(vector<float>& coff1, vector<float>& coff2)  
  110. {  
  111.     float d1 = norm( coff1 );  
  112.     float d2 = norm( coff2 );  
  113.     float d3 = dotProduct( coff1,coff2 );  
  114.     if ( d2 <0.0001 )      
  115.         return 1.0;  
  116.     else  
  117.         return d3/(d1*d2);  
  118. }  
  119.   
  120. // 点积  
  121. float DctDetect::dotProduct( vector<float>& coff1, vector<float>& coff2)  
  122. {  
  123.     size_t i = 0, n = coff1.size();  
  124.     assert(coff1.size() == coff2.size());  
  125.     float s = 0.0f;  
  126.     const float *ptr1 = &coff1[0], *ptr2 = &coff2[0];  
  127.     for( ; i < n; i++ )  
  128.         s += (float)ptr1[i]*ptr2[i];  
  129.     return s;     
  130. }  
  131.   
  132. // 检测邻域是否有前景,有则返回true  
  133. bool DctDetect::checkNeighbor(int r,int c)  
  134. {  
  135.     int count = 0;    
  136.     if ( (r-1) >=0 && m_grid[r-1][c].prev_status == 1)  // 上面patch  
  137.         count++;  
  138.     if ( (c+1) < m_gridCols && m_grid[r][c+1].prev_status == 1)  // 右边patch  
  139.         count++;  
  140.     if ( (r+1) < m_gridRows && m_grid[r+1][c].prev_status == 1)  // 下面patch  
  141.         count++;  
  142.     if ( (c-1) >= 0 && m_grid[r][c-1].prev_status == 1)  // 左边patch  
  143.         count++;  
  144.   
  145.     if ( count > 1 )  
  146.         return true;  
  147.     else  
  148.         return false;     
  149. }  
  150.   
  151.   
  152. void DctDetect::detect(Mat& frame)  
  153. {  
  154.     m_foreground = 0;  
  155.     float dist = 0.0f;  
  156.   
  157.     vector<float> coff;  
  158.     ELEM _elem;  // 单个数据  
  159.     vector<ELEM> _data; // 模型数据  
  160.   
  161.     for ( int i=0; i< m_gridRows; ++i )  
  162.     {  
  163.         for ( int j=0; j< m_gridCols; ++j )  
  164.         {  
  165.             calcDct(frame(m_grid[i][j]), coff );      
  166.             _data = m_model[i][j];  
  167.             int mNum = _data.size(); // 模型的个数  
  168.   
  169.             float fmax = FLT_MIN;  
  170.             int idx = -1;  
  171.             for ( int k=0; k<mNum; ++k )  
  172.             {  
  173.                 dist = calcDist( coff, _data[k].m_data );  
  174.                 if ( dist > fmax )  
  175.                 {  
  176.                     fmax = dist;  
  177.                     idx = j;  
  178.                 }  
  179.             } // 匹配完成  
  180.             if ( fmax > m_threshold )  // 匹配上  
  181.             {  
  182.                 for ( int k=0; k<mNum; ++k )   
  183.                 {  
  184.                     if ( idx ==j )  // 匹配上的模型权重增加             
  185.                         m_model[i][j][k].m_weight +=m_inc ;               
  186.                     else                  
  187.                         m_model[i][j][k].m_weight -=m_dec;            
  188.                 }  
  189.             }  
  190.             else  // 如果没有匹配上,则检测上次邻域内是否有前景  
  191.             {     
  192.                 bool isNeighbor = checkNeighbor(i,j);  
  193.                 if ( isNeighbor )  // 如果邻域内有前景,则标注为前景区域  
  194.                 {  
  195.                     m_foreground(m_grid[i][j]) =255;  
  196.                     m_grid[i][j].count +=1;  
  197.                 }  
  198.                 else  
  199.                 {                         
  200.                     m_grid[i][j].status = 1;                                      
  201.                     _data = m_model[i][j]; // 加入背景模型  
  202.                     _elem.m_data = coff;  
  203.                     _elem.m_weight = m_inc;  
  204.                     _data.push_back( _elem );  
  205.                     m_model[i][j]= _data;  
  206.                 }             
  207.                                   
  208.             }  
  209.           
  210.             // 剔除背景中值为负数的模型  
  211.             vector<ELEM> _temp;  
  212.             _data = m_model[i][j];  
  213.             mNum = _data.size();  
  214.             for ( int k=0; k<mNum; ++k )  
  215.             {  
  216.                 if ( _data[k].m_weight<0)  
  217.                     continue;  
  218.                 else   
  219.                 {  
  220.                     if ( _data[k].m_weight>20.0 )  
  221.                         _data[k].m_weight = 20.0;  
  222.                     _temp.push_back( _data[k] );  
  223.                 }  
  224.             }  
  225.             _data.clear();  
  226.             _data.insert( _data.begin(), _temp.begin(), _temp.end());  
  227.             m_model[i][j]= _data;  
  228.   
  229.         }  // end for j  
  230.     } // end for i  
  231.       
  232.     chageGridStatus();  
  233. }  
  234.   
  235. void DctDetect::chageGridStatus()  
  236. {  
  237.     for ( int i=0; i<m_gridRows; ++i )  
  238.     {  
  239.         for ( int j=0; j<m_gridCols; ++j )  
  240.         {  
  241.             m_grid[i][j].prev_status = m_grid[i][j].status ;  
  242.             m_grid[i][j].status = 0;   
  243.         }  
  244.     }  
  245. }  
  246.   
  247. DctDetect::~DctDetect(void)  
  248. {  
  249. }  

     论文下载地址:Real-Time Moving Object Detection for Video Surveillance

     程序代码下载地址:基于DCT系数背景建模与运动目标检测算法V1.0

转载于:https://www.cnblogs.com/ywsoftware/p/4502356.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值