I'm running into an odd problem with OpenCV on Linux, Ubuntu 16.04 specifically. If I use usual code to show a webcam stream like this it works fine:
// 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);
}
This example shows the webcam stream in one imshow window and a Canny edges image in a second window. Both windows update and show the images as expected with very little if any perceptible flicker.
If you're wondering why I'm using the 1th camera instead of the usual 0th camera, I'm running this on a Jetson TX2 and the 0th camera is the one integral to the development board and I'd prefer to use an additional external webcam. For this same reason I have to use Ubuntu 16.04 but I suspect the result would be the same with Ubuntu 18.04 (have not tested this however).
If instead I have a function that takes significant processing instead of taking simple Canny edges, i.e.:
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);
}
The detectLicensePlate() function takes about a second to run.
The problem I'm having is, when running this program, the window only appears for the slightest amount of time, usually not long enough to even be perceptible, and never long enough to actually see the result.
The strange thing is, the window disappears, then the second or so day occurs for detectLicensePlate() to do its thing, then the window appears again for a very short time, then disappears again, and so on. It's almost as though just after cv::imshow("imgOriginal", imgOriginal);, cv::destroyAllWindows(); is implicitly being called.
The behavior I'm attempting to achieve is for the window to stay open and continue to show the previous result while processing the next. From what I recall this was the default behavior on Windows.
I should mention that I'm explicitly declaring the windows with cv::namedWindow("imgOriginal"); before the while loop in an attempt to not let it go out of scope but this does not seem to help.
Of course I can make the delay longer, i.e.
charCheckForEscKey = cv::waitKey(1500);
To wait for 1.5 seconds, but then the application gets very unresponsive.
Based on this post c++ opencv image not display inside the boost thread I tried declaring the window outside the while loop and putting detectLicensePlate() and cv::imshow() on a separate thread, as follows:
.
.
.
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);
}
I even tried putting detectLicensePlate() on a separate thread but not cv::imshow(), and the other way around, still the same result. No matter how I change the order or use threading I can't get the window to stay open while the next round of processing is going.
I realize I could use an entirely different windowing environment, such as Qt or something else, and that may or may not solve the problem, but I'd really prefer to avoid that for various reasons.
Does anybody have any other suggestions to get an OpenCV imshow window to stay open until the window is next updated or cv::destroyAllWindows() is called explicitly?
Related
I am taking my first steps with OpenCV and I am trying to run this piece of code. It is supposed to open the specified video in a new window and wait for the user to press ESC. I tried passing both the relative and absolute path to VideoCapture but VideoCapture::isOpened() always fails. Why is this happening?
If I pass 0 to VideoCapture and do NOT call isOpened(), then I get a nice little window.
Note that I am using VS15 and OpenCV 2.4 (with the x86 libs)
#include "opencv2/opencv.hpp"
using namespace cv;
int main(int, char**)
{
VideoCapture cap(path_to_video); // open the video file
// VideoCapture cap(0);
if(!cap.isOpened()) // check if we succeeded
return -1;
namedWindow("Video",1);
for(;;)
{
Mat frame;
cap >> frame; // get a new frame from camera
imshow("Video", frame);
if(waitKey(30) >= 0) break;
}
return 0;
}
EDIT: I solved this by reinstalling OpenCV and creating a new Visual Studio project. The above code miraculously started working.
If I pass 0 to VideoCapture and do NOT call isOpened(), then I get a
nice little window. Why is this happening?
Because the VideoCapture class has two different constructors. The one that takes a string attempts to read from a file. The one that takes an integer attempts to read from a device. Passing 0 to the second version specifies the default device / camera.
VideoCapture::open¶ Open video file or a capturing device for video
capturing
C++: bool VideoCapture::open(const string& filename)
C++: bool VideoCapture::open(int device)
Parameters:
filename – name of the opened video file (eg. video.avi)
or image sequence (eg. img_%02d.jpg, which will read samples like
img_00.jpg, img_01.jpg, img_02.jpg, ...)
device – id of the opened video capturing device (i.e. a camera index).
I've had this issue for a long time and I'm not sure whats going on.
So i have a loop from which nextFrame is called, now the issue lies with what the imshow actually shows.
I specifically want one image every time i call cap.grab() and cap.retrieve(), but it seems to have this buffer internally in the "cap" object, so instead on getting individual instantaneous images i would get a sequence/images of images when i click through the images, then after 3/4 frames a new sequence.
How do i get single frames?
cap is a VideoCapture object, maxCount is the size of the vector.
void CamLoop::nextFrame() {
.
.
.
//if first loop fill a vector<Mat> with random Mats from camera
if (firstLoop) {
Mat buff;
cap >> buff;
for(int i = 0; i<(maxCounter); i++) {
buffer.push_back(buff);
}
}
projector.nextCode();
if (!customImages) {
cap.grab();
Mat buff;
cap.retrieve(buff);
//tried this way too
//cap >> buff;
buffer[counter] = buff;
setMouseCallback( "Camera", mouseFunc, this );
imshow("Camera", buffer[counter]);
waitKey(1);
}
.
.
.
counter++;
}
I am using Linux Mint Rosa with OpenCV 3.1.0 on Eclipse Mars
EDIT
The problem is that VideoCapture has a buffer, try this on your own computer in debug mode, the frames aren't live, how would i over come this issue?
I tried using
cap.set(CV_CAP_PROP_BUFFERSIZE,1);
but it gives me this error.
VIDEOIO ERROR: V4L2: setting property #38 is not supported
also tried
cap.set(CV_CAP_PROP_MODE,1);
but it gives me this error.
VIDEOIO ERROR: V4L2: setting property #9 is not supported
EDIT
It may be the camera with the buffer and not the VideoCapture object itself.
A slow and cheat fix may be to do
cap.open( *CAMERA_NUM* );
in the loop, this is slow but it achieves still images without the buffer.
I am semantically segmenting images within a video sequence and displaying the result within a display window in real-time. However, my code is "dropping frames" by not updating the display window with each call to imshow.
Below is a code extract that demonstrates my problem:
for (int i = 0; i < images->size(); i++)
{
Mat frame = images->getImage(i);
// semantic segmentation code (omitted)
Mat frame_overlay = ...
// problem: the window "seg result" does not always update
imshow("seg result", frame_overlay);
int key = waitKey(1);
if (key == 27)
break;
}
As a work around I can increase the wait time from 1 ms to 10 ms in the call to waitKey, but surely there has to be a better way of doing this.
How can I force the "seg result" window to update with the new frame_overlay image?
I am using opencv to show frames from camera. I want to show that frames in to two separation windows. I want show real frame from camera into first window (show frames after every 30 mili-seconds) and show the frames in second window with some delay (that means it will show frames after every 1 seconds). Is it possible to do that task. I tried to do it with my code but it is does not work well. Please give me one solution to do that task using opencv and visual studio 2012. Thanks in advance
This is my code
VideoCapture cap(0);
if (!cap.isOpened())
{
cout << "exit" << endl;
return -1;
}
namedWindow("Window 1", 1);
namedWindow("Window 2", 2);
long count = 0;
Mat face_algin;
while (true)
{
Mat frame;
Mat original;
cap >> frame;
if (!frame.empty()){
original = frame.clone();
cv::imshow("Window 1", original);
}
if (waitKey(30) >= 0) break;// Delay 30ms for first window
}
You could write the loop to display frames in a single function with the video file name as the argument and call them simultaneously by multi-threading.
The pseudo code would look like,
void* play_video(void* frame_rate)
{
// play at specified frame rate
}
main()
{
create_thread(thread1, play_video, normal_frame_rate);
create_thread(thread2, play_video, delayed_frame_rate);
join_thread(thread1);
join_thread(thread2);
}
I am using openCV 2.4.10 on visual studios 2012 express for desktop on windows 7, 32 bit operating system.
I created a function that initializes a webcam, takes an image and stores it in a matrix, and then returns the image matrix.
Mat frameCapture ()
{
Mat srcCap;
//initializes structure type of cap
VideoCapture cap(0);
if(!cap.isOpened())
{
//check for camera
cout << "No camera detected" << endl;
waitKey(10);
}
//stores next frame into matrix
cap >> srcCap;
//check to see the camera took a picture
if( srcCap.empty())
{
cout << "no data in image\n";
}
//return the image matrix
cap.release();
return srcCap;
}
int main ()
{
Mat src;
src = frameCapture();
imshow (window1, src);
waitKey(0);
}
So when running the program, it will say "no data in image" meaning that srcCap.empty() returned true and then it will throw an assertion error for the imshow function. However, the program will sometimes run and return an image successfully. Furthermore, when I incorporate the function in a loop for image processing, it will sometimes take a few pictures and then randomly spit out "no data in image" and throw the same assertion error, or it won't take the first picture at all and spits out "no data in image", throwing the same assertion error. The camera is detected every time and cap is opened; the code never says "No camera detected"
My question is what is causing cap >> srcCap to not work, is it a hardware issue? The camera i'm using is a usb 2.0 plugable microscope.
I think you that your current program just reads the first frame only. Mostly when reading the camera frame, the first frame may not contain any data.
I would suggest that you use a loop in the main() and read latter frames.