Processing a single video frame

Now we begin to learn the methods of processing video. Values of pixels in the current video frame can be read in a way similar to the one in ofImage, using access to its pixel array data:

unsigned char *getPixels()

Also, here is the getPixelRef() method, which returns a reference to a pixel array of the current frame, represented by a special class ofPixels.

Tip

Note that the ofImage class has getPixelRef() too and can be used in a similar way.

It is easy to get the pixel color using pixels.getColor( x, y ), which returns the ofColor value of pixel ( x,y ). Compared to directly working with pixels data using getPixels(), it is a relatively slow operation, but is more simple and convenient. Note, ofPixels has useful properties such as getWidth() and getHeight() that are used for getting the width and height, and also the channels value, which holds the number of channels in the image (1, 3, or 4).

The vertical lines image example

See the example where we read the colors of center horizontal line pixels and draw vertical lines with the corresponding colors. The project is similar to the previous example, only testApp::draw() is changed:

Note

This is example 05-Video/02-VideoVerticals.

void testApp::draw(){
  //Getting reference to the pixel array
  ofPixels &pixels = video.getPixelsRef();

  //Define variables w, h equal to frame width and height
  int w = pixels.getWidth();
  int h = pixels.getHeight();

  //Scan center horizontal line
  for (int x=0; x<w; x++) {
        //Getting color of the center line
        ofColor color = pixels.getColor( x, h / 2 );

        //Draw a vertical line using this color
        ofSetColor( color );
        ofLine( x, 0, x, h );
  }
}

Running this example, you will see a movie with frames built from a set of colored vertical lines. The color of each line is taken from the central horizontal line of the original movie's frame:

The vertical lines image example

The important thing in the example is using the & symbol in the line:

ofPixels &pixels = video.getPixelRef();

This symbol means that we are getting just a reference of the pixel array data, and not copying the data itself. So this is an extremely fast operation, just like a pointer assignment. But when the next frame is obtained, we will lose old pixels data and it will be a reference on the new frame, or maybe some memory error can occur. Instead, if we call it another way, without &:

ofPixels pixels = video.getPixelRef();

The data will be copied to pixels, and stored there as long as we want. It is safe, but consumes a lot of memory and hence is a consuming operation (that can be noticeable for large frame size).

It is possible to change pixel colors in ofPixels, using pixels.setColor( x, y, color ) with color value of type ofColor. But the pixel array obtained from the video frame is not intended for changing its image, so you will not see the changes drawing it with video.draw(). If you want to draw the changed pixels, create an ofImage object and load the pixels array into this image, using the setFromPixels() function.

The replacing colors example

Let's consider an example where we change the color components of all the framed pixels using a random-generated table and draw the resulting image. Also, the example demonstrates the usage of the video.isFrameNew() function.

It is based on the emptyExample project in openFrameworks. Before running it, copy the handsTrees.mov file into the bin/data folder of your project.

Note

This is example 05-Video/03-VideoReplacingColors.

In the testApp.h file inside the testApp class declaration, add the following lines:

ofVideoPlayer video;  //Declare video player object
ofImage image;        //Declare image object
int table[16];        //Declare table for color replacing

In the testApp.cpp file, fill the bodies of the setup(), update(), and draw() functions in the following way:

void testApp::setup(){
  video.loadMovie( "handsTrees.mov" );  //Load video file
  video.play();  //Start video to play

  //Fill the table by random values from 0 to 255
  for ( int i=0; i<16; i++ ) {
      table[i] = ofRandom( 0, 255 );
  }

}

void testApp::update(){
  video.update();    //Decode the new frame if needed

  //Do computing only if a new frame was obtained
  if ( video.isFrameNew() ) {
      //Getting pixels
      ofPixels pixels = video.getPixelsRef();

      //Scan all the pixels
      for (int y=0; y<pixels.getHeight(); y++) {
          for (int x=0; x<pixels.getWidth(); x++) {
              //Getting pixel (x,y) color
              ofColor col = pixels.getColor( x, y );

              //Change color components of col
              //using table
              col.r = table[ col.r/16 ];
              col.g = table[ col.g/16 ];
              col.b = table[ col.b/16 ];

              //Set the color back to the pixel (x,y)
              pixels.setColor( x, y, col );
          }
      }

      //Set pixel array to the image
      image.setFromPixels( pixels );
  }
}

void testApp::draw(){
  ofBackground( 255, 255, 255 );  //Set white background

  //Draw the image
  ofSetColor( 255, 255, 255 );
  image.draw(0,0);
}

When you start the application, you will see the movie with changed pixel colors. The rule for color changing is fixed during application execution. A color replace table is constructed at startup using random number generator; so each time you run the application, you will obtain a different result. The following screenshot shows us an example:

The replacing colors example

The rule for color replacing is held in a random-generated table:

for ( int i=0; i<16; i++ ) {
  table[i] = ofRandom( 0, 255 );
}

And the main operation of the example is changing the color using table:

col.r = table[ col.r/16 ];
col.g = table[ col.g/16 ];
col.b = table[ col.b/16 ];

Indeed, each color component lies in range [0, 255], so col.r/16, col.g/16, and col.g/16 lies in range [0, 15]. Our table has size 16, so operation is correct. Note that if we create table of size 256, we can use simple operations as follows:

col.r = table[ col.r ];
col.g = table[ col.g ];
col.b = table[ col.b ];

The resultant image will be much more "color-sprayed". (Before running the project with such modification, you need to replace in code all constants from 16 to 256.)

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset