Skip to content

Instantly share code, notes, and snippets.

@fieldOfView
Created October 16, 2012 08:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fieldOfView/3898078 to your computer and use it in GitHub Desktop.
Save fieldOfView/3898078 to your computer and use it in GitHub Desktop.
A quick (and dirty?) image averager in Cinder. Uses a 32 bit (floating point) Fbo to accumulate frames.
#include "cinder/Cinder.h"
#include "cinder/app/AppBasic.h"
#include "cinder/ImageIo.h"
#include "cinder/Utilities.h"
#include "cinder/gl/Texture.h"
#include "cinder/Capture.h"
#include "cinder/gl/Fbo.h"
using namespace ci;
using namespace ci::app;
class CaptureApp : public AppBasic {
public:
void setup();
void keyDown( KeyEvent event );
void update();
void draw();
void clearImage();
void saveImage();
void saveBuffer();
Capture mCapture;
gl::Texture mTexture;
gl::Fbo mRenderBuffer;
unsigned int mFrames;
bool mLive;
bool mCapturing;
};
void CaptureApp::setup()
{
try {
mCapture = Capture( 1920, 1080 );
mCapture.start();
}
catch( ... ) {
console() << "Failed to initialize capture" << std::endl;
}
gl::Fbo::Format fmt;
fmt.setColorInternalFormat( GL_RGB32F_ARB );
mRenderBuffer = gl::Fbo( mCapture.getWidth(), mCapture.getHeight(), fmt );
mFrames = 0;
mLive = false;
mCapturing = true;
}
void CaptureApp::keyDown( KeyEvent event )
{
switch( event.getCode() ) {
case KeyEvent::KEY_f:
// toggle fullscreen
setFullScreen( ! isFullScreen() );
break;
case KeyEvent::KEY_SPACE:
// pause/resume
mCapturing = !mCapturing;
break;
case KeyEvent::KEY_l:
// toggle live preview/accumulated result
mLive = !mLive;
break;
case KeyEvent::KEY_c:
// clear renderbuffer
clearImage();
break;
case KeyEvent::KEY_s:
// save result
saveImage();
break;
case KeyEvent::KEY_b:
// save buffer
saveBuffer();
break;
}
}
void CaptureApp::update()
{
if( mCapture && mCapture.checkNewFrame() ) {
mTexture = gl::Texture( mCapture.getSurface() );
if( mCapturing ) {
// bind the FBO, so we can draw on it
mRenderBuffer.bindFramebuffer();
// set the correct viewport and matrices
glPushAttrib( GL_VIEWPORT_BIT );
gl::setViewport( mRenderBuffer.getBounds() );
gl::pushMatrices();
gl::setMatricesWindow( mRenderBuffer.getSize() );
// enable additive blending
gl::enableAdditiveBlending();
// draw Fbo upsidedown, because...
Rectf bufferRect = Rectf( 0, (float)mRenderBuffer.getHeight(), (float)mRenderBuffer.getWidth(), 0 );
gl::draw( mTexture, mTexture.getBounds(), bufferRect );
gl::disableAlphaBlending();
// restore matrices and viewport
gl::popMatrices();
glPopAttrib();
// unbind the FBO to stop drawing on it
mRenderBuffer.unbindFramebuffer();
// Increase frame count
mFrames++;
}
}
}
void CaptureApp::draw()
{
gl::clear( Color( 0.0f, 0.0f, 0.0f ));
if( !mLive ) {
if( mFrames > 0 ) {
float factor = 1.0f / (float)mFrames;
gl::color( Color( factor, factor, factor ));
gl::draw( mRenderBuffer.getTexture(), Rectf( mRenderBuffer.getBounds() ).getCenteredFit( getWindowBounds(), true ));
gl::color( Color( 1.0f, 1.0f, 1.0f ));
}
} else {
gl::draw( mTexture, Rectf( mTexture.getBounds() ).getCenteredFit( getWindowBounds(), true ));
}
}
void CaptureApp::clearImage()
{
mRenderBuffer.bindFramebuffer();
gl::clear( Color( 0.0f, 0.0f, 0.0f ) );
mRenderBuffer.unbindFramebuffer();
mFrames = 0;
}
void CaptureApp::saveImage()
{
fs::path pngPath = getSaveFilePath( getHomeDirectory() );
if( pngPath.empty() ) {
return;
}
gl::Fbo exportBuffer;
exportBuffer = gl::Fbo( mCapture.getWidth(), mCapture.getHeight() );
// bind the FBO, so we can draw on it
exportBuffer.bindFramebuffer();
// set the correct viewport and matrices
glPushAttrib( GL_VIEWPORT_BIT );
gl::setViewport( exportBuffer.getBounds() );
gl::pushMatrices();
gl::setMatricesWindow( exportBuffer.getSize() );
// draw Fbo upsidedown, because...
Rectf bufferRect = Rectf( 0, (float)exportBuffer.getHeight(), (float)exportBuffer.getWidth(), 0 );
if( mFrames > 0 ) {
float factor = 1.0f / (float)mFrames;
gl::color( Color( factor, factor, factor ));
gl::draw( mRenderBuffer.getTexture(), bufferRect );
gl::color( Color( 1.0f, 1.0f, 1.0f ));
}
// restore matrices and viewport
gl::popMatrices();
glPopAttrib();
// unbind the FBO to stop drawing on it
mRenderBuffer.unbindFramebuffer();
writeImage( pngPath, Surface32f( exportBuffer.getTexture() ), ImageTarget::Options(), "png" );
}
void CaptureApp::saveBuffer()
{
fs::path pngPath = getSaveFilePath( getHomeDirectory() );
if( pngPath.empty() ) {
return;
}
writeImage( pngPath, Surface32f( mRenderBuffer.getTexture() ), ImageTarget::Options(), "png" );
}
CINDER_APP_BASIC( CaptureApp, RendererGl )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment