简介
在本篇中,我们分别使用opencv提供的方法:BackgroundSubtractorMOG 和 CvBGCodeBookModel两种方式来实现video的运动跟踪。
BackgroundSubtractorMOG
在这里,首先要感谢:http://blog.csdn.net/yang_xian521/article/details/6991002 这篇blog的博主,非常感谢该博主,这里使用的实例来源于它。
具体代码
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/video/video.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main( int argc, char ** argv) {
Mat frame;
Mat foreground; // 前景图片
VideoCapture capture( argv[ 1 ] ) ;
if ( ! capture.isOpened ( ) )
{
return 0 ;
}
namedWindow( "Extracted Foreground" ) ;
namedWindow( "Source Video" ) ;
// 混合高斯物体
BackgroundSubtractorMOG mog;
bool stop( false ) ;
while ( ! stop)
{
if ( ! capture.read ( frame) )
{
break ;
}
// 更新背景图片并且输出前景
mog( frame, foreground, 0.01 ) ;
// 输出的前景图片并不是2值图片,要处理一下显示
threshold( foreground, foreground, 128 , 255 , THRESH_BINARY_INV) ;
// show foreground
imshow( "Extracted Foreground" , foreground) ;
imshow( "Source Video" , frame) ;
if ( waitKey( 10 ) == 27 )
{
stop = true ;
}
}
}
效果演示
具体的代码讲解,请看之前提到的那个博客上有详细的描述。
具体效果如下:
CvBGCodeBookModel
这个是实例是有opencv官方提供的实例bgfg_codebook.cpp简化而来。
具体代码
#include "opencv2/core/core.hpp"
#include "opencv2/video/background_segm.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/legacy/legacy.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
using namespace std;
using namespace cv;
CvBGCodeBookModel* model = 0 ;
const int NCHANNELS = 3 ;
bool ch[ NCHANNELS] = { true , true , true } ; // This sets what channels should be adjusted for background bounds
int main( int argc, const char ** argv) {
int nframesToLearnBG = <a href="http://www.opengroup.org/onlinepubs/%3Cspan%20class=" nu19"="" style="text-decoration: none; color: rgb(11, 0, 128); background-image: none; background-position: initial initial; background-repeat: initial initial;">009695399/ functions/ atoi.html">atoi ( argv[ 1 ] ) ;
string filename = argv[ 2 ] ;
IplImage* rawImage = 0 , * yuvImage = 0 ; //yuvImage is for codebook method
IplImage * ImaskCodeBook = 0 ,* ImaskCodeBookCC = 0 ;
CvCapture* capture = 0 ;
int c, n, nframes = 0 ;
model = cvCreateBGCodeBookModel( ) ; //codebook方法中,初始化
//Set color thresholds to default values
model-> modMin[ 0 ] = 3 ;
model-> modMin[ 1 ] = model-> modMin[ 2 ] = 3 ;
model-> modMax[ 0 ] = 10 ;
model-> modMax[ 1 ] = model-> modMax[ 2 ] = 10 ;
model-> cbBounds[ 0 ] = model-> cbBounds[ 1 ] = model-> cbBounds[ 2 ] = 10 ;
bool pause = false ;
bool singlestep = false ;
capture = cvCreateFileCapture( filename.c_str ( ) ) ;
if ( ! capture ) {
return - 1 ;
}
//MAIN PROCESSING LOOP:
for ( ;; ) {
if ( ! pause) {
rawImage = cvQueryFrame( capture) ;
++ nframes;
if ( ! rawImage)
break ;
}
if ( singlestep)
pause = true ;
//First time:
if ( nframes == 1 && rawImage) {
yuvImage = cvCloneImage( rawImage) ;
ImaskCodeBook = cvCreateImage( cvGetSize( rawImage) , IPL_DEPTH_8U, 1 ) ;
ImaskCodeBookCC = cvCreateImage( cvGetSize( rawImage) , IPL_DEPTH_8U, 1 ) ;
cvSet( ImaskCodeBook, cvScalar( 255 ) ) ;
cvNamedWindow( "Raw" , 1 ) ;
cvNamedWindow( "ForegroundCodeBook" , 1 ) ;
cvNamedWindow( "CodeBook_ConnectComp" , 1 ) ;
}
if ( rawImage) {
cvCvtColor( rawImage, yuvImage, CV_BGR2YCrCb) ; //YUV For codebook method
if ( ! pause && nframes- 1 < nframesToLearnBG)
cvBGCodeBookUpdate( model, yuvImage ) ; //codebook方法中,更新背景模型
if ( nframes- 1 == nframesToLearnBG)
cvBGCodeBookClearStale( model, model-> t/ 2 ) ; //清除消极的codebook
if ( nframes- 1 >= nframesToLearnBG) {
// Find foreground by codebook method
cvBGCodeBookDiff( model, yuvImage, ImaskCodeBook) ; //codebook方法中,背景减除
// This part just to visualize bounding boxes and centers if desired
cvCopy( ImaskCodeBook, ImaskCodeBookCC) ;
cvSegmentFGMask( ImaskCodeBookCC) ;
}
//Display
cvShowImage( "Raw" , rawImage) ;
cvShowImage( "ForegroundCodeBook" , ImaskCodeBook) ;
cvShowImage( "CodeBook_ConnectComp" , ImaskCodeBookCC) ;
}
// User input:
c = cvWaitKey( 100 ) & 0xFF ;
}
cvReleaseCapture( & capture ) ;
cvDestroyWindow( "Raw" ) ;
cvDestroyWindow( "ForegroundCodeBook" ) ;
cvDestroyWindow( "CodeBook_ConnectComp" ) ;
return 0 ;
}
代码讲解
1、运行时候需要传入两个参数:(1)背景计算的帧数. (2)使用的video文件。
int nframesToLearnBG = <a href="http://www.opengroup.org/onlinepubs/%3Cspan%20class=" nu19"="" style="text-decoration: none; color: rgb(11, 0, 128); background-image: none; background-position: initial initial; background-repeat: initial initial;">009695399/ functions/ atoi.html">atoi ( argv[ 1 ] ) ;
string filename = argv[ 2 ] ;
2、初始化codebook,设置它计算使用的的相关阀值。
CvBGCodeBookModel* model = 0 ;
model = cvCreateBGCodeBookModel( ) ; //codebook方法中,初始化
//Set color thresholds to default values
model-> modMin[ 0 ] = 3 ;
model-> modMin[ 1 ] = model-> modMin[ 2 ] = 3 ;
model-> modMax[ 0 ] = 10 ;
model-> modMax[ 1 ] = model-> modMax[ 2 ] = 10 ;
model-> cbBounds[ 0 ] = model-> cbBounds[ 1 ] = model-> cbBounds[ 2 ] = 10 ;
3、打开传入的video文件。
capture = cvCreateFileCapture( filename.c_str ( ) ) ;
if ( ! capture ) {
<a href="http://www.opengroup.org/onlinepubs/%3Cspan%20class=" nu19"="" style="text-decoration: none; color: rgb(11, 0, 128); background-image: none; background-position: initial initial; background-repeat: initial initial;">009695399/ functions/ printf.html">printf ( "Can not initialize video capturing\n \n " ) ;
return - 1 ;
}
4、在for的死循环中,不断的从video文件中去出一帧数据。
rawImage = cvQueryFrame( capture) ;
++ nframes;
if ( ! rawImage)
break ;
5、如果是处理第一帧数据,初始化之后会使用的图像:yuvImage ImaskCodeBook ImaskCodeBookCC和创建相关的显示窗口。
if ( nframes == 1 && rawImage) {
yuvImage = cvCloneImage( rawImage) ;
ImaskCodeBook = cvCreateImage( cvGetSize( rawImage) , IPL_DEPTH_8U, 1 ) ;
ImaskCodeBookCC = cvCreateImage( cvGetSize( rawImage) , IPL_DEPTH_8U, 1 ) ;
cvSet( ImaskCodeBook, cvScalar( 255 ) ) ;
cvNamedWindow( "Raw" , 1 ) ;
cvNamedWindow( "ForegroundCodeBook" , 1 ) ;
cvNamedWindow( "CodeBook_ConnectComp" , 1 ) ;
}
6、首先将处理图像转换成yuv,然后如果当前处理的帧数小于之前传入的背景计算帧数,则使用cvBGCodeBookUpdate进行背景模型跟踪。如果当前帧数等于之前传入的背景
计算帧数,则使用cvBGCodeBookClearStale清除消极的codebook,到了这一步就相当于背景部分训练计算完成。
cvCvtColor( rawImage, yuvImage, CV_BGR2YCrCb) ; //YUV For codebook method
if ( ! pause && nframes- 1 < nframesToLearnBG)
cvBGCodeBookUpdate( model, yuvImage ) ; //codebook方法中,更新背景模型
if ( nframes- 1 == nframesToLearnBG)
cvBGCodeBookClearStale( model, model-> t/ 2 ) ; //清除消极的codebook
7、使用cvBGCodeBookDiff来进行背景减除,获得运动部分的图像,保存在ImaskCodeBook中。接着使用cvSegmentFGMask做连通域分割,从而获得更好的运动图像,保存在
ImaskCodeBookCC中。
if ( nframes- 1 >= nframesToLearnBG) {
// Find foreground by codebook method
cvBGCodeBookDiff( model, yuvImage, ImaskCodeBook) ; //codebook方法中,背景减除
// This part just to visualize bounding boxes and centers if desired
cvCopy( ImaskCodeBook, ImaskCodeBookCC) ;
cvSegmentFGMask( ImaskCodeBookCC) ;
}
8、最后将原始图像(rawImage)、背景减去之后图像(ImaskCodeBook)和连通域分割后图像(ImaskCodeBookCC)分别显示出来。
//Display
cvShowImage( "Raw" , rawImage) ;
cvShowImage( "ForegroundCodeBook" , ImaskCodeBook) ;
cvShowImage( "CodeBook_ConnectComp" , ImaskCodeBookCC) ;
效果演示
最后对应的效果演示如下:
原始图像
背景减去之后图像
连通域分割后图像