Skip to content

Instantly share code, notes, and snippets.

@joshuajnoble
Last active December 21, 2015 13:49
Show Gist options
  • Save joshuajnoble/6315618 to your computer and use it in GitHub Desktop.
Save joshuajnoble/6315618 to your computer and use it in GitHub Desktop.
Using Background subtraction in Cinder
#include "cinder/app/AppBasic.h"
#include "cinder/gl/gl.h"
#include "cinder/gl/Texture.h"
#include "cinder/Capture.h"
#include "CinderOpenCV.h"
using namespace ci;
using namespace ci::app;
using namespace std;
class bgSubtractApp : public AppBasic {
public:
void setup();
void keyDown(KeyEvent key);
void update();
void draw();
cv::BackgroundSubtractorMOG bgsubtractor;
vector< vector<cv::Point> > mContours;
vector<PolyLine2f> mContourLine;
bool mUpdateBackground;
Capture mCapture;
Surface mCaptureSurf;
gl::Texture mForegroundTexture, mBackgroundTexture;
int mDrawMode;
};
void bgSubtractApp::setup()
{
mDrawMode = 0;
// we want to start with the background updating
mUpdateBackground = true;
// make some textures to draw into
gl::Texture::Format fmt;
mForegroundTexture = gl::Texture(640, 480, fmt);
mBackgroundTexture = gl::Texture(640, 480, fmt);
mCapture = Capture(640, 480);
mCapture.start();
}
void bgSubtractApp::keyDown(KeyEvent key) {
mDrawMode++;
if(mDrawMode > 2) {
mDrawMode = 0;
}
}
void bgSubtractApp::update()
{
if(mCapture.checkNewFrame()) {
if(getElapsedFrames() % 120 == 0) { // only do this only every 4 secs or so
mUpdateBackground = true;
}
mCaptureSurf = mCapture.getSurface();
cv::Mat working, newFrame, fgFrame;
newFrame = toOcv( mCaptureSurf ); // capture the frame
// case you're wondering, this is overloaded (), not a constructor call
bgsubtractor(newFrame, fgFrame, mUpdateBackground ? 1 : 0);
mUpdateBackground = false;
int numberOfIters = 3;
vector<cv::Vec4i> hierarchy;
cv::dilate(fgFrame, working, cv::Mat(), cv::Point(-1,-1), numberOfIters);
cv::erode(working, working, cv::Mat(), cv::Point(-1,-1), numberOfIters * 2);
cv::dilate(working, working, cv::Mat(), cv::Point(-1,-1), numberOfIters);
mContours.clear();
// get all the contours now
cv::findContours( working, mContours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
// now copy them into a
mContourLine.clear();
for( int i = 0; i < mContours.size(); i++) {
mContourLine.push_back(PolyLine2f());
for( int j = 0; j < mContours[i].size(); j++) {
mContourLine.at(i).push_back(Vec2f(mContours[i][j].x, mContours[i][j].y) );
}
}
if( mContours.size() == 0 )
return;
// we're going to ^ the mask
cv::Mat filledFG, filledBG;
filledBG = cv::Mat::zeros(fgFrame.size(), CV_32F);
filledFG = cv::Mat::zeros(fgFrame.size(), CV_32F);
// get the foreground
newFrame.copyTo(filledFG, fgFrame);
// now get the background
newFrame.copyTo(filledBG, 255 - fgFrame);
mBackgroundTexture.update( Surface(fromOcv(filledBG) ));
mForegroundTexture.update( Surface(fromOcv(filledFG) ));
}
}
void bgSubtractApp::draw()
{
// clear out the window with black
gl::clear( Color( 0, 0, 0 ) );
switch (mDrawMode) {
case 0:
if(mBackgroundTexture)
gl::draw(mBackgroundTexture);
break;
case 1:
if(mForegroundTexture)
gl::draw(mForegroundTexture);
break;
case 2:
for( int i = 0; i < mContourLine.size(); i++) {
gl::draw(mContourLine.at(i));
}
break;
}
}
CINDER_APP_BASIC( bgSubtractApp, RendererGl )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment