19 January 2010

Author

Jan Vantomme

Categories

Generative Design
Tutorial

Mirroring Video with openFrameworks

When you create an installation that uses a webcam to analyse the behavior of people, you often need to mirror the video to use it. In this article I’m going to explain how to do this in openFrameworks.

The first thing you need to do is to declare some variables in testApp.h. You’ll need an ofVideoGrabber to capture video from the webcam, an ofTexture to render the mirrored video to the screen, a char array to store temporary pixel values and two integers for the width and height of the video to capture. Add this code to testApp.h, right after the standard methods.

ofVideoGrabber vidGrabber;
ofTexture mirrorTexture;
unsigned char * videoMirror;
int camWidth;
int camHeight;

Next up is setting the values of these variables in the setup() method of testApp.cpp. Set the width and height of the video to capture first, set up the grabber, create a new unsigned char for the temporary pixel values and allocate a texture for the mirrored video. Note that the lenght of the temporary pixel array is camWidth x camHeight x 3. Each pixel takes up 3 places in the array. One for each RGB component. Add the code below to setup().

camWidth = 320;
camHeight = 240;
vidGrabber.setVerbose(true);
vidGrabber.initGrabber(camWidth, camHeight);
videoMirror = new unsigned char[camWidth*camHeight*3];
mirrorTexture.allocate(camWidth, camHeight, GL_RGB);

Once the variables are all set up, you’ll need the algorithm to swap pixels. This is a bit tricky because you need to swap them in blocks of three values. You can’t just reverse the pixels as the R, G and B components need to stay in place. If you don’t do this, the colors of the mirrored video will look weird.
This is the code to add to the update() method.

ofBackground(0, 0, 0);
vidGrabber.grabFrame();
if (vidGrabber.isFrameNew()) {
    unsigned char * pixels = vidGrabber.getPixels();
    for (int i = 0; i < camHeight; i++) {
        for (int j = 0; j < camWidth*3; j+=3) {
            // pixel number
            int pix1 = (i*camWidth*3) + j;
            int pix2 = (i*camWidth*3) + (j+1);
            int pix3 = (i*camWidth*3) + (j+2);
            // mirror pixel number
            int mir1 = (i*camWidth*3)+1 * (camWidth*3 - j-3);
            int mir2 = (i*camWidth*3)+1 * (camWidth*3 - j-2);
            int mir3 = (i*camWidth*3)+1 * (camWidth*3 - j-1);
            // swap pixels
            videoMirror[pix1] = pixels[mir1];
            videoMirror[pix2] = pixels[mir2];
            videoMirror[pix3] = pixels[mir3];	
        }
    }
    mirrorTexture.loadData(videoMirror, camWidth, camHeight, GL_RGB);	
}

Drawing the video to the screen is easy. You do need to set the background to solid white before drawing, otherwise the video will be tinted in the color that was last set. Add this code to testApp.cpp in draw()

ofSetColor(255, 255, 255);
vidGrabber.draw(0, 0);
mirrorTexture.draw(camWidth, 0, camWidth, camHeight);

Now build that app and it should look somewhat like the picture below.

A screengrab of the mirrored video project.

So now you know how to mirror an RGB video. This is useful for tracking colors. Next article will be about mirroring grayscale video, which is a lot faster and good if you only need to track motion.

Downloads

Top · Tweet about this

Browse Articles

5 Opinions posted so far. Now go post your own. To the comment form!

  1. From:Theodore Watson
    Date:19 January 2010, 14:23

    gravatar

    Nice tutorial!

    Another easier way to do it is to use the ofxOpenCv addon.
    Both the ofxCvColorImage and ofxCvGrayscaleImage have a mirror(bool flipHorizontal, bool flipVertical) method, so you can stick the pixels in a cvimage flip them and get them back.

    Its nice to know how to do it by hand though- I made my students learn it by hand before I told them about the mirror function :)

    Hardest yet is a 90/270 Degree rotate – especially with an RGB array.

    Top · Permanent link to this comment

  2. From:Jan Vantomme
    Date:19 January 2010, 14:34

    gravatar

    Didn’t know about the mirror function in ofxOpenCv. Wrote this on the train and didn’t have any documentation with me. Was fun to do.

    Wouldn’t ask my students to write algorithms like this. Most of them think it’s hard enough to draw simple shapes with code.

    Top · Permanent link to this comment

  3. From:Bart
    Date:16 February 2010, 19:43

    gravatar

    This works as well:

    glPushMatrix();
        ofTranslate(camWidth,camHeight);
        glScalef(-1, -1,1);
        vidGrabber.draw(0,0);
    glPopMatrix();

    You can also rotate it by exchanging the glScalef with an ofRotate. Problem is that they both work with a pivot situated at (0,0)

    Top · Permanent link to this comment

  4. From:xenomuta
    Date: 3 March 2010, 04:51

    gravatar

    Both of your examples have enlightened me anyways, but I was getting this done with better performance by drawing images with negative width:

    image.setFromPixels(vidGrabber.getPixels(), camWidth, camHeight);
    image.draw(xPos + camWidth, yPos, -camWidth, camHeight);

    Top · Permanent link to this comment

  5. From:Jan Vantomme
    Date: 3 March 2010, 11:33

    gravatar

    I wouldn’t recommend using the algorithm in this article if you only use it to display images. I wrote it just to show how the pixel arrays in openFrameworks work.

    Algorithms like this can be used to track objects without using OpenCV or as a base for Augmented Reality applications.

    Top · Permanent link to this comment

Commenting is closed for this article.

Subscribe to this blog

About this blog

This is the personal weblog of Jan Vantomme.
I write about the everyday things that move me as a designer. I write shorter things on Twitter.

Add to Technorati Favorites

Some of the blogs I like

Adaptive Path
A blog on User Experience
DevKick
Web Development for Designers
The Man In Blue
A blog on web technology by Cameron Adams
Andy Budd
Webdesign
Aral Balkan
Confessions of an internet junkie.