4. Reading From a Webcam

From my perspective one of the most intriguing applications of all this simple image and file handling so far is reading in data from a webcam. I was pleasantly surprised at how easy it was using OpenCV. Below is the code I used to read in information from a webcam and save it to a file.

# include "highgui.h"
# include "cv.h"

int main( int argc, char** argv ) {
	CvCapture* capture;

	capture = cvCreateCameraCapture(0);

	assert( capture != NULL );

	IplImage* bgr_frame = cvQueryFrame( capture );

	CvSize size = cvSize(
			(int)cvGetCaptureProperty( capture,
                            CV_CAP_PROP_FRAME_WIDTH),
			(int)cvGetCaptureProperty( capture,
                            CV_CAP_PROP_FRAME_HEIGHT)
			);

	cvNamedWindow( "Webcam", CV_WINDOW_AUTOSIZE );

	CvVideoWriter *writer = cvCreateVideoWriter( argv[ 1 ],
                            CV_FOURCC('D','I','V','X'),
                            30,
                            size
                            );

	while( (bgr_frame = cvQueryFrame( capture )) != NULL ) {
		cvWriteFrame( writer, bgr_frame );
		cvShowImage( "Webcam", bgr_frame );
		char c = cvWaitKey( 33 );
		if( c == 27 ) break;
	}
	cvReleaseVideoWriter( &writer );
	cvReleaseCapture( &capture );
	cvDestroyWindow( "Webcam" );
	return( 0 );
}

Get the code from my Git Repository
If you need help with Git, follow this quick introduction – Getting Started With Git

So the idea behind the program is this… First I wanted to make a pointer to a CvCapture structure, because I’m going to need somehwere to store the webcam information and capture feed. When I initialized the new capture structure, I used a new function CreateCameraCapture…

CvCapture* cvCreateCameraCapture( int index )
index - The camera device number
        Index   Device
          0     /dev/video0
          1     /dev/video1
          2     /dev/video2
          3     /dev/video3
          ...
          7     /dev/video7
          with
          -1    /dev/video

So I initialized the structure with my webcam /dev/video0, any number can be used, and the -1 will choose one arbitrarily.

Next I needed an IplImage structure pointer for displaying each frame captured by my webcam, but I wanted to do more than just display it. I wanted to write each frame down into a file as the camera was running. For the CreateVideoWriter function, which we’ll see momentarily, I needed the size of the images being captured by my webcam. There is another structure for storing the sizes, CvSize. It’s declared inside cxtypes.h as simply as it sounds.

typedef struct
{
    int width;
    int height;
}
CvSize;

After declaring a variable of type CvSize, I instantiated it with the cvSize function.

CvSize cvSize( int width, int height )
{
      CvSize s;
      s.width = width;
      s.height = height;
      return s;
}

It’s as easy as that, I don’t think that needs much explanation.

What does deserve an explanation is the super handy dandy cvGetCaptureProperty function. Notice I used it to get the height and width of my camera’s captured images and set that as the height and width of the new CvSize structure. Here is how it works.

double cvGetCaptureProperty(CvCapture* capture, int property_id);
capture - This is the structure containing all the information about
           it's video/camera/movie
property_id - The property information desried. 

Can be any of the following: CV_CAP_PROP_POS_MSEC       0
                             CV_CAP_PROP_POS_FRAMES     1
                             CV_CAP_PROP_POS_AVI_RATIO  2
                             CV_CAP_PROP_FRAME_WIDTH    3
                             CV_CAP_PROP_FRAME_HEIGHT   4
                             CV_CAP_PROP_FPS            5
                             CV_CAP_PROP_FOURCC         6
                             CV_CAP_PROP_FRAME_COUNT    7
                             CV_CAP_PROP_FORMAT         8
                             CV_CAP_PROP_MODE           9
                             CV_CAP_PROP_BRIGHTNESS    10
                             CV_CAP_PROP_CONTRAST      11
                             CV_CAP_PROP_SATURATION    12
                             CV_CAP_PROP_HUE           13
                             CV_CAP_PROP_GAIN          14
                             CV_CAP_PROP_EXPOSURE      15
                             CV_CAP_PROP_CONVERT_RGB   16
                             CV_CAP_PROP_WHITE_BALANCE 17
                             CV_CAP_PROP_RECTIFICATION 18

I find this to be a great function, one worth memorizing. Take note that it returns a double, so I needed to static cast them to integers for the cvSize function to accept them.

Inside the loop I’m thinking, I want to be writing the frames from the video feed before I display them. This is from remembering that IplImage structures instantiated to a CvCapture’s frames are released immediately after the function ends. So I’d have to write each frame down before they were released, and to write an image I needed a writer…

typedef struct CvVideoWriter CvVideoWriter;
CvVideoWriter* cvCreateVideoWriter(
                           const char* filename,
                           int fourcc,
                           double fps,
                           CvSize frame_size
                           );
filename - Name of the output video file.
fourcc - 4-character code of codec used to compress the frames.
         For example,
             CV_FOURCC('P','I','M','1') is MPEG-1 codec,
             CV_FOURCC('M','J','P','G') is motion-jpeg codec etc.
         Under Win32 it is possible to pass -1 in order to choose
         compression method and additional compression
         parameters from dialog.
fps - Framerate of the created video stream.
frame_size - Size of video frames.

I had some trouble with this function for a bit. The codec you choose to compress the frames must be on your computer. I put in a codec I believed was on my system only to find it not writing the file, after a while of searching and reading through the source, I found the problem which I recorded in my OpenCV Errors section.

I know what you’re thinking. “Hey! You put the fps in manually to 30, but I remember seeing a CV_CAP_PROP_FPS, why didn’t you use the cvGetCaptureProperty function and store it in a double and put it in that way?” Well I tried that. For a reason I’m not sure of yet, my webcam doesn’t seem to be sharing that information nicely with my computer, so I was receiving an error telling me it couldn’t read the fps from the CvCapture structure. Oh well. 30 fps seems to be working fine.

So I’m ready for the loop. I get it going with some new pizazz, but the logic is the same. As planned I write the frame first, then display it.

int cvWriteFrame( CvVideoWriter* writer, const IplImage* image );
writer - Video writer structure.
image - The frame to be written.

It does precisely what it says, takes in an image and writes it to the file that was given to the CreateVideoWriter function. Then show the image, and do that standard clean up, including releasing the new CvVideoWriter with the usual approach.

void cvReleaseVideoWriter( CvVideoWriter** writer );
writer - Pointer to the video file writer structure.

That’s that. Now by running this program a window will pop up displaying everything the webcam sees and save it to a file given as the first parameter to the main function. You can use the video player that was written in the previous post Basic Video Manipulation to test out the newly recorded video.

References

I’m studying from Gary Bradski’s Learning OpenCV

This entry was posted in OpenCV Journey. Bookmark the permalink.

9 Responses to 4. Reading From a Webcam

  1. joy says:

    I’m also learning OpenCV as well for my undergraduate project and am having a bit of difficulty. But this post really helped. Thank you and I hope you keep posting :)

  2. edwin says:

    Hi, how do you choose which directory to output the video file to?

  3. Nathan Crock says:

    edwin,

    When you choose the name of the file in your program, you can name the path-to-directory there. For instance say there is a folder in the previous directory called ‘frames’ which you wish to save a video called ‘my_friends’ then the name of the file in your code would be ‘../frames/my_friends’ where the .. means previous directory.

    Good luck,

    Nathan Crock

  4. Nathan Crock says:

    Thank you Joy,

    I’ve been off a little trying to finish my thesis prospectus, however once it’s done I plan to get back to posting.

    Thanks for the feedback!

    Nathan

  5. Luis Ribeiro says:

    Hi Nathan,
    Sorry if i’m not doing this topic in the correct place.
    I have a problem in OpenCV, I want to save a video directly from the WebCam with some transformations, but I’m not able.
    I want to save a video with only one channel frames!
    I receive an error saying that i need use only 3 channel frame to make a video.
    PLEASE HELP ME

    #include “cv.h”
    #include “highgui.h”
    #include “stdio.h”
    #include “iostream>
    #include “math.h”

    int main( int argc, char** argv )
    {

    CvCapture *capture;
    IplImage *frame;
    IplImage *frame_blue;
    IplImage *blue;
    IplImage *frame_total;

    capture = cvCaptureFromCAM( 0 );
    if ( !capture )
    return EXIT_FAILURE;

    assert( capture != NULL );

    frame = cvQueryFrame( capture );
    if ( !frame )
    return EXIT_FAILURE;

    //cvNamedWindow( “Video” , CV_WINDOW_AUTOSIZE );
    //cvNamedWindow( “Subtractor” , CV_WINDOW_AUTOSIZE );

    CvSize size = cvSize
    (
    (int)cvGetCaptureProperty( capture, CV_CAP_PROP_FRAME_WIDTH),
    (int)cvGetCaptureProperty( capture, CV_CAP_PROP_FRAME_HEIGHT)
    );

    frame_blue = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 1 );
    cvSplit( frame , frame_blue , 0 , 0 , 0 );
    cvShowImage(“Frame de Subtracação”, frame_blue);

    blue = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 1 );

    frame_total = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 1 );

    CvVideoWriter *writer = cvCreateVideoWriter
    (
    argv[ 1 ],
    CV_FOURCC(‘D’,'I’,'V’,'X’),
    25,
    size,
    0
    );

    while( (frame = cvQueryFrame( capture )) != NULL )
    {
    frame = cvQueryFrame(capture);
    if ( !frame )
    return EXIT_FAILURE;

    cvSplit( frame , blue , 0 , 0 , 0 );

    cvSub( frame_blue, blue, frame_total, NULL );

    cvShowImage(“Video RGB”, frame);
    cvShowImage(“Video de Vermelhos”, blue);
    cvShowImage(“Total”, frame_total);

    cvWriteFrame( writer, frame_total );

    char c = cvWaitKey(1);

    if (c == 27)
    return EXIT_FAILURE;
    }

    cvReleaseCapture ( &capture );
    cvReleaseVideoWriter ( &writer );
    cvDestroyWindow ( “Frame de Subtracação” );
    cvDestroyWindow ( “Video de Vermelhos” );
    cvDestroyWindow ( “Total” );

    return EXIT_SUCCESS;
    }

    is it possible to write gray frames in a video by OpenCV -> cvWriteFrame

  6. Qiang Zhang says:

    Hi,

    Thanks for your guide.

    However, I met a different problem. I am using visual studio 2010 and openCV 2.1. I am capturing the video from a webcam and writing into a AVI file (XVID compression). The code runs good in debug configuration. However, when I try to have a release configuration (so the code can be optimized), the compilation is OK, but the “cvCreateVideoWriter” always report an error when executed. The code is:
    “CvVideoWriter * tool_view_write=cvCreateVideoWriter(str, CV_FOURCC(‘X’, ‘V’, ‘I’, ‘D’), 15, cvSize(320, 240));”.

    Do you have any idea on that?

    Thanks!

  7. Nathan Crock says:

    What is the error?

  8. avi says:

    hi…. sorry to disturb but i would like to seek a help from you.
    i am new to opencv but want to do an image processing project. i have recently installed opencv 2.1 in deccpp4.9.9.2. i have successively linked the both. when i write and compile a simple code to display an image, the compilation is ok but when i try to run the program the image window is blank. my code is as follows;

    #include “cv.h”
    #include “highgui.h”
    int main()
    {
    IplImage * input;
    input = cvLoadImage(“shivendu.jpg”,1);
    cvNamedWindow(“Output”,1);
    cvShowImage(“Output”, input);
    cvWaitKey(0);
    cvDestroyWindow( “Output” ); //destroy the window
    cvReleaseImage( &input ); //release the memory for the image
    cvWaitKey(0);
    return 0;
    }
    plz help me

  9. rabeb says:

    Hello,
    I want to retrieve images from video and save them but “CV_CAP_PROP_FRAME_COUNT” seem dosen’t work.
    captureSave = cvCaptureFromAVI(dirOpen.toStdString().c_str());
    frameW = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
    FPS_open = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FPS); // frame pes secund
    for( i=0;i<frameCount;i++){

    cvGrabFrame(captureSave);
    frame = cvRetrieveFrame(captureSave);

    sprintf(buf, "c:/dataF/Image%04d.jpg", i);
    cvSaveImage(buf,frame);
    }

    please help me to know the number of frames in my video.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>