To make my question clearer, please view the following codes below:
For snapping image:
void CameraTest ::on_snapButton_clicked()
{
CvCapture* capture = cvCaptureFromCAM(0); // capture from video device #0
cvSetCaptureProperty(capture ,CV_CAP_PROP_FRAME_WIDTH , 800);
cvSetCaptureProperty(capture ,CV_CAP_PROP_FRAME_HEIGHT , 600);
if(!cvGrabFrame(capture)) //if no webcam detected or failed to capture anything
{ // capture a frame
cout << "Could not grab a frame\n\7";
exit(0);
}
IplImage* img=cvRetrieveFrame(capture); // retrieve the captured frame
cv::Mat imageContainer(img);
image=imageContainer;
cv::imshow("Mat",image);
//cvReleaseCapture(&capture); When I enable this, and run the programming calling this, there will be an error.
}
Now, the program to display the image:
void CameraTest ::on_processButton_clicked()
{
cv::imshow("image snapped", image);
//my image processing steps...
}
When I enable the cvReleaseCapture(&capture) line, I recieve the following error:
Unhandled exception at 0x00fc3ff5 in CameraTest.exe: 0xC0000005: Access violation reading location 0x042e1030.
When I comment/remove the line, I am able to display image properly upon clicking the other button, but when I want to snap new images, I have to click the button a few times, which is a major flaw in the program. Is there anyway to go around it?
avoid the outdated c-api (IplImages, Cv*functions) stick with the c++ api.
the images you get from a capture point to memory inside the cam-driver. if you don't clone() the image, and release the capture, you got a dangling pointer.
don't create a new capture for each shot. (cam needs some 'warm-up' time so it'll be slow as hell).
keep one instance around in your class instead
class CameraTest
{
VideoCapture capture; // make it a class - member
CameraTest () : capture(0) // capture from video device #0
{
capture.set(CV_CAP_PROP_FRAME_WIDTH , 800);
capture.set(CV_CAP_PROP_FRAME_HEIGHT , 600);
}
// ...
};
void CameraTest ::on_snapButton_clicked()
{
Mat img; // temp var pointing todriver mem
if(!capture.read(img)) //if no webcam detected or failed to capture anything
{
cout << "Could not grab a frame\n\7";
exit(0);
}
image = img.clone(); // keep our member var alive
cv::imshow("Mat",image);
}
Replace :
if(!cvGrabFrame(capture)) //if no webcam detected or failed to capture anything
{ // capture a frame
cout << "Could not grab a frame\n\7";
exit(0);
}
by
if ( !capture )
{
cout << "Could not grab a frame\n\7";
exit(0);
}
and replace
IplImage* img=cvRetrieveFrame(capture);
by
IplImage* img = cvQueryFrame( capture );
cvQueryFrame Grabs and returns a frame from video or camera. This function is a combination of cvGrabFrame and cvRetrieveFrame in one call. The returned image should not be released or modified by user.
Related
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?
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.
I ran into a routine that converts from IplImage to QImages in Qt, i tried it and it works perfects, after that i tried to display a video in a label using also Iplframes, it also worked, but now im trying to display live video from my webcam and im running into some kind of trouble because it doesnt display anything, Opencv 2.3 , Ubuntu Linux C++
CvCapture* capture = cvCreateFileCapture( argv[1] );
//CvCapture* capture = cvCaptureFromCAM( 0 );
while(1) {
frame = cvQueryFrame( capture );
cvWaitKey(33);
if( !frame ) break;
cvCvtColor(frame,frame,CV_BGR2RGB);
myImage = QImage((unsigned char *)frame->imageDataOrigin,frame->width,frame->height,QImage::Format_RGB888);
myLabel.setPixmap(QPixmap::fromImage(myImage));
myLabel.show();
//sleep(1);
Sleeper::msleep(33);
}
There i have the 2 options , capturefromcam or capturefromavi, from an avi video it converts and displays converted frames perfectly, but when i try the same thing for my webcam's captured frames it doesnt display anything, also i dont get any error or something like that, any idea?
From the looks of it, cvCaptureFromCAM() failed to find a device at index 0. But you don't know this because you are not coding defensively: cvCaptureFromCAM() returns NULL when it fails to access a device:
CvCapture* capture = cvCaptureFromCAM( 0 );
if (!capture)
{
// print error
// quit application
}
Try passing CV_CAP_ANY or experiment with other indexes: 1, 2, 3, and if none of them work I suggest you check the compatibility list and verify is your camera is supported by OpenCV.
The same attention should be payed with cvQueryFrame():
frame = cvQueryFrame( capture );
if (!frame)
{
// print error
// quit application
}
I have a grabber which can get the images and show them on the screen with the following code
while((lastPicNr = Fg_getLastPicNumberBlockingEx(fg,lastPicNr+1,0,10,_memoryAllc))<200) {
iPtr=(unsigned char*)Fg_getImagePtrEx(fg,lastPicNr,0,_memoryAllc);
::DrawBuffer(nId,iPtr,lastPicNr,"testing"); }
but I want to use the pointer to the image data and display them with OpenCV, cause I need to do the processing on the pixels. my camera is a CCD mono camera and the depth of the pixels is 8bits. I am new to OpenCV, is there any option in opencv that can get the return of the (unsigned char*)Fg_getImagePtrEx(fg,lastPicNr,0,_memoryAllc); and disply it on the screen? or get the data from the iPtr pointer an allow me to use the image data?
Creating an IplImage from unsigned char* raw_data takes 2 important instructions: cvCreateImageHeader() and cvSetData():
// 1 channel for mono camera, and for RGB would be 3
int channels = 1;
IplImage* cv_image = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, channels);
if (!cv_image)
{
// print error, failed to allocate image!
}
cvSetData(cv_image, raw_data, cv_image->widthStep);
cvNamedWindow("win1", CV_WINDOW_AUTOSIZE);
cvShowImage("win1", cv_image);
cvWaitKey(10);
// release resources
cvReleaseImageHeader(&cv_image);
cvDestroyWindow("win1");
I haven't tested the code, but the roadmap for the code you are looking for is there.
If you are using C++, I don't understand why your are not doing it the simple way like this:
If your camera is supported, I would do it this way:
cv::VideoCapture capture(0);
if(!capture.isOpened()) {
// print error
return -1;
}
cv::namedWindow("viewer");
cv::Mat frame;
while( true )
{
capture >> frame;
// ... processing here
cv::imshow("viewer", frame);
int c = cv::waitKey(10);
if( (char)c == 'c' ) { break; } // press c to quit
}
I would recommend starting to read the docs and tutorials which you can find here.