Extract all video frame from mp4 video using OpenCV and C++ - c++

I'm following a tutorial to extract video frames. I've read this question, it doesn't work, also queationfrom Open CV Answer, but the solution is for capturing current frame. I have a 120fps video and want to extract all of them. Here's my code
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <string>
#include <sstream>
using namespace cv;
using namespace std;
int c = 0;
string int2str(int &);
int main(int argc, char **argv) {
string s;
VideoCapture cap("test.mp4"); // video
if (!cap.isOpened())
{
cout << "Cannot open the video file" << endl;
return -1;
}
double fps = cap.get(CV_CAP_PROP_FPS); //get the frames per seconds of the video
cout << "Frame per seconds : " << fps << endl;
namedWindow("MyVideo", CV_WINDOW_AUTOSIZE); //create a window called "MyVideo"
while (1)
{
Mat frame;
Mat Gray_frame;
bool bSuccess = cap.read(frame); // read a new frame from video
if (!bSuccess)
{
cout << "Cannot read the frame from video file" << endl;
break;
}
s = int2str(c);
//cout<<("%d\n",frame )<<endl;
c++;
imshow("MyVideo", frame); //show the frame in "MyVideo" window
imwrite("ig" + s + ".jpg", frame);
if (waitKey(30) == 27) //esc key
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
//int to string function
string int2str(int &i) {
string s;
stringstream ss(s);
ss << i;
return ss.str();
}
My problem is, I have a minute video at 120fps. I expected to be able to extract 120 frames. But the extraction went wrong, the video last for 1 minute but I got more than 200 frames stored in my folder. Did I do something wrong in my code ?

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;
}

Frame Extraction Only few seconds in the beginning of video file using OpenCV

Following my previous question, I want to extract frames from a video. But only 2 seconds at the beginning of the video.
I want to work with raw video as much as I can, that why I don't want to cut the original video and then process it.
Here's my code to extract frame. But this will extract all frame from the video :
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <string>
#include <sstream>
using namespace cv;
using namespace std;
int c = 0;
string int2str(int &);
int main(int argc, char **argv) {
string s;
VideoCapture cap("test_video.mp4");
if (!cap.isOpened())
{
cout << "Cannot open the video file" << endl;
return -1;
}
double fps = cap.get(CV_CAP_PROP_FPS);
cout << "Frame per seconds : " << fps << endl;
namedWindow("MyVideo", CV_WINDOW_NORMAL);
resizeWindow("MyVideo", 600, 600);
while (1)
{
Mat frame;
Mat Gray_frame;
bool bSuccess = cap.read(frame);
if (!bSuccess)
{
cout << "Cannot read the frame from video file" << endl;
break;
}
s = int2str(c);
//cout<<("%d\n",frame )<<endl;
c++;
imshow("MyVideo", frame);
imwrite("frame" + s + ".jpg", frame);
if (waitKey(30) == 27)
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
string int2str(int &i) {
string s;
stringstream ss(s);
ss << i;
return ss.str();
}
And advice ? Thanks.
It seems like you already know the FPS of the video. So isn't it just a matter of counting how many frames you have extracted and breaking after you reach FPS * 2?
double fps = cap.get(CV_CAP_PROP_FPS);
int framesToExtract = fps * 2;
for (int frames = 0; frames < framesToExtract; ++frames)
{
... // your processing here
}
Also, I looked at your previous question and it seems like you have a misunderstanding of FPS?
FPS = Frames Per Second, this means how many frames there are every second of the video. So let's say your video is 120 FPS. This means there are 120 frames in one second of video, 240 in two seconds and so on.
So (VIDEO_FPS * x) gets you the amount of frames in x seconds of the video.

Is it possible to crop raw video before extracting all the frames using OpenCV and C++?

I want to crop a certain area of my raw video before extracting the frames. I don't want to use external cropping video software because I need the video to be raw for processing. Is it possible to crop a certain area before extraction ? I read about ROI for images, is it possible for video too ?
Here's my extraction code that's already working :
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <string>
#include <sstream>
using namespace cv;
using namespace std;
int c = 0;
string int2str(int &);
int main(int argc, char **argv) {
string s;
VideoCapture cap("test_video.mov");
if (!cap.isOpened())
{
cout << "Cannot open the video file" << endl;
return -1;
}
double fps = cap.get(CV_CAP_PROP_FPS);
cout << "Frame per seconds : " << fps << endl;
namedWindow("MyVideo", CV_WINDOW_NORMAL);
resizeWindow("MyVideo", 600, 600);
while (1)
{
Mat frame;
Mat Gray_frame;
bool bSuccess = cap.read(frame);
if (!bSuccess)
{
cout << "Cannot read the frame from video file" << endl;
break;
}
s = int2str(c);
//cout<<("%d\n",frame )<<endl;
c++;
imshow("MyVideo", frame);
imwrite("frame" + s + ".jpg", frame);
if (waitKey(30) == 27)
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
string int2str(int &i) {
string s;
stringstream ss(s);
ss << i;
return ss.str();
}
Still need to crop the video, any advice ?

Saved video doesn't have the same duration as streamed video from a camera

I have a question about saving a video with openCV in C++ (I'm using Linux Ubuntu).
I was trying to save a stream from open camera for some time. I finally succeeded, but now I have really not many ideas why the saved stream doesn't have the same duration as I was streaming from my camera. When I am streaming for 10 seconds it has only for example 2-3 seconds and looks like it is accelerated.
Does anybody have some clue what could be the problem? Something wrong in my code or maybe computing performance, maybe the system doesn't save every frame?
Thanks for your help.
My code:
#include <stdio.h>
#include <iostream> // for standard I/O
#include <string> // for strings
#include <opencv2/core.hpp> // Basic OpenCV structures (cv::Mat)
#include <opencv2/videoio.hpp> // Video write
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat capture;
VideoCapture cap(0);
if(!cap.isOpened())
{
cout<<"Cannot connect to camera"<<endl;
return -1;
}
namedWindow("Display",CV_WINDOW_AUTOSIZE);
double dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH);
double dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
Size frameSize(static_cast<int>(dWidth), static_cast<int>(dHeight));
VideoWriter oVideoWriter ("/home/Stream_video/cpp/Cam/out.avi", CV_FOURCC('P','I','M','1'), 20, frameSize,true);
if ( !oVideoWriter.isOpened() ) {
cout << "ERROR: Failed to write the video" << endl;
return -1;
}
while(true){
Mat frame;
bool bSuccess = cap.read(frame); // read a new frame from video
if (!bSuccess) {
cout << "ERROR: Cannot read a frame from video file" << endl;
break; //if not success, break loop
}
oVideoWriter.write(frame); //writer the frame into the file
imshow("Display", frame);
if (waitKey(10) == 27) {
cout << "esc key is pressed by user" << endl;
break;
}
}
}

how to draw a circle in video

im trying to draw a circle in a video from my webcam i using this function
cv::circle(cap,points(1,0),3,cv::Scalar(255,255,255),-1);
i found it in a document but i don't know why its't work i edit my code many time but its still give my error that's my full code i using opencv3
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <vector>
#include <iostream>
#include <sstream>
#include <opencv2/video/background_segm.hpp>
#include <opencv2/video/background_segm.hpp>
using namespace cv;
using namespace std;
int main()
{
VideoCapture cap(0); // open the video file for reading
if ( !cap.isOpened() ) // if not success, exit program
{
cout << "Cannot open the video file" << endl;
return -1;
}
//cap.set(CV_CAP_PROP_POS_MSEC, 300); //start the video at 300ms
double fps = cap.get(CV_CAP_PROP_FPS); //get the frames per seconds of the video
cout << "Frame per seconds : " << fps << endl;
namedWindow("MyVideo",CV_WINDOW_AUTOSIZE); //create a window called "MyVideo"
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 the frame from video file" << endl;
break;
}
imshow("MyVideo", frame); //show the frame in "MyVideo" window
cv::circle(cap,points(1,0),3,cv::Scalar(255,255,255),-1);
if(waitKey(30) == 27) //wait for 'esc' key press for 30 ms. If 'esc' key is pressed, break loop
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
circle accepts a Mat object, not a VideoCapture object. So you need to draw the circle on frame.
Also you need to show the image after you actually draw the circle.
So replace the imshow / circle part of your code with:
...
cv::circle(frame, points(1,0), 3, cv::Scalar(255,255,255), -1);
imshow("MyVideo", frame);
...