read successive frames OpenCV using cvQueryframe

前端 未结 3 1686
囚心锁ツ
囚心锁ツ 2020-12-06 08:08

I have a basic question in regards to cvQueryFrame() in OpenCV.

I have the following code:

IplImage *frame1,*frame2;
frame1 = cvQueryFrame(capture         


        
相关标签:
3条回答
  • 2020-12-06 08:42

    Ok !

    You have to make a copy of your frame. frame1 = cvQueryFrame(capture); is a pointer as you said.

    The code i found is :

    IplImage* img1(null), img2(null);
    CvCapture* cap = cvCaptureFromAVI("mavideo.avi");
    img2 = cvQueryFrame( cap );
    img1 = cvCloneImage( img2 ); // on alloue une nouvelle image
    
    while( cvGrabFrame( cap ) )
    {
        cvCopy( img2, img1 ); // copie de l'image, pas du pointeur
        img2 = cvRetrieveFrame( cap );
    } 
    
    cvReleaseCapture( &cap );
    cvReleaseImage( &img1 );
    

    You can replace the while by a waitkey or anything but if you do that use

    img2 = cvQueryFrame( cap ); 
    

    instead of

    img2 = cvRetrieveFrame( cap );
    

    cause you'll not have the

    cvGrabFrame( cap )
    

    anymore

    I don't know if i'm clear so... i stay here ^^

    Enjoy ;)

    Laurent

    0 讨论(0)
  • 2020-12-06 08:43

    cvQueryFrame() returns the pointer to OpenCV's "private" internal buffer which it always fills with the last grabbed frame.
    If you want 2 frames you will need to cache a copy. Once you allocate (e.g. using cvCloneImage()) space for your previous frame, you can use cvCopy() to copy just the image data. Do not use cvCloneImage() inside the loop as that is very inefficient due to the internal memory allocations (and deallocations, otherwise you'll have memory leaks as well).

    Update: the code will look something like this:

    IplImage* currFrame = 0;
    IplImage* prevFrame = 0;
    CvCapture* cap = cvCaptureFromAVI("sample.avi");   
    currFrame = cvQueryFrame( cap );
    
     // Clone the frame to have an identically sized and typed copy
    prevFrame  = cvCloneImage( currFrame );
    
    while(currFrame = cvQueryFrame( cap ))
    {
        // process the video using currFrame and prevFrame...
    
        // ...
    
    
        // When done, overwrite prevFrame with current copy in preparation
        // for the next frame.
        cvCopy( currFrame , prevFrame); 
    } 
    
    cvReleaseImage( &img1 );
    cvReleaseCapture( &cap );
    

    Note: Often, you can avoid this "redundant" copying time by doing a conversion instead.
    For example, say your display is in color, but your processing is in grayscale. You only need the 2 consecutive copies in grayscale. Since you will need to convert to grayscale anyway, you can do that directly from the captured frame thus avoiding the redundant cvCopy(). To save the previous frame you would just swap pointers between your 2 allocated grayscale images.

    0 讨论(0)
  • 2020-12-06 08:59

    ok following from Laurent's answer: I believe the key is cvCloneImage(). cvCloneImage creates a new copy of the original image including the header, ROI, imageData etc. and then points frame2 to this new data.

    Since cvQueryFrame is a wrapper for cvGrabFrame & cvRetrieveFrame together I didn't want to split up the functions, so with a small modification I can still use cvQueryFrame.

    Below is my modified solution.

    
    IplImage *frame = cvQueryFrame(capture); //to read properties of frame.
    IplImage *frame2 = NULL;

    while (1){ if(frame2) frame = cvCloneImage(frame2); // copy image to allow grabbing next frame frame2 = cvQueryFrame(capture); //read next frame if(!frame2) break; //if frame cannot be read, EOF so break from loop }

    I hope you understand what I've done here. Feel free to ask any more questions.

    0 讨论(0)
提交回复
热议问题