Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCV - closing the image display window

Tags:

c++

c

opencv

I am doing on a project for searching through an image database, and when I find the results to some query - 5 database images, I would like to display the results visually. I do not keep all the images in memory, so I have do load the image first in order to display it.

I had something simple in mind, in pseudocode:

for image 1..5
    load images
    display image in a window
    wait for any keypress
    close the window

Here's a snippet of my code in C++ using OpenCV for this purpose:

IplImage *img;

for (int i=0; i < 5; ++i){
    img = cvLoadImage(images[i].name.c_str(),1);
    cvShowImage(("Match" + images[i].name).c_str(), img);
    cvWaitKey(0);
    cvDestroyWindow(("Match" + images[i].name).c_str());
    // sleep(1);
    cvReleaseImage(&img);
}

The images array used here does not as such exist in my code, but for the sake of the question, it contains the File Names of the images relative to the current program running point if its name member. I store the image names a bit differently in my project.

The code above almost works: I can iterate through 4/5 images OK, but when last image is displayed and a key is pressed, the image goes gray and I can not close the image window withouth crashing the rest of my application.

My first idea was that becouse of compile-time optimizations, cvReleaseImage releases the image before cvDestroyWindow is finished, and that somehow makes it freeze. But, I've tried adding some waiting time (hence the commented out sleep(1) line of my code) and it didn't help.

I am calling this display functionality from my console application, and when the image freezes, the control returns back to my application and I can keep using it (but the image window is still frozen in the background).

Can you give me any suggestions on how to fix this?

EDIT

I have talked to some people dealing with computer vision and OpenCV on a regular basis since asking the question, and still no ideas.

I have also found a similar stackoverflow question, but there is still no accepted answer. Googleing just gives similar questions as a result, but no answers.

Any ideas on what to try (even if they are not the complete solution) are very much appreciated.

like image 747
penelope Avatar asked Jan 12 '12 21:01

penelope


3 Answers

For testing purposes, the application below does exactly what you stated in the question: it loads 7 images through the command line, one by one, and creates a new window for each image to be display.

It works flawlessly with OpenCV 2.3.1 on Linux.

#include <cv.h>
#include <highgui.h>

#define NUM_IMGS 7

int main(int argc, char* argv[])
{
    if (argc < 8)
    {
        printf("Usage: %s <img1> <img2> <img3> <img4> <img5> <img6> <img7>\n", argv[0]);
        return -1;
    }

    // Array to store pointers for the images
    IplImage* images[NUM_IMGS] = { 0 };

    for (int i = 0; i < NUM_IMGS; i++)
    {
        // load image
        images[i] = cvLoadImage(argv[i+1], CV_LOAD_IMAGE_UNCHANGED);
        if (!images[i])
        {
            printf("!!! failed to load: %s\n", argv[i+1]);
            continue;
        }

        // display image in a window
        cvNamedWindow(argv[i+1], CV_WINDOW_AUTOSIZE); // creating a new window each time
        cvShowImage(argv[i+1], images[i]);

        // wait for keypress
        cvWaitKey(0);

        // close the window
        cvDestroyWindow(argv[i+1]);
        cvReleaseImage(&images[i]);
    }

    return 0;
}
like image 132
karlphillip Avatar answered Nov 20 '22 23:11

karlphillip


cvDestroyWindow() usually only starts pretty complicated procedure of window destruction. This procedure requires some interaction (event exchange) between windowing system and your application. Until this procedure finishes, the window cannot be completely destroyed. That is the reason why you see partially destroyed window while your application performs something not related to GUI.

Event exchange may be performed in system-dependent manner. In Windows this means (directly or indirectly) calling GetMessage or MsgWaitFor* functions and processing the result. For Unixes this means (directly or indirectly) calling XNextEvent and processing the result.

OpenCV allows to do this event exchange in system-independent way. There are two documented methods to do this. First one is cvWaitKey() (just call cvWaitKey(1) after you close the last image). Second one is to call cvStartWindowThread() at the start of your program to allow OpenCV updating its windows automatically.

Only one of these methods worked properly on my Linux box with libcv2.1: cvStartWindowThread().


Update (code snippet with cvStartWindowThread())

//gcc -std=c99 main.c -lcv -lcxcore -lhighgui
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <stdio.h>
#include <unistd.h>

#define NUM_IMGS 2

int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        printf("Usage: %s <img1>\n", argv[0]);
        return -1;
    }

    cvStartWindowThread();

    // Array to store pointers for the images
    IplImage* images[NUM_IMGS] = { 0 };

    for (int i = 0; i < NUM_IMGS; i++)
    {
        // load image
        images[i] = cvLoadImage(argv[i+1], CV_LOAD_IMAGE_UNCHANGED);
        if (!images[i])
        {
            printf("!!! failed to load: %s\n", argv[i+1]);
            continue;
        }

        // display image in a window
        cvNamedWindow(argv[i+1], CV_WINDOW_AUTOSIZE); // creating a new window each time
        cvShowImage(argv[i+1], images[i]);

        // wait for keypress
        cvWaitKey(0);

        // close the window
        cvDestroyWindow(argv[i+1]);
        cvReleaseImage(&images[i]);
    }

    //    cvWaitKey(1);
    sleep(10);
    return 0;
}
like image 25
Evgeny Kluev Avatar answered Nov 20 '22 22:11

Evgeny Kluev


There is no need to destroy the window on each frame, you can simply call cvShowImage() with the same window name and it will replace the current image.

You only need to call destroy window at shutdown. You can use cvCreateWindow() to create the window at startup but it will be created automatically on the first showWindow() call.

like image 3
Martin Beckett Avatar answered Nov 20 '22 23:11

Martin Beckett