I'm trying to take and display the most current frame on any key event. It is important for me that the photo will be taken only once (without using infinity loop). I have a problem because displayed photo is the previous one not the most current. It looks like some buffor with captured frames in VideoCapture object.
I'm using OpenCV 4.6.0 and laptop camera.
#include <iostream>
#include <opencv2/opencv.hpp>
int main() {
cv::VideoCapture cap0(0);
cv::Mat frame0;
for (;;)
{
cap0.read(frame0);
if (!frame0.empty())
{
imshow("cap0", frame0);
}
cv::waitKey(0);
}
return 0;
}
Is it possible to get and display current photo without doing infinity loop whenever I click any key?
Related
I want to show a live stream of the camera connected to raspberry in qt application (OS Linux). After googling it, I found out I must display the video inside QLabel. When displaying an image there's no problem and everything works fine, but when I want to display the live stream inside QLabel, the live stream window opens separately (not inside QLabel). would you tell me how to solve this problem? here's my code :
void Dialog::on_Preview_clicked()
{
command = "raspistill";
args<<"-o"<<"/home/pi/Pictures/Preview/"+Date1.currentDateTime().toString()+".jpg"<<"-t"<<QString::number(20000);
Pic.start(command,args,QIODevice::ReadOnly);
QPixmap pix("//home//pi//Pictures//Preview//test.jpg");
ui->label_2->setPixmap(pix);
ui->label_2->setScaledContents(true);
}
This code opens video capturing screen and captures an image after 20 seconds. the only problem is that the capture screen (which could be used as a live stream). isn't being displayed inside the "Lable_2". Is there anyway to do this without using OpenCV library? If not, tell me how to do it using OpenCV.
Thanks
It is pretty simple in opencv
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
return -1;
Mat edges;
namedWindow("edges",1);
for(;;)
{
Mat frame;
cap >> frame; // get a new frame from camera
imshow("edges", frame);
if(waitKey(30) >= 0) break;
}
return 0;
}
Stream the camera using OpenCV, and show it in QLabel is possible.
When QCamera not working, and also use OpenCV in the project, could use VideoCapture to stream the video instead of QCamera.
The problem can be decomposed into several steps. Basically, We need:
Create a QThread for streaming(Don't let the GUI thread blocked).
In the sub-thread, using cv::VideoCapture to capture the frame into a cv::Mat.
Convert the cv::Mat to QImage(how to convert an opencv cv::Mat to qimage).
Pass QImage frame from sub-thread to the main GUI thread.
Paint the QImage on the QLabel.
I put the complete demo code in Github. it could paint the frame on the QLabel and QML VideoOutput.
I'm using OpenCV 3.1, I try to run a simple code as the following one (main function):
cv::VideoCapture cam;
cv::Mat matTestingNumbers;
cam.open(0);
if (!cam.isOpened()) { printf("--(!)Error opening video capture\n"); return -1; }
while (cam.read(matTestingNumbers))
{
cv::imshow("matTestingNumbers", matTestingNumbers);
cv::waitKey(5000);
}
When I move the camera it seems that the code does not capture and show the current frame but shows all the captured frames from the previous position and only then from the new one.
So when I capture the wall it shows the correct frames (the wall itself) in the correct delay, but, when I twist the camera to my computer, I first see about 3 frames of the wall and only then the computer, it seems that the frames are stuck.
I've tried to use videoCapture.set() functions and set the FPS to 1, and I tried to switch the method of capturing to cam >> matTestingNumbers (and the rest of the main function according to this change) but nothing helped, I still got "stuck" frames.
BTW, These are the solutions I found on web.
What can I do to fix this problem?
Thank you, Dan.
EDIT:
I tried to retrieve frames as the following:
#include "opencv2/opencv.hpp"
using namespace cv;
int main(int, char**)
{
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
return -1;
Mat frame;
namedWindow("edges",1);
for(;;)
{
cap.grab();
if (waitKey(11) >= 0)
{
cap.retrieve(frame);
imshow("edges", frame);
}
}
return 0;
}
But, it gave the result (when I pointed the camera on one spot and pressed a key it showed one more of the previous frames that were captured of the other point).
It is just like you're trying to picture one person then another but when you picture the second you get the photo of the first person what doesn't make sense.
Then, I tried the following:
#include "opencv2/opencv.hpp"
using namespace cv;
int main(int, char**)
{
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
return -1;
Mat frame;
namedWindow("edges",1);
for(;;)
{
cap >> frame;
if (waitKey(33) >= 0)
imshow("edges", frame);
}
return 0;
}
And it worked as expected.
One of the problems is that you are not calling cv::waitKey(X) to properly freeze the window for X amount of milliseconds. Get rid of usleep()!
i'm working on a project using OpenCV243, I need to get the foreground during a stream, my Problem is that I use the cv::absdiff to get it doesn't really help, here is my code and the result .
#include <iostream>
#include<opencv2\opencv.hpp>
#include<opencv2\calib3d\calib3d.hpp>
#include<opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
int main (){
cv::VideoCapture cap(0);
cv::Mat frame,frame1,frame2;
cap >> frame;
frame.copyTo(frame1);
cv::imwrite("background.jpeg",frame1);
int key = 0;
while(key!=27){
cap >> frame;
cv::absdiff(frame, frame1, frame2); // frame2 = frame -frame1
cv::imshow("foreground", frame2);
if(key=='c'){
//frame.copyTo(frame2);
cv::imwrite("foreground.jpeg", frame2);
key = 0;
}
cv::imshow("frame",frame);
key = cv::waitKey(10);
}
cap.release();
return 0;
}
as you can see the subtraction work but what I want to get is only the values of that changed for example if have a Pixel in the background with [130,130,130] and the same pixel has [200,200,200] in the frame I want to get exactly the last values and not [70,70,70]
I've already seen this tutorial : http://mateuszstankiewicz.eu/?p=189
but I can't understand the code and I have problems setting cv::BackgroundSubtractorMOG2 with my openCV version
thanks in advance for you help
BackgroundSubtractorMOG2 should work with #include "opencv2/video/background_segm.hpp"
The samples with OpenCV have two nice c++ examples (in the samples\cpp directory).
bgfg_segm.cpp shows how to use the BackgroundSubtractorMOG2
bgfg_gmg.cpp uses BackgroundSubtractorGMG
To get the last values (and asuming you meant to get the foreground pixel values) you could copy the frame using the foreground mask. This is also done in the first example, in the following snippet:
bg_model(img, fgmask, update_bg_model ? -1 : 0);
fgimg = Scalar::all(0);
img.copyTo(fgimg, fgmask);
I am using OpenCV and trying to apply a Gaussian Blur to an incoming video stream. I basically use cvQueryFrame to remove a frame, blur it and display the frame onto the screen. The thing is though, my video gets stuck on the first frame after I apply the blur....anyone know why? its basically showing one frame instead of a video. The second I remove the blur it starts outputting video again.
#include "cv.h"
#include "highgui.h"
#include "cvaux.h"
#include <iostream>
using namespace std;
int main()
{
//declare initial data
IplImage *grabCapture= 0; //used for inital video frame capture
IplImage *process =0; //used for processing
IplImage *output=0; //displays final output
CvCapture* vidStream= cvCaptureFromCAM(0);
cvNamedWindow ("Output", CV_WINDOW_AUTOSIZE);
int createimage=1;
while (1)
{
grabCapture= cvQueryFrame (vidStream);
if (createimage==1)
{
process= cvCreateImage (cvGetSize(grabCapture), IPL_DEPTH_16U, 3);
createimage=0;
}
*process=*grabCapture;
cvSmooth (process,process,CV_GAUSSIAN,7,7); //line that makes it display frame instead of video
cvShowImage("Output",process);
}
//clean up data
cvReleaseImage (&grabCapture);
cvReleaseImage (&process);
cvReleaseImage (&output);
cvReleaseCapture (&vidStream);
return 0;
}
You are missing a call to cvWaitKey. This is the only way to tell OpenCV to process events and thus prevent the GUI from freezing.
Try adding this line:
cvWaitKey(10);
after cvShowImage("Output",process);.
Edit: here is the documentation for cvWaitKey
I need a program to capture pictures from multiple webcams and save them automatically in Windows Vista. I got the basic code from this link. The code runs in Window XP, but when I tried using it on Vista it says "failed." Different errors pop up every time it is executed. Would it help if I used the SDK platform? Does anyone have any suggestions?
I can't test this on multiple webcams since I only have one, but I'm sure OpenCV2.0 should be able to handle it. Here's some sample code (I use Vista) with one webcam to get you started.
#include <cv.h>
#include <highgui.h>
using namespace cv;
int main()
{
// Start capturing on camera 0
VideoCapture cap(0);
if(!cap.isOpened()) return -1;
// This matrix will store the edges of the captured frame
Mat edges;
namedWindow("edges",1);
for(;;)
{
// Acquire the frame from cap into frame
Mat frame;
cap >> frame;
// Now, find the edges by converting to grayscale, blurring and then Canny edge detection
cvtColor(frame, edges, CV_BGR2GRAY);
GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
Canny(edges, edges, 0, 30, 3);
// Display the edges and the frame
imshow("edges", edges);
imshow("frame", frame);
// Terminate by pressing a key
if(waitKey(30) >= 0) break;
}
return 0;
}
Note:
The matrix edges is allocated during
the first frame processing and unless
the resolution will suddenly change,
the same buffer will be reused for
every next frame’s edge map.
As you can see, the code is quite clean and readable! I lifted this from the OpenCV 2.0 documentation (opencv.pdf).
The code not only displays the image from the webcam (under frame) but also does real-time edge detection! Here's a screenshot when I pointed the webcam at my monitor :)
screenshot http://img245.imageshack.us/img245/5014/scrq.png
If you want code to just display the frames from one camera:
#include <cv.h>
#include <highgui.h>
using namespace cv;
int main()
{
VideoCapture cap(0);
if(!cap.isOpened()) return -1;
for(;;)
{
Mat frame;
cap >> frame;
imshow("frame", frame);
if(waitKey(30) >= 0) break;
}
return 0;
}
If the program works with UAC off or when running administrator, make sure the place you choose to save the results are in writable places like the user's my documents folder. Generally speaking root folders and the program files folder is read only for normal users.