Take screenshot of webcam feed on Keypress using OpenCV and C++ - c++

I'm currently getting the webcam feed of my laptop using VideoCapture cap(0) function and then display it in a Mat frame. What I want to do next is whenever I press a key 'c' for example, it takes the screenshot of the frame and save it into a folder as a JPEG image. However I have no idea on how to do so. Help is much needed, thank you.

I have spent several days searching the internet for the right solution with simple keyboard input. Ther was allways some leg / delay while using cv::waitKey.
The solution i have found is with adding Sleep(5) just after the capturing the frame from webcam.
The below example is a combination of different forum threads.
It works without any leg / delay. Windows OS.
Press "q" to capture and save the frame.
There is a webcam feed always present. You can change the sequence to show the captured frame / image.
PS "tipka" - means "key" on the keyboard.
Regards, Andrej
#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
#include <windows.h> // For Sleep
using namespace cv;
using namespace std;
int ct = 0;
char tipka;
char filename[100]; // For filename
int c = 1; // For filename
int main(int, char**)
{
Mat frame;
//--- INITIALIZE VIDEOCAPTURE
VideoCapture cap;
// open the default camera using default API
cap.open(0);
// OR advance usage: select any API backend
int deviceID = 0; // 0 = open default camera
int apiID = cv::CAP_ANY; // 0 = autodetect default API
// open selected camera using selected API
cap.open(deviceID + apiID);
// check if we succeeded
if (!cap.isOpened()) {
cerr << "ERROR! Unable to open camera\n";
return -1;
}
//--- GRAB AND WRITE LOOP
cout << "Start grabbing" << endl
<< "Press a to terminate" << endl;
for (;;)
{
// wait for a new frame from camera and store it into 'frame'
cap.read(frame);
if (frame.empty()) {
cerr << "ERROR! blank frame grabbed\n";
break;
}
Sleep(5); // Sleep is mandatory - for no leg!
// show live and wait for a key with timeout long enough to show images
imshow("CAMERA 1", frame); // Window name
tipka = cv::waitKey(30);
if (tipka == 'q') {
sprintf_s(filename, "C:/Images/Frame_%d.jpg", c); // select your folder - filename is "Frame_n"
cv::waitKey(10);
imshow("CAMERA 1", frame);
imwrite(filename, frame);
cout << "Frame_" << c << endl;
c++;
}
if (tipka == 'a') {
cout << "Terminating..." << endl;
Sleep(2000);
break;
}
}
// the camera will be deinitialized automatically in VideoCapture destructor
return 0;
}

Related

Record multiple videos from webcam stream in OpenCV C++

I want to record selected frames as multiple videos from webcam. I tried the following code to start recording a video on a key press and stop recording that video with a different key press. I want to record multiple such videos. But the recorded video files are empty. I can run its equivalent Python code successfully, but I want the same in C++. Can you please help me to correct my mistake?
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
int main(){
// Create a VideoCapture object and use camera to capture the video
VideoCapture cap(0);
// Check if camera opened successfully
if(!cap.isOpened()){
cout << "Error opening video stream" << endl;
return -1;
}
// Default resolutions of the frame are obtained.
int frame_width = cap.get(cv::CAP_PROP_FRAME_WIDTH);
int frame_height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
bool recording = false;
int videono = 1;
VideoWriter video("dummy.avi", cv::VideoWriter::fourcc('M','J','P','G'), 10, Size(frame_width,frame_height));
video.release();
while(1)
{
Mat frame;
// Capture frame-by-frame
cap >> frame;
// If the frame is empty, break immediately
if (frame.empty())
break;
// Display the resulting frame
imshow( "Frame", frame );
// Press ESC on keyboard to exit
char c = (char)waitKey(1);
if( c == 27 )
break;
// Press s on keyboard to start recording
if( c == 115 and !recording)
{
char path[100];
sprintf(path, "%d.avi", videono);
std::cout << "recording started for " << path << "\n";
videono += 1;
VideoWriter video(path, cv::VideoWriter::fourcc('M','J','P','G'), 10, Size(frame_width,frame_height));
recording = true;
}
if( recording )
video.write(frame);
// Press x on keyboard to stop recording
if( c == 120)
{
std::cout << "recording finished.\n";
recording = false;
video.release();
}
}
// release the video capture and write object
cap.release();
// Closes all the frames
destroyAllWindows();
return 0;
}
Instead of re-creating a new VideoWriter every time and deleting it immediately like this
{
VideoWriter video(path, cv::VideoWriter::fourcc('M','J','P','G'), 10, Size(frame_width,frame_height));
} // <-- deleted here, because it's going out of scope
You should just use the 'open' function on the existing VideoWriter.
So something like this:
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
int main(){
// Create a VideoCapture object and use camera to capture the video
VideoCapture cap(0);
// Check if camera opened successfully
if(!cap.isOpened()){
cout << "Error opening video stream" << endl;
return -1;
}
// Default resolutions of the frame are obtained.
int frame_width = cap.get(cv::CAP_PROP_FRAME_WIDTH);
int frame_height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
bool recording = false;
int videono = 1;
VideoWriter video;
while(1)
{
Mat frame;
// Capture frame-by-frame
cap >> frame;
// If the frame is empty, break immediately
if (frame.empty())
break;
// Display the resulting frame
imshow( "Frame", frame );
char c = (char)waitKey(1);
if( c == 27 ) // Press ESC on keyboard to exit
break;
if( c == 115 and !recording) // Press s on keyboard to start recording
{
char path[100];
sprintf(path, "%d.avi", videono);
std::cout << "recording started for " << path << "\n";
videono += 1;
video.open(path, cv::VideoWriter::fourcc('M','J','P','G'), 10, Size(frame_width,frame_height));
recording = true;
}
if( recording )
video.write(frame);
if( c == 'x') // Press x on keyboard to stop recording
{
std::cout << "recording finished.\n";
recording = false;
video.release();
}
}
cap.release();// release the video capture and write object
destroyAllWindows(); // Closes all the frames
return 0;
}

OpenCV imwrite is not working

I have a simple OpenCV application that takes a video stream from the webcam, and when the spacebar is pressed it captures the current image and freezes on that image. When I try to use the cv::imwrite() method to save the picture to disk, it does not work. The code successfully compiles but it does not save the image. It is returning a false value as well from the call. I am not sure if this is an issue of type of image or something else, but I seem to be stumped.
Here is the code for my current cpp class:
#include <iostream>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace std;
using namespace cv;
Mat picture;
char key;
class FacialRec {
};
int main() {
//Starting the video
VideoCapture videoCapture(0);
if (!videoCapture.isOpened()) {
cout << "Unable to open video file." << endl;
return 1;
}
namedWindow("Webcam", CV_WINDOW_AUTOSIZE);
while(true) {
Mat frame;
videoCapture.retrieve(frame);
bool success = videoCapture.read(frame);
if (!success) {
cout << "Could not read from video file" << endl;
return 1;
}
imshow("Webcam", frame);
key = waitKey(30);
if (key == 27) { //escape key pressed: stop program
cout << "ESC pressed. Program closing..." << endl;
break;
}else if (key == ' ') { //spacebar pressed: take a picture
picture = frame;
key = -1;
while (true) {
imshow("Webcam", picture);
key = waitKey(30);
if (key == 27 || key == 32) {
cout << "ESC or SPACE pressed. Returning to video..." << endl;
break;
}
if (key == 115) {
//trying to save to current directory
bool maybe = imwrite("/testimage.jpg", picture);
// maybe bool is always getting value of 0, or false
cout << "s was pressed. saving image " << maybe << endl;
}
}
}
}
return 0;
}
You are attempting to write testimage.jpg to the / directory. The executing program probably doesn't have sufficient permissions to write to that directory. Based on your comment, you probably want
//trying to save to current directory
bool maybe = imwrite("./testimage.jpg", picture);
Since . denotes the current working directory.
OpenCV sometimes has problems to write to a .jpg image. Try to change that to .png or .bmp to see if that makes a difference in your case.
If you have further issues with writing images, you can debug them in OpenCV by adding this few lines of code to display them and see if they are valid:
// Create a window for display.
namedWindow( "Display window", WINDOW_AUTOSIZE );
// Show our image inside it.
imshow( "Display window", picture );
// Wait for a keystroke in the window
waitKey(0);
A few suggestions.
try a different file format.
does your IDE defiantly know your target folder / home path directory?
Is your image definitely valid? does it show when you imshow()?

OpenCV Video Capture

I am using OpenCV 2.4.8 and Visual Studio 2013 to run the following simple VideoCapture program. The program is intended to capture the video from the webcam and display it.
However, the program works fine only for the FIRST TIME (after signing in windows), and doesn't work second time.
The problem I get on debugging is :
After executing this line - "bool bSuccess = cap.read(frame);" frame variable is still NULL.
#include "stdafx.h"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
char key;
int main(int argc, char* argv[])
{
VideoCapture cap(0); // open the video camera no. 0
if(!cap.isOpened()) // if not success, exit program
{
cout << "Cannot open the video file" << endl;
return -1;
}
double dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH); //get the width of frames of the video
double dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT); //get the height of frames of the video
cout << "Frame size : " << dWidth << " x " << dHeight << endl;
namedWindow("MyVideo",CV_WINDOW_AUTOSIZE); //create a window called "MyVideo"
Mat frame;
while(1)
{
bool bSuccess = cap.read(frame); // read a new frame from video
if (!bSuccess) //if not success, break loop
{
cout << "Cannot read a frame from video file" << endl;
break;
}
imshow("MyVideo", frame); //show the frame in "MyVideo" window
if(waitKey(30) == 27) //wait for 'esc' key press for 30ms. If 'esc' key is pressed, break loop
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
This happen because the camera is not correctly closed after first instance of program. You should try to close the console by esc button and not by clicking X.
Could you try and read more than a single frame before breaking the loop? This may be similar to this problem, where a corrupted first frame / slow camera set up was the only problem.
Unable to read frames from VideoCapture from secondary webcam with OpenCV

RaspberryPi C++ app compile issue using OpenCV and Raspicam

Using the code below, I am trying to create an app in C++ with OpenCV + Raspicam. This app should stream video in real time from the RasPi camera model connected to my Pi to an Xwindow.
I get the following error on compile:
videofeed.cpp: In function ‘int main(int, char**)’:
videofeed.cpp:36:37: error: ‘cv::imread’ is not a member of ‘raspicam::RaspiCam_Cv’
How do I remedy this?
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>
#include </home/pi/raspicam-0.1.3/src/raspicam_cv.h>
using namespace std;
int main ( int argc,char **argv ) {
raspicam::RaspiCam_Cv Camera;
cv::Mat image;
int nCount=100;
//set camera params
Camera.set( CV_CAP_PROP_FORMAT, CV_8UC1 );
//Open camera
cout<<"Opening Camera..."<<endl;
if (!Camera.open())// if not success, exit program
{
cout << "Cannot open the video cam" << endl;
return -1;
}
double dWidth = Camera.get(CV_CAP_PROP_FRAME_WIDTH); //get the width of frames o$
double dHeight = Camera.get(CV_CAP_PROP_FRAME_HEIGHT); //get the height of frame$
cout << "Frame size : " << dWidth << " x " << dHeight << endl;
cv::namedWindow("MyVideo",CV_WINDOW_AUTOSIZE); //create a window called "MyVideo"
while (1)
{
cv::Mat frame;
bool bSuccess = Camera.cv::imread(frame); // get a new frame from camera
if (!bSuccess) //if not success, break loop
{
cout << "Cannot read a frame from video stream" << endl;
break;
}
cv::imshow("MyVideo", frame); //show the frame in "MyVideo" window
if (cv::waitKey(30) == 27) //wait for 'esc' key press for 30ms. If 'esc' ke$
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////
bool bSuccess = Camera.cv::imread(frame); is an error,there is no imreadfunciton in raspicam::RaspiCam_Cv.If you want grub a frame,you can use function grub and than retrieve .
For example:
Mat img;
camera.grab();
camera.retrieve(img);
You can see the declaration:
/**
* Grabs the next frame from video file or capturing device.
*/
bool grab();
/**
*Decodes and returns the grabbed video frame.
*/
void retrieve ( cv::Mat& image );
Also ,you can get example in:https://github.com/cedricve/raspicam

opencv videocapture c++ not working 2 times

I tried the following code for capturing a video from my webcam:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
int main()
{
VideoCapture cap(0); // open the video camera no. 0
if (!cap.isOpened()) // if not success, exit program
{
cout << "Cannot open the video cam" << endl;
return -1;
}
double dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH); //get the width of frames of the video
double dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT); //get the height of frames of the video
cout << "Frame size : " << dWidth << " x " << dHeight << endl;
namedWindow("MyVideo", CV_WINDOW_AUTOSIZE); //create a window called "MyVideo"
namedWindow("Changed", CV_WINDOW_AUTOSIZE);
while (1)
{
Mat frame;
bool bSuccess = cap.read(frame); // read a new frame from video
if (!bSuccess) //if not success, break loop
{
cout << "Cannot read a frame from video stream" << endl;
break;
}
Mat imgH = frame + Scalar(75, 75, 75);
imshow("MyVideo", frame); //show the frame in "MyVideo" window
imshow("Changed", imgH);
if (waitKey(30) == 27) //wait for 'esc' key press for 30ms. If 'esc' key is pressed, break loop
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
Now here's my problem:
After debugging that program for the first time everything works as expected. But when debugging for a second time (after changing some lines in the code) it cannot read from the camera.
Does anyone have a hint for me how to solve that problem?
Thanks!
The code you posted seems to be working absolutely fine in my case, and the output is as intended.
However please make sure that your webcam is switched on before you run the program, this is important.
Since i have a YouCam client in my computer for the webcam, therefore it shows that i need to start youcam.
Since i dont have enough reputation to post an image, so please see the following link in order to view the output i got when webcam not already switched on.
http://i.imgur.com/h4bTZ7z.png
Hope this helps!!