1

I'm sparkling brand new to Qt, and am finding it very rewarding to learn. I'm trying to merge some existing C++ code with a new Qt GUI. Basically, the idea is to have images that are extracted from an .avi file be processed in the backend and then displayed in a QLabel on-screen. I have managed to get the following bit of code to display the frames correctly:

while (frame = cvQueryFrame(capture))
{
    // Some processing code...

    QImage qImageFrame((uchar*) frame->imageData, frame->width, frame->height, frame->widthStep, QImage::Format_RGB888);
    qImageFrame = qImageFrame.rgbSwapped();
    QPixmap qFrame;

    qFrame.convertFromImage(qImageFrame);
    label->setPixmap(qFrame);
    label->repaint();

    cvWaitKey(10);
}

Now, however, this obviously means that the UI stops being responsive to user input until all the frames from the movie are displayed. How is something like this done?

NB: I am performing the processing using the openCV library, which expects the images in a certain format. One thing which I think I cannot do, for example, is work with the .avi file directly in the Qt domain.

Kristian D'Amato
  • 3,996
  • 9
  • 45
  • 69

4 Answers4

3

I disagree with Tamás's suggestion that his answer is the "simplest" solution.

The quickest, least-invasive solution to your problem is to add qApp->processEvents(); into your loop. I would drop it in after the label->repaint(); and see what happens.

clee
  • 10,943
  • 6
  • 36
  • 28
  • This relies on assumption that the processing itself is negligible time for all possible inputs. This may or may not be true. If this is the case, then yes, this solution is indeed simpler than mine. – Tamás Szelei Jun 05 '11 at 10:56
  • I have tried your suggestion. Yes, the UI becomes responsive again, but if I quit the application the window gets destroyed while the process keeps on working in the background... I think I'm going to try this with threads. – Kristian D'Amato Jun 05 '11 at 14:01
1

You should really have a look at the Qt Phonon multimedia framework. Might not get you the level of control you have with OpenCV over the media files, but it's worth a good looking into.

For your original question: you have to do the processing in a different thread. This gets tricky because you can only call GUI functions from the UI thread, and you (I suppose) don't want to be copying the image data around too much.

For a good run-down (and pointers to the Qt docs), have a look at Qt signaling across threads, one is GUI thread?. Notice it'll take extra work if you want to pass QImages directly.

Community
  • 1
  • 1
Mat
  • 202,337
  • 40
  • 393
  • 406
1

Sometimes the simplest solution is the best. Create a worker thread by subclassing QRunnable for decoding your frames and send signals back to the GUI to update the frame. When Qt signals emitted across threads, they are queued and dispatched correctly. Especially in the case of a single worker thread, you won't have headaches because of concurrency issues. Copying QImage is not a problem, because it utilizes implicit sharing. To write your own implicitly shared data classes, use QSharedDataPointer (as far as I know, Qt uses it internally as well).

Tamás Szelei
  • 23,169
  • 18
  • 105
  • 180
0

Using a thread is not the only (or indeed, necessarily the preferred) way to do this.

Your UI is blocking because you're using a blocking sleep (cvWaitKey). If you use QTimer instead and connect its timeout signal to a slot which draws the next frame, then your UI should stay responsive.

PAG
  • 1,836
  • 1
  • 18
  • 19
  • Are you sure that cvWaitKey is blocking? I'm not familiar with openCV, but a quick search indicates otherwise. See http://stackoverflow.com/questions/5217519/opencv-cvwaitkey . Also, even if you remove the blocking wait, the processing itself still can take some time, so my opinion is that using a worker thread is justified here. – Tamás Szelei Jun 05 '11 at 10:11
  • “Are you sure that cvWaitKey is blocking? I'm not familiar with openCV, but a quick search indicates otherwise. See stackoverflow.com/questions/5217519/opencv-cvwaitkey” — Tamás, you seem mistaken. The first answer in the link you've posted states "cvWaitKey() sleeps for X miliseconds, waiting for any key to be pressed". Your point about the processing taking time is true, but it seems to be negligible time if a single-threaded version was used before. – PAG Jun 05 '11 at 10:37