C++ OpenCV - 关闭图像显示窗口
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8842901/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
OpenCV - closing the image display window
提问by penelope
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.
我正在做一个搜索图像数据库的项目,当我找到某个查询的结果 - 5 个数据库图像时,我想直观地显示结果。我没有将所有图像保存在内存中,所以我必须先加载图像以显示它。
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:
这是我为此目的C++
使用的代码片段OpenCV
:
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.
images
此处使用的数组在我的代码中并不存在,但为了问题起见,它包含相对于当前程序运行点的图像的文件名(如果其name
成员)。我在我的项目中存储图像名称有点不同。
The code above almostworks: 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.
上面的代码几乎可以工作:我可以遍历 4/5 个图像,但是当显示最后一个图像并按下一个键时,图像变灰,我无法关闭图像窗口而不会使我的应用程序的其余部分崩溃。
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.
我的第一个想法是,由于编译时优化,cvReleaseImage
在cvDestroyWindow
完成之前释放图像,并以某种方式使其冻结。但是,我尝试添加一些等待时间(因此注释掉了sleep(1)
我的代码行),但没有帮助。
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.
自从提出这个问题以来,我定期与一些处理计算机视觉和 OpenCV 的人进行了交谈,但仍然没有任何想法。
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.
我也发现了一个类似的stackoverflow question,但仍然没有公认的答案。谷歌搜索结果只是给出了类似的问题,但没有答案。
Any ideas on what to try (even if they are not the complete solution) are very much appreciated.
非常感谢关于尝试什么的任何想法(即使它们不是完整的解决方案)。
回答by karlphillip
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.
出于测试目的,下面的应用程序完全按照您在问题中的说明进行操作:它通过命令行一张一张地加载 7 个图像,并为要显示的每个图像创建一个新窗口。
It works flawlessly with OpenCV 2.3.1 on Linux.
它与 Linux 上的 OpenCV 2.3.1 完美配合。
#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;
}
回答by Evgeny Kluev
cvDestroyWindow()
usually only startspretty 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.
cvDestroyWindow()
通常只启动相当复杂的窗口销毁过程。此过程需要窗口系统和您的应用程序之间进行一些交互(事件交换)。在此过程完成之前,无法完全销毁窗口。这就是为什么当您的应用程序执行与 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.
可以以依赖于系统的方式执行事件交换。在 Windows 中,这意味着(直接或间接)调用GetMessage
或MsgWaitFor*
函数并处理结果。对于 Unix 而言,这意味着(直接或间接)调用XNextEvent
和处理结果。
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.
OpenCV 允许以独立于系统的方式进行此事件交换。有两种记录在案的方法可以做到这一点。第一个是cvWaitKey()
(cvWaitKey(1)
关闭最后一个图像后调用)。第二个是cvStartWindowThread()
在程序开始时调用以允许 OpenCV 自动更新其窗口。
Only one of these methods worked properly on my Linux box with libcv2.1: cvStartWindowThread()
.
这些方法中只有一个正确的工作在我的Linux主机,libcv2.1: cvStartWindowThread()
。
Update (code snippet with cvStartWindowThread())
更新(带有 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;
}
回答by Martin Beckett
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.
不需要在每一帧上销毁窗口,您只需使用相同的窗口名称调用 cvShowImage() ,它将替换当前图像。
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.
您只需要在关机时调用销毁窗口。您可以在启动时使用 cvCreateWindow() 创建窗口,但它会在第一次调用 showWindow() 时自动创建。
回答by moooeeeep
In your code, I've seen no calls of cvNamedWindow()
to create any of the windows you use to show images on (and that you destroy). You should probably put one of those calls into the loop, before you cvShowImage()
(as karlphillip has shown in his answer).
在您的代码中,我没有看到cvNamedWindow()
创建任何用于显示图像的窗口(以及您销毁的窗口)的调用。您可能应该先将其中一个调用放入循环中cvShowImage()
(正如 karlphillip 在他的回答中所示)。
If you create the named windows before the loop: Have you made sure that none of the images have duplicate names? To make sure you don't assign an image to a destroyed window, and to make sure you don't destroy a window that has already been destroyed?
如果您在循环之前创建命名窗口:您是否确保没有任何图像具有重复名称?确保不会将图像分配给被破坏的窗口,并确保不会破坏已经被破坏的窗口?
Would omitting all calls of cvDestroyWindow()
and using a single call of cvDestroyAllWindows()
instead help to avoid your problem?
省略所有调用cvDestroyWindow()
并使用单个调用是否cvDestroyAllWindows()
有助于避免您的问题?
回答by Sam
Did you test that your 5th image is correctly loaded? What about this?
您是否测试过您的第 5 张图片是否已正确加载?那这个呢?
for(...)
{
if(!img)
break;
// display it
}
The problem you encounter sounds like a null pointer to cvShowImage();
您遇到的问题听起来像是指向 cvShowImage(); 的空指针;
回答by Samer
If you want to close all OpenCV image display windows
use: destroyAllWindows();
如果要关闭所有 OpenCV 图像显示窗口,请使用: destroyAllWindows();
回答by mfrellum
I love openCV but it is not the only way to display the search result from your test query. You could write a html file from your c++-code in the root of your image folder and open it in a browser.
我喜欢 openCV,但它不是显示测试查询搜索结果的唯一方法。您可以从图像文件夹的根目录中的 c++ 代码编写一个 html 文件,然后在浏览器中打开它。
If you are running a webserver you could write a simple file list and publish it with a simple php-script or similar.
如果您正在运行网络服务器,您可以编写一个简单的文件列表并使用简单的 php 脚本或类似的方式发布它。
The resulting html-code would be something like:
生成的 html 代码类似于:
<!DOCTYPE html>
<html>
<head>
<style>img {display:block}</style>
<meta http-equiv="refresh" content="5">
</head>
<body>
<img src="subfolderA/img1.png" />
<img src="subfolderB/img2.png" />
<img src="subfolderC/img3.png" />
<img src="subfolderD/img4.png" />
<img src="subfolderE/img5.png" />
</body>
</html>
On advantage of this approach is that it can run on a headless server.
这种方法的优点是它可以在无头服务器上运行。
For closing the image display window look at the documentation for opencv2.3: waitKey(especially notes about events), destroyWindowand this code example based on the image.cpp sample in openCV2.3:
要关闭图像显示窗口,请查看 opencv2.3 的文档: waitKey(特别是关于事件的注释)、destroyWindow和基于 openCV2.3 中的 image.cpp 示例的此代码示例:
#include "cv.h" // include standard OpenCV headers, same as before
#include "highgui.h"
#include <stdio.h>
#include <iostream>
using namespace cv; // all the new API is put into "cv" namespace. Export its content
using namespace std;
void help(){
cout <<
"\nThis program shows how to use cv::Mat and IplImages converting back and forth.\n"
"Call:\n"
"./image img1.png img2.png img3.png img4.png img5.png\n" << endl;
}
int main( int argc, char** argv ){
help();
namedWindow("Peephole", CV_WINDOW_AUTOSIZE);
int i=0;
while ((argc-1) > i){
i++;
const char* imagename = argv[i];
Ptr<IplImage> iplimg = cvLoadImage(imagename); // Ptr<T> is safe ref-conting pointer class
if(iplimg.empty()){
fprintf(stderr, "Can not load image %s\n", imagename);
return -1;
}
Mat img(iplimg); // cv::Mat replaces the CvMat and IplImage, but it's easy to convert
// between the old and the new data structures (by default, only the header
// is converted, while the data is shared)
if( !img.data ) // check if the image has been loaded properly
return -1;
// it's easy to pass the new matrices to the functions that only work with IplImage or CvMat:
// step 1) - convert the headers, data will not be copied
// this is counterpart for cvNamedWindow
imshow("Peephole", img);
waitKey();
}
destroyAllWindows();
while (1) {
waitKey(10);
}
// all the memory will automatically be released by Vector<>, Mat and Ptr<> destructors.
return 0;
}
回答by SB26
Try using
尝试使用
cvDestroyWindow("Match");
// sleep(1);
cvReleaseImage(&img); // outside the for loop