2010-05-11 19:44:00 +02:00
|
|
|
// Background average sample code done with averages and done with codebooks
|
|
|
|
// (adapted from the OpenCV book sample)
|
|
|
|
//
|
|
|
|
// NOTE: To get the keyboard to work, you *have* to have one of the video windows be active
|
|
|
|
// and NOT the consule window.
|
|
|
|
//
|
|
|
|
// Gary Bradski Oct 3, 2008.
|
|
|
|
//
|
|
|
|
/* *************** License:**************************
|
|
|
|
Oct. 3, 2008
|
|
|
|
Right to use this code in any way you want without warrenty, support or any guarentee of it working.
|
|
|
|
|
|
|
|
BOOK: It would be nice if you cited it:
|
|
|
|
Learning OpenCV: Computer Vision with the OpenCV Library
|
|
|
|
by Gary Bradski and Adrian Kaehler
|
|
|
|
Published by O'Reilly Media, October 3, 2008
|
|
|
|
|
|
|
|
AVAILABLE AT:
|
|
|
|
http://www.amazon.com/Learning-OpenCV-Computer-Vision-Library/dp/0596516134
|
|
|
|
Or: http://oreilly.com/catalog/9780596516130/
|
|
|
|
ISBN-10: 0596516134 or: ISBN-13: 978-0596516130
|
|
|
|
************************************************** */
|
2011-08-04 18:09:04 +02:00
|
|
|
#include "opencv2/core/core.hpp"
|
|
|
|
#include "opencv2/video/background_segm.hpp"
|
|
|
|
#include "opencv2/imgproc/imgproc_c.h"
|
|
|
|
#include "opencv2/highgui/highgui.hpp"
|
2010-05-11 19:44:00 +02:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
2011-08-04 18:09:04 +02:00
|
|
|
using namespace std;
|
|
|
|
using namespace cv;
|
2010-11-26 18:59:40 +01:00
|
|
|
|
2010-05-11 19:44:00 +02:00
|
|
|
//VARIABLES for CODEBOOK METHOD:
|
|
|
|
CvBGCodeBookModel* model = 0;
|
|
|
|
const int NCHANNELS = 3;
|
|
|
|
bool ch[NCHANNELS]={true,true,true}; // This sets what channels should be adjusted for background bounds
|
|
|
|
|
2011-08-04 18:09:04 +02:00
|
|
|
void help()
|
2010-05-11 19:44:00 +02:00
|
|
|
{
|
|
|
|
printf("\nLearn background and find foreground using simple average and average difference learning method:\n"
|
2010-12-01 03:22:24 +01:00
|
|
|
"Originally from the book: Learning OpenCV by O'Reilly press\n"
|
2011-08-04 18:09:04 +02:00
|
|
|
"\nUSAGE:\n"
|
|
|
|
" bgfg_codebook [--nframes(-nf)=300] [--movie_filename(-mf)=tree.avi] [--camera(-c), use camera or not]\n"
|
2011-06-09 14:01:47 +02:00
|
|
|
"***Keep the focus on the video windows, NOT the consol***\n\n"
|
|
|
|
"INTERACTIVE PARAMETERS:\n"
|
|
|
|
"\tESC,q,Q - quit the program\n"
|
|
|
|
"\th - print this help\n"
|
|
|
|
"\tp - pause toggle\n"
|
|
|
|
"\ts - single step\n"
|
|
|
|
"\tr - run mode (single step off)\n"
|
|
|
|
"=== AVG PARAMS ===\n"
|
|
|
|
"\t- - bump high threshold UP by 0.25\n"
|
|
|
|
"\t= - bump high threshold DOWN by 0.25\n"
|
|
|
|
"\t[ - bump low threshold UP by 0.25\n"
|
|
|
|
"\t] - bump low threshold DOWN by 0.25\n"
|
|
|
|
"=== CODEBOOK PARAMS ===\n"
|
|
|
|
"\ty,u,v- only adjust channel 0(y) or 1(u) or 2(v) respectively\n"
|
|
|
|
"\ta - adjust all 3 channels at once\n"
|
|
|
|
"\tb - adjust both 2 and 3 at once\n"
|
|
|
|
"\ti,o - bump upper threshold up,down by 1\n"
|
|
|
|
"\tk,l - bump lower threshold up,down by 1\n"
|
|
|
|
"\tSPACE - reset the model\n"
|
2010-05-11 19:44:00 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
//USAGE: ch9_background startFrameCollection# endFrameCollection# [movie filename, else from camera]
|
|
|
|
//If from AVI, then optionally add HighAvg, LowAvg, HighCB_Y LowCB_Y HighCB_U LowCB_U HighCB_V LowCB_V
|
|
|
|
//
|
2011-08-04 18:09:04 +02:00
|
|
|
const char *keys =
|
2010-05-11 19:44:00 +02:00
|
|
|
{
|
2011-08-04 18:09:04 +02:00
|
|
|
"{nf|nframes |300 |frames number}"
|
|
|
|
"{c |camera |false |use the camera or not}"
|
|
|
|
"{mf|movie_file|tree.avi |used movie video file}"
|
|
|
|
};
|
|
|
|
int main(int argc, const char** argv)
|
|
|
|
{
|
|
|
|
help();
|
|
|
|
|
|
|
|
CommandLineParser parser(argc, argv, keys);
|
|
|
|
int nframesToLearnBG = parser.get<int>("nf");
|
|
|
|
bool useCamera = parser.get<bool>("c");
|
|
|
|
string filename = parser.get<string>("mf");
|
2010-05-11 19:44:00 +02:00
|
|
|
IplImage* rawImage = 0, *yuvImage = 0; //yuvImage is for codebook method
|
|
|
|
IplImage *ImaskCodeBook = 0,*ImaskCodeBookCC = 0;
|
|
|
|
CvCapture* capture = 0;
|
2011-05-21 16:09:03 +02:00
|
|
|
|
2011-06-09 14:01:47 +02:00
|
|
|
int c, n, nframes = 0;
|
2010-05-11 19:44:00 +02:00
|
|
|
|
|
|
|
model = cvCreateBGCodeBookModel();
|
|
|
|
|
|
|
|
//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;
|
|
|
|
|
2011-08-04 18:09:04 +02:00
|
|
|
if( useCamera )
|
2011-06-09 14:01:47 +02:00
|
|
|
{
|
|
|
|
printf("Capture from camera\n");
|
|
|
|
capture = cvCaptureFromCAM( 0 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-08-04 18:09:04 +02:00
|
|
|
printf("Capture from file %s\n",filename.c_str());
|
|
|
|
capture = cvCreateFileCapture( filename.c_str() );
|
2011-06-09 14:01:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if( !capture )
|
|
|
|
{
|
|
|
|
printf( "Can not initialize video capturing\n\n" );
|
|
|
|
help();
|
|
|
|
return -1;
|
|
|
|
}
|
2010-05-11 19:44:00 +02:00
|
|
|
|
|
|
|
//MAIN PROCESSING LOOP:
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
if( !pause )
|
|
|
|
{
|
|
|
|
rawImage = cvQueryFrame( capture );
|
|
|
|
++nframes;
|
|
|
|
if(!rawImage)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( singlestep )
|
|
|
|
pause = true;
|
|
|
|
|
|
|
|
//First time:
|
|
|
|
if( nframes == 1 && rawImage )
|
|
|
|
{
|
|
|
|
// CODEBOOK METHOD ALLOCATION
|
|
|
|
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 we've got an rawImage and are good to go:
|
|
|
|
if( rawImage )
|
|
|
|
{
|
|
|
|
cvCvtColor( rawImage, yuvImage, CV_BGR2YCrCb );//YUV For codebook method
|
|
|
|
//This is where we build our background model
|
|
|
|
if( !pause && nframes-1 < nframesToLearnBG )
|
|
|
|
cvBGCodeBookUpdate( model, yuvImage );
|
|
|
|
|
|
|
|
if( nframes-1 == nframesToLearnBG )
|
|
|
|
cvBGCodeBookClearStale( model, model->t/2 );
|
|
|
|
|
|
|
|
//Find the foreground if any
|
|
|
|
if( nframes-1 >= nframesToLearnBG )
|
|
|
|
{
|
|
|
|
// Find foreground by codebook method
|
|
|
|
cvBGCodeBookDiff( model, yuvImage, ImaskCodeBook );
|
|
|
|
// 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(10)&0xFF;
|
|
|
|
c = tolower(c);
|
|
|
|
// End processing on ESC, q or Q
|
|
|
|
if(c == 27 || c == 'q')
|
|
|
|
break;
|
|
|
|
//Else check for user input
|
|
|
|
switch( c )
|
|
|
|
{
|
|
|
|
case 'h':
|
|
|
|
help();
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
pause = !pause;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
singlestep = !singlestep;
|
|
|
|
pause = false;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
pause = false;
|
|
|
|
singlestep = false;
|
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
cvBGCodeBookClearStale( model, 0 );
|
|
|
|
nframes = 0;
|
|
|
|
break;
|
|
|
|
//CODEBOOK PARAMS
|
|
|
|
case 'y': case '0':
|
|
|
|
case 'u': case '1':
|
|
|
|
case 'v': case '2':
|
|
|
|
case 'a': case '3':
|
|
|
|
case 'b':
|
|
|
|
ch[0] = c == 'y' || c == '0' || c == 'a' || c == '3';
|
|
|
|
ch[1] = c == 'u' || c == '1' || c == 'a' || c == '3' || c == 'b';
|
|
|
|
ch[2] = c == 'v' || c == '2' || c == 'a' || c == '3' || c == 'b';
|
|
|
|
printf("CodeBook YUV Channels active: %d, %d, %d\n", ch[0], ch[1], ch[2] );
|
|
|
|
break;
|
|
|
|
case 'i': //modify max classification bounds (max bound goes higher)
|
|
|
|
case 'o': //modify max classification bounds (max bound goes lower)
|
|
|
|
case 'k': //modify min classification bounds (min bound goes lower)
|
|
|
|
case 'l': //modify min classification bounds (min bound goes higher)
|
|
|
|
{
|
|
|
|
uchar* ptr = c == 'i' || c == 'o' ? model->modMax : model->modMin;
|
|
|
|
for(n=0; n<NCHANNELS; n++)
|
|
|
|
{
|
|
|
|
if( ch[n] )
|
|
|
|
{
|
|
|
|
int v = ptr[n] + (c == 'i' || c == 'l' ? 1 : -1);
|
2010-11-26 18:59:40 +01:00
|
|
|
ptr[n] = cv::saturate_cast<uchar>(v);
|
2010-05-11 19:44:00 +02:00
|
|
|
}
|
|
|
|
printf("%d,", ptr[n]);
|
|
|
|
}
|
|
|
|
printf(" CodeBook %s Side\n", c == 'i' || c == 'o' ? "High" : "Low" );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cvReleaseCapture( &capture );
|
|
|
|
cvDestroyWindow( "Raw" );
|
|
|
|
cvDestroyWindow( "ForegroundCodeBook");
|
|
|
|
cvDestroyWindow( "CodeBook_ConnectComp");
|
|
|
|
return 0;
|
|
|
|
}
|