OpenCV-关闭图像显示窗口
OpenCV - closing the image display window
我正在做一个搜索图像数据库的项目,当我找到一些查询-5数据库图像的结果时,我想直观地显示结果。我没有把所有的图像都保存在内存中,所以我必须先加载图像才能显示它
我有一些简单的想法,用伪代码:
for image 1..5
load images
display image in a window
wait for any keypress
close the window
以下是我在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);
}
这里使用的images
数组在我的代码中并不存在,但为了解决问题,它包含相对于当前程序运行点的映像的文件名(如果是name
成员的话)。我在项目中存储的图像名称有点不同。
上面的代码几乎是有效的:我可以迭代4/5个图像,但当显示最后一个图像并按下一个键时,图像会变灰,我无法关闭图像窗口而不破坏我的应用程序的其余部分。
我的第一个想法是,由于编译时优化,cvReleaseImage
在cvDestroyWindow
完成之前发布映像,这在某种程度上使其冻结。但是,我已经尝试添加一些等待时间(因此我的代码的sleep(1)
行被注释掉了),但没有帮助。
我从控制台应用程序调用此显示功能,当图像冻结时,控件返回到我的应用程序,我可以继续使用它(但图像窗口仍然冻结在后台)。
你能给我一些关于如何解决这个问题的建议吗?
编辑
自从提出这个问题以来,我定期与一些处理计算机视觉和OpenCV的人交谈,但仍然没有任何想法。
我也发现了一个类似的stackoverflow问题,但仍然没有公认的答案。谷歌只是给出了类似的问题,但没有答案。
任何关于尝试什么的想法(即使它们不是完整的解决方案)都将不胜感激。
出于测试目的,下面的应用程序完全按照您在问题中所说的操作:它通过命令行逐个加载7个图像,并为每个要显示的图像创建一个新窗口。
它与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: %sn", 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()
通常只启动相当复杂的窗口销毁过程。此过程需要在窗口系统和应用程序之间进行一些交互(事件交换)。在该过程完成之前,无法完全销毁该窗口。这就是为什么在应用程序执行与GUI无关的操作时,您会看到部分销毁的窗口的原因。
事件交换可以以依赖于系统的方式执行。在Windows中,这意味着(直接或间接)调用GetMessage
或MsgWaitFor*
函数并处理结果。对于Unixes,这意味着(直接或间接)调用XNextEvent
并处理结果。
OpenCV允许以独立于系统的方式进行此事件交换。有两种记录在案的方法可以做到这一点。第一个是cvWaitKey()
(只需在关闭最后一个图像后调用cvWaitKey(1)
)。第二个是在程序开始时调用cvStartWindowThread()
,以允许OpenCV自动更新其窗口。
这些方法中只有一个在我的带有libcv2.1:cvStartWindowThread()
的Linux盒子上正常工作。
更新(带有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: %sn", 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;
}
不需要破坏每帧上的窗口,只需使用相同的窗口名称调用cvShowImage(),它就会替换当前图像。
您只需要在关闭时调用destroy窗口。您可以在启动时使用cvCreateWindow()创建窗口,但它将在第一次showWindow()调用时自动创建。
在您的代码中,我没有看到调用cvNamedWindow()
来创建您用来显示图像的任何窗口(以及您销毁的窗口)。在cvShowImage()
之前,您可能应该将其中一个调用放入循环中(正如karlphillip在他的回答中所示)。
如果在循环之前创建命名窗口:是否确保没有任何图像具有重复名称?为了确保您不会将图像分配给已销毁的窗口,并确保您不会销毁已销毁的窗?
省略cvDestroyWindow()
的所有调用并使用cvDestroyAllWindows()
的单个调用是否有助于避免您的问题?
您是否测试了第5张图像是否正确加载?这个怎么样?
for(...)
{
if(!img)
break;
// display it
}
您遇到的问题听起来像是指向cvShowImage()的空指针;
我喜欢openCV,但它不是显示测试查询搜索结果的唯一方法。您可以在图像文件夹的根目录中用c++代码编写一个html文件,然后在浏览器中打开它。
如果您正在运行Web服务器,您可以编写一个简单的文件列表,并使用简单的php脚本或类似脚本发布它。
生成的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>
这种方法的优点是它可以在无头服务器上运行。
要关闭图像显示窗口,请参阅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.pngn" << 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 %sn", 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;
}
如果要关闭所有OpenCV图像显示窗口用法:destroyAllWindows();
我想要的是一个检查是否按下了键或窗口是否关闭的解决方案。这样python就不会停滞:
"""Check if window closed or key pressed"""
import cv2 as cv
img = cv.imread('image.jpg')
cv.imshow("MyWindow", img)
while cv.getWindowProperty("MyWindow", cv.WND_PROP_VISIBLE) > 0:
if cv.waitKey(1000) > 0:
break
尝试使用
cvDestroyWindow("Match");
// sleep(1);
cvReleaseImage(&img); // outside the for loop
- 使用 while 循环时不显示窗口
- 有没有办法拿一个opencv显示窗口并将其保存到GUI窗口?
- SDL视频显示窗口:如何连接窗口关闭事件回调
- Qt:缓慢启动时显示窗口内容
- 为什么MessageBox在我创建的桌面中显示窗口,而AllocConsole在上一个桌面中显示它
- 如何显示窗口大小不同的输出图像?通过使用 cv::Mat
- QMLApplicationViewer 多个实例仅首先显示窗口
- 为什么HWND_NOTTOPMOST无法在xp中显示窗口前景
- 基本C++SFML显示窗口错误
- 使用Richedit控件时,基于对话框的Win32 API程序将不会显示窗口
- 显示窗口的极简主义Visual C++应用程序
- Win32:是否可以显示窗口,但在任务栏中隐藏它
- OpenCV-关闭图像显示窗口
- IWebBrowser2在渲染完成后显示窗口
- 防止在调用SDL_SetVideoMode后显示窗口
- 如何使用rad studio显示窗口总数
- Opencv highgui显示窗口
- 使用sfml显示窗口
- 跨平台c++库/库:显示窗口,在屏幕上渲染2D形状,在屏幕上渲染文本
- 用于创建菜单栏的c++ win32程序(程序编译并运行,也显示窗口但不显示菜单栏)