Вопрос

I am trying to get a hang of OpenCV. At the moment I am trying to subtract two frames from each other and display the result. I have found example code which will do that just fine. My problem is that I am getting a memory allocation error. Well, nothing to special about that, because I am feeding the program with HD video. So my question is how do I release the allocated memory of an IplImage*? The Mat type has something like Mat.release(). IplImage does not have that, nor does free(IplImage) work.

Here is my code:

#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\highgui\highgui_c.h>


using namespace cv;

int main()
{
    std::string videofilename;

    std::cout << "Please specify the video name (make sure it is in the same folder\nas the application!):" << std::endl;
    std::cin >> videofilename;
    std::cout << "The name you provided: " << videofilename << std::endl;

    VideoCapture video(videofilename);

    if(!video.isOpened())
    {
        std::cout << "Could not open video file" << std::endl;
        return -1;
    }

    std::cout << "Number of frames: " << video.get(CV_CAP_PROP_FRAME_COUNT) << std::endl;
    std::cout << "Duration: "<< static_cast<int>(video.get(CV_CAP_PROP_FRAME_COUNT))/(30*60) << "min " << static_cast<int>((video.get(CV_CAP_PROP_FRAME_COUNT)))%(30*60)/30 << "sek" << std::endl;

    // Close it before opening for playing
    video.release();

    CvCapture* capture = cvCaptureFromAVI(videofilename.c_str()); 
    IplImage* frame = cvQueryFrame(capture);
    IplImage* currframe = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,3);
    IplImage* destframe = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,3);


    if ( !capture ) 
    {  
        std::cout << "Could not open video file" << std::endl;
        return -1; 
    }

    cvNamedWindow("dest", CV_WINDOW_AUTOSIZE);

    while(1)
    {
        frame = cvQueryFrame(capture);

        if(!frame)
        {
            printf("Capture Finished\n");
            break;
        }

        currframe = cvCloneImage(frame);    // copy frame to current
        frame = cvQueryFrame(capture);        // grab frame

        if(!frame)
        {
            printf("Capture Finished\n");
            break;
        }

        cvSub(frame, currframe, destframe);    // subtraction between the last frame to cur
        cvShowImage("dest", destframe);
        //cvReleaseImage(currframe); // doesn't work
        //free(currframe); // doesnt work either
        //delete(currframe); //again, no luck
        cvWaitKey(30);
    }

cvDestroyWindow("dest");
cvReleaseCapture(&capture);
return 0;
}
Это было полезно?

Решение

You can free IplImage using cvReleaseImage. It takes address of a pointer to an IplImage, i.e. IplImage** as argument, so you have to do this:

cvReleaseImage(&currframe);

instead of cvReleaseImage(currframe);.

But keep in mind, the image returned by cvQueryFrame, (frame in your case) is a special case and it should not be released or modified. Also, you don't have to preallocate currFrame if you are going to initialize it using cvCloneImage eventually.

The final code would look like this:

int main()
{
std::string videofilename;

std::cout << "Please specify the video name (make sure it is in the same folder\nas the application!):" << std::endl;
std::cin >> videofilename;
std::cout << "The name you provided: " << videofilename << std::endl;

VideoCapture video(videofilename);

if(!video.isOpened())
{
    std::cout << "Could not open video file" << std::endl;
    return -1;
}

std::cout << "Number of frames: " << video.get(CV_CAP_PROP_FRAME_COUNT) << std::endl;
std::cout << "Duration: "<< static_cast<int>(video.get(CV_CAP_PROP_FRAME_COUNT))/(30*60) << "min " << static_cast<int>((video.get(CV_CAP_PROP_FRAME_COUNT)))%(30*60)/30 << "sek" << std::endl;

// Close it before opening for playing
video.release();

CvCapture* capture = cvCaptureFromAVI(videofilename.c_str()); 
IplImage* frame = cvQueryFrame(capture);
IplImage* currframe;
IplImage* destframe = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,3);


if ( !capture ) 
{  
    std::cout << "Could not open video file" << std::endl;
    return -1; 
}

cvNamedWindow("dest", CV_WINDOW_AUTOSIZE);

while(1)
{
    frame = cvQueryFrame(capture);

    if(!frame)
    {
        printf("Capture Finished\n");
        break;
    }

    currframe = cvCloneImage(frame);    // copy frame to current
    frame = cvQueryFrame(capture);        // grab frame

    if(!frame)
    {
        printf("Capture Finished\n");
        break;
    }

    cvSub(frame, currframe, destframe);    // subtraction between the last frame to cur
    cvShowImage("dest", destframe);
    cvWaitKey(30);
    cvReleaseImage(&currframe);
}

cvDestroyWindow("dest");
cvReleaseCapture(&capture);
return 0;
}

Другие советы

Use cvReleaseImage(). For example, if you want to release IplImage* frame, use cvReleaseImage(&frame).

For Mat, you don't need to release it explicitly. It will release automatically when out of its code block.


Edit: take a look at here on more details about cvReleaseImage(), which addresses on some wrong releasing situations.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top