我在Linux上遇到了一个奇怪的问题,特别是Ubuntu 16.04上的OpenCV。如果我使用通常的代码来显示这样的网络摄像头流,则效果很好:
// WebcamTest.cpp
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
// declare a VideoCapture object and associate to webcam, 1 => use 2nd webcam, the 0th webcam is the one integral to the TX2 development board
cv::VideoCapture capWebcam(1);
// check if VideoCapture object was associated to webcam successfully, if not, show error message and bail
if (capWebcam.isOpened() == false)
{
std::cout << "error: capWebcam not accessed successfully\n\n";
return (0);
}
cv::Mat imgOriginal; // input image
cv::Mat imgGrayscale; // grayscale of input image
cv::Mat imgBlurred; // intermediate blured image
cv::Mat imgCanny; // Canny edge image
char charCheckForEscKey = 0;
// while the Esc key has not been pressed and the webcam connection is not lost . . .
while (charCheckForEscKey != 27 && capWebcam.isOpened())
{
bool blnFrameReadSuccessfully = capWebcam.read(imgOriginal); // get next frame
// if frame was not read successfully, print error message and jump out of while loop
if (!blnFrameReadSuccessfully || imgOriginal.empty())
{
std::cout << "error: frame not read from webcam\n";
break;
}
// convert to grayscale
cv::cvtColor(imgOriginal, imgGrayscale, CV_BGR2GRAY);
// blur image
cv::GaussianBlur(imgGrayscale, imgBlurred, cv::Size(5, 5), 0);
// get Canny edges
cv::Canny(imgBlurred, imgCanny, 75, 150);
cv::imshow("imgOriginal", imgOriginal);
cv::imshow("imgCanny", imgCanny);
charCheckForEscKey = cv::waitKey(1); // delay (in ms) and get key press, if any
} // end while
return (0);
}
此示例在一个显示窗口中显示网络摄像头流,在第二个窗口中显示Canny边缘图像。两个窗口都会更新并按预期显示图像,并且几乎没有可见的闪烁。
如果您想知道为什么我使用第1个摄像头而不是通常的第0个摄像头,请在Jetson TX2上运行,第0个摄像头是开发板不可或缺的一个,我更喜欢使用其他外部网络摄像头。出于同样的原因,我必须使用Ubuntu 16.04,但是我怀疑结果与Ubuntu 18.04相同(但是尚未测试)。
如果相反,我有一个需要大量处理而不是简单的Canny边缘的函数,即:
int main(void)
{
.
.
.
// declare a VideoCapture object and associate to webcam, 1 => use 2nd webcam, the 0th webcam is the one integral to the TX2 development board
cv::VideoCapture capWebcam(1);
// check if VideoCapture object was associated to webcam successfully, if not, show error message and bail
if (capWebcam.isOpened() == false)
{
std::cout << "error: capWebcam not accessed successfully\n\n";
return (0);
}
cv::namedWindow("imgOriginal");
cv::Mat imgOriginal;
char charCheckForEscKey = 0;
// while the Esc key has not been pressed and the webcam connection is not lost . . .
while (charCheckForEscKey != 27 && capWebcam.isOpened())
{
bool blnFrameReadSuccessfully = capWebcam.read(imgOriginal); // get next frame
// if frame was not read successfully, print error message and jump out of while loop
if (!blnFrameReadSuccessfully || imgOriginal.empty())
{
std::cout << "error: frame not read from webcam\n";
break;
}
detectLicensePlate(imgOriginal);
cv::imshow("imgOriginal", imgOriginal);
charCheckForEscKey = cv::waitKey(1); // delay (in ms) and get key press, if any
} // end while
.
.
.
return (0);
}
detectLicensePlate()
函数大约需要运行一秒钟。
我遇到的问题是,在运行该程序时,窗口仅出现最短的时间,通常时间不足以至于无法察觉,也没有足够长的时间才能真正看到结果。
奇怪的是,窗口消失了,然后detectLicensePlate()
进行工作的第二天左右,然后窗口再次出现了很短的时间,然后又消失了,依此类推。就像在cv::imshow("imgOriginal", imgOriginal);
之后,cv::destroyAllWindows();
被隐式调用一样。
我试图实现的行为是使窗口保持打开状态,并在处理下一个结果时继续显示上一个结果。我记得这是Windows上的默认行为。
我应该提到的是,我在while循环之前用cv::namedWindow("imgOriginal");
明确声明了Windows,以免使其超出范围,但这似乎无济于事。
我当然可以延长延迟时间,即
charCheckForEscKey = cv::waitKey(1500);
要等待1.5秒,但应用程序将变得非常无响应。
基于本文c++ opencv image not display inside the boost thread,我尝试在while循环之外声明窗口,并将detectLicensePlate()
和cv::imshow()
放在单独的线程中,如下所示:
.
.
.
cv::namedWindow("imgOriginal");
boost::thread myThread;
// while the Esc key has not been pressed and the webcam connection is not lost . . .
while (charCheckForEscKey != 27 && capWebcam.isOpened())
{
// if frame was not read successfully, print error message and jump out of while loop
if (!blnFrameReadSuccessfully || imgOriginal.empty())
{
std::cout << "error: frame not read from webcam\n";
break;
}
myThread = boost::thread(&preDetectLicensePlate, imgOriginal);
myThread.join();
.
.
.
} // end while
// separate function
void preDetectLicensePlate(cv::Mat &imgOriginal)
{
detectLicensePlate(imgOriginal);
cv::imshow("imgOriginal", imgOriginal);
}
我什至尝试将detectLicensePlate()
放在一个单独的线程上,而不是cv::imshow()
上,反之,结果仍然相同。无论我如何更改顺序或使用线程,在进行下一轮处理时,都无法使窗口保持打开状态。
我意识到我可以使用完全不同的窗口环境,例如Qt或其他方式,但这可能会解决问题,也可能无法解决问题,但出于各种原因,我真的希望避免这种情况。
是否有人有其他建议来使OpenCV imshow
窗口保持打开状态,直到下一次更新该窗口或显式调用cv::destroyAllWindows()
为止?