OK, that was great. Now it's time to tinker around, enhance our toy programs, and explore a little more of the available functionality. The first thing we might notice about the AVI player of Example 2-2 is that it has no way to move around quickly within the video. Our next task will be to add a slider bar, which will give us this ability.
The HighGUI toolkit provides a number of simple instruments for working with images and video beyond the simple display functions we have
just demonstrated. One especially useful mechanism is the slider, which enables us to jump easily from one part of a video to another. To
create a slider, we call cvCreateTrackbar()
and indicate
which window we would like the trackbar to appear in. In order to obtain the desired
functionality, we need only supply a callback that will perform the relocation. Example 2-3 gives the details.
Example 2-3. Program to add a trackbar slider to the basic viewer window: when the slider is moved, the function onTrackbarSlide() is called and then passed to the slider's new value
#include "cv.h" #include "highgui.h" int g_slider_position = 0; CvCapture* g_capture = NULL; void onTrackbarSlide(int pos) { cvSetCaptureProperty( g_capture, CV_CAP_PROP_POS_FRAMES, pos ); } int main( int argc, char** argv ) { cvNamedWindow( "Example3", CV_WINDOW_AUTOSIZE ); g_capture = cvCreateFileCapture( argv[1] ); int frames = (int) cvGetCaptureProperty( g_capture, CV_CAP_PROP_FRAME_COUNT ); if( frames!= 0 ) { cvCreateTrackbar( "Position", "Example3", &g_slider_position, frames, onTrackbarSlide ); } IplImage* frame; // While loop (as in Example 2) capture & show video ... // Release memory and destroy window ... return(0); }
In essence, then, the strategy is to add a global variable to represent the slider position and then add a callback that updates this variable and relocates the read position in the video. One call creates the slider and attaches the callback, and we are off and running.[12] Let's look at the details.
int g_slider_position = 0; CvCapture* g_capture = NULL;
First we define a global variable for the slider position. The callback will need access to the
capture object, so we promote that to a global variable. Because we are nice people and like
our code to be readable and easy to understand, we adopt the convention of adding a leading
g_
to any global variable.
void onTrackbarSlide(int pos) { cvSetCaptureProperty( g_capture, CV_CAP_PROP_POS_FRAMES, pos );
Now we define a callback routine to be used when the user pokes the slider. This routine will be passed to a 32-bit integer, which will be the slider position.
The call to cvSetCaptureProperty()
is one we will see
often in the future, along with its counterpart cvGetCaptureProperty()
. These routines allow us to configure (or query in the
latter case) various properties of the CvCapture
object.
In this case we pass the argument CV_CAP_PROP_POS_FRAMES
,
which indicates that we would like to set the read position in units of frames. (We can use
AVI_RATIO
instead of FRAMES
if we want to set the position as a fraction of the overall video
length). Finally, we pass in the new value of the position. Because HighGUI is highly civilized, it will automatically handle such issues as the
possibility that the frame we have requested is not a key-frame; it will start at the previous key-frame and fast forward up to the
requested frame without us having to fuss with such details.
int frames = (int) cvGetCaptureProperty( g_capture, CV_CAP_PROP_FRAME_COUNT );
As promised, we use cvGetCaptureProperty()
when we
want to query some data from the CvCapture
structure. In
this case, we want to find out how many frames are in the video so that we can calibrate the
slider (in the next step).
if( frames!= 0 ) { cvCreateTrackbar( "Position", "Example3", &g_slider_position, frames, onTrackbarSlide ); }
The last detail is to create the trackbar itself. The function cvCreateTrackbar()
allows us to give the trackbar a label[13] (in this case Position
) and to specify a
window to put the trackbar in. We then provide a variable that will be bound to the
trackbar, the maximum value of the trackbar, and a callback (or NULL if we don't want one)
for when the slider is moved. Observe that we do not create the trackbar if cvGetCaptureProperty()
returned a zero frame count. This is
because sometimes, depending on how the video was encoded, the total number of frames will
not be available. In this case we will just play the movie without providing a
trackbar.
It is worth noting that the slider created by HighGUI is not as full-featured as some sliders out there. Of course, there's no reason you can't use your favorite windowing toolkit instead of HighGUI, but the HighGUI tools are quick to implement and get us off the ground in a hurry.
Finally, we did not include the extra tidbit of code needed to make the slider move as the video plays. This is left as an exercise for the reader.
[12] This code does not update the slider position as the video plays; we leave that as an exercise for the reader. Also note that some mpeg encodings do not allow you to move backward in the video.
[13] Because HighGUI is a lightweight and easy-to-use toolkit, cvCreateTrackbar()
does not distinguish between the name of the trackbar
and the label that actually appears on the screen next to the trackbar. You may already
have noticed that cvNamedWindow()
likewise does not
distinguish between the name of the window and the label that appears on the window in
the GUI.