Ask Your Question
0

Delay voluntarily a live feed from a VideoCapture

asked 2013-05-06 03:49:27 -0600

mistermystere gravatar image

Hi,

I have a class Camera inheriting from cv::VideoCapture, which its core method is to convert a cv::Mat that I get from a live stream to a QImage :

QImage Camera::getFrame() {
    if(isOpened()) {
        cv::Mat image;
        (*this) >> image;
        cv::cvtColor(image, image, CV_BGR2RGB);
        return QImage((uchar*) image.data, image.cols, image.rows, image.step, QImage::Format_RGB888);
    }
    else return QImage();
}

And an encapsulating class CameraDelayedView which calls this method and adds a delay :

void CameraDelayedView::timerEvent(QTimerEvent *evt) {
    if(cam != NULL) {
        buffer.enqueue(cam->getFrame());

        if(buffer.size() > delay*fps) {
            setPixmap(QPixmap::fromImage(buffer.dequeue()));
        }
    }
}

The first frame is delayed like I want, but from that moment on, the video is a normal live feed like I would get without the queue system. Apparently, the images are part of a buffer which is updated, so that when creating a QImage with image.data, the pointers point at a frame which will be updated afterward. I want to avoid that: keep a snapshot, store it.

Do I have to copy each image.data myself to make it independant, or is there a more efficient way ? Please do not hesitate to tell me if the above can be more efficient as well.

Thanks in advance.

Regards, Mister Mystère

edit retag flag offensive close merge delete

1 answer

Sort by » oldest newest most voted
2

answered 2013-05-06 04:07:34 -0600

You have two solutions in my opinion:

  1. Grab frame each time and retrieve only when its needed (see Grab and Retrieve functions on HighGui doc) with a timer, or a counter, etc.
  2. Use a double buffer, like in OpenGL: grab and retrieve an image in the back buffer, create an accessor to the front buffer with synchronization. Copy the back buffer to the front (if no one is accessing to the buffer) and swap pointers (see Multiple buffering on wikipedia here). In this case each image is retrieved, but you can compared it in a smart "way", eg. check if the image as changed since last retrieve, etc.
edit flag offensive delete link more

Comments

Merci de votre réponse ;) I'm particularly interested in the first solution since it's a very simple one (I have quite a tight schedule). So I would need to grab an image in my timerEvent (so once every 35ms), and in that very method, as soon as a counter reaches delay*fps start retrieving at each call ? (I can't compile here for now) One important issue is the size of the buffer. I'll be dealing with delays up to 2 seconds (hence 60 frames in VGA)... Is it limited somehow ? Edit: Hmm, sounds like this solution would not allow for 2 cameras without some extra work around it. I saw cv::Mat::clone(), seems to answer my question doesn't it?

mistermystere gravatar imagemistermystere ( 2013-05-06 05:00:03 -0600 )edit

I'm not sure of what you mean, but if you need to have a single buffer for many images, you should probably fixed the size of the buffer (Nbimage*size_of_image) and just keep the index of the image, therefore, no need to allocated memory after that, and you save time also.

Mathieu Barnachon gravatar imageMathieu Barnachon ( 2013-05-06 07:33:22 -0600 )edit

I have a buffer for each camera so that should be fine for this. Well I'd be glad to share a code that worked for me using simply cv::Mat::clone() but I'm not allowed to answer my own question before 2 days so I'll post later. In the meantime I'm still looking for an explanation for having and a solution for avoiding tuning the timer to the actual FPS of the camera... Because otherwise I get an increase in the desired lag by up to 50% (at 30 fps instead of 23fps with which I have 10%) !

mistermystere gravatar imagemistermystere ( 2013-05-06 13:27:25 -0600 )edit

Question Tools

Stats

Asked: 2013-05-06 03:49:27 -0600

Seen: 2,125 times

Last updated: May 06 '13