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.
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;
}
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;
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With