I try to capture video using Logitech C920 webcam with full hd resolution. It provides 30 fps with this resolution.
It works with windows camera application at 30 fps but whatever I try, I could not get this fps rate with opencv videoCapture.
Note: I use windows 10 and vs15.
I tried with different usb ports, opencv versions and codecs. Result is same, ~5 fps.
I measured fps ignoring first 10 frames. Here are my calculations: only read = "5.04fps" , read+imshow = "4.97fps" and read+imshow+write = "4.91fps"
void main()
{
mainStream.open(0);
mainStream.set(CV_CAP_PROP_FRAME_WIDTH, 1920);
mainStream.set(CV_CAP_PROP_FRAME_HEIGHT, 1080);
mainStream.set(CV_CAP_PROP_FPS, 30);
mainStream.set(CV_CAP_PROP_FOURCC, CV_FOURCC('M', 'J', 'P', 'G'));
mainWriter.open("outputnew2.avi", CV_FOURCC('M', 'J', 'P', 'G'), 30, cv::Size(frameW, frameH), true);
namedWindow("frame", 1);
while (true){
Mat frame;
mainStream >> frame;
imshow("frame", frame);
if (waitKey(5) == 27)
break;
mainWriter << frame;
}
mainStream.release();
mainWriter.release();
}
First of all:
The imshow method is very slow (in a pretty relative scope). Try to measure the real fps while you do not show the image and do not write the image to a file.
After that is done, you can check the real fps and determine which one of the two options (showing or writing) is slowing down your achieved fps rate.
Please post results of the achieved fps rate without showing or writing the image.
Edit:
Alright, you nearly always get 5 fps, which is kind of slow. Does the saved video (or images) match the resolution you wanted? Are they really 1920x1080
?
In that case, do the measured times differ from release and debug build?
Edit2:
If the same code works with other usb cams (and they produce more fps than the C920) my immediate suspect is the C920 itself (or its driver at least). Does it help if you deinstall the driver for it (eventually reboot) and install the newest driver again?
Another thing: Do the measured fps change if you do not request 30 but maybe like 20 fps?
Edit3:
It seems it was a driver issue (merged from comments). Reinstalling the driver is one method to adress this
Related
I'm using OpenCV4 to read from a camera. Similar to a webcam. Works great, code is somewhat like this:
cv::VideoCapture cap(0);
cap.set(cv::CAP_PROP_FRAME_WIDTH , 1600);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, 1200);
while (true)
{
cv::Mat mat;
// wait for some external event here so I know it is time to take a picture...
cap >> mat;
process_image(mat);
}
Problem is, this gives many video frames, not a single image. This is important because in my case I don't want nor need to be processing 30 FPS. I actually have specific physical events that trigger reading the image from the camera at certain times. Because OpenCV is expecting the caller to want video -- not surprising considering the class is called cv::VideoCapture -- it has buffered many seconds of frames.
What I see in the image is always from several seconds ago.
So my questions:
Is there a way to flush the OpenCV buffer?
Or to tell OpenCV to discard the input until I tell it to take another image?
Or to get the most recent image instead of the oldest one?
The other option I'm thinking of investigating is using V4L2 directly instead of OpenCV. Will that let me take individual pictures or only stream video like OpenCV?
I'm reading a video file, and it's slower than the actual FPS of the file (59 FPS #1080p) even if i'm not doing any processing to the image:
using namespace cv;
using namespace std;
// Global variables
UMat frame; //current frame
int main(int argc, char** argv)
{
VideoCapture capture("myFile.MP4");
namedWindow("Frame");
capture.set(CAP_PROP_FPS, 120); //not changing anything
cout>>capture.get(CAP_PROP_FPS);
while (charCheckForEscKey != 27) {
capture >>frame;
if (frame.empty())
break;
imshow("Frame", frame);
}
}
Even if I tried to set CAP_PROP_FPS to 120 it doesn't change the fps of the file and when I get(CAP_PROP_FPS) I still get 59.9...
When I read the video the actual outcome is more or less 54 FPS (even using UMat).
Is there a way to read the file at a higher FPS rate ?
I asked he question on the opencv Q&A website as well :http://answers.opencv.org/question/117482/change-fps-on-video-capture-from-file/
Is it just because my computer is too slow ?
TL;DR FPS is irrelevant to the problem, probably a performance issue
What FPS is used for? Before you can display a single frame of video, you have to read the data (from an HDD, DVD, Network, Internet or whatever) and decode it. Both of these operations take time, the amount of which differs from system to system, depending on the speed of HDD/Internet, processor speed etc. If we just display each frame as soon as it's ready, the resulting movie speed will, therefore, vary from system to system. That is usually not what we want, so along with the sequence of video frames we get the "frames per second" value (a. k. a. FPS), which tells us how soon we shall display each consecutive frame (once every 1/30-th of a second for 30 FPS, once every 1/60-th of a second for 60 FPS, etc.) If the frame is ready to be displayed but it's too early, we can wait till its time comes. If it's time to display a frame but it's not ready (on an underpowered/too busy system), there's not much we can do (maybe drop frames in some situations). To see the effect for yourself, try changing the FPS value for x2, saving the file and display it with VLC: for the same amount of data and same number of frame, you will notice that the speed of your video has doubled and the time - halved. Try writing each frame twice for your x2 FPS - you will see that the playback speed is back to normal (with double the number of frames and meaningless increase of the file size).
What FPS is not used for? When processing (not displaying) a video, we are not limited by the original FPS, and the processing goes as fast as it can. If your PC can process 1000 frames per second - good, if 1500 - even better. Needless to say, changing the FPS value in the file won't improve your CPU/HDD speed, so if you were only able to process 54 frames per second, you are still going to be able to only process 54 frames per second.
But how can VLC display faster? Assuming you didn't forget to switch from Debug to Release build before measuring time, there are still a number of possibilities: VLC is probably better optimized for the particular task of video playback (OpenCV is not really that fast at some tasks, plus it has to convert each frame to a more general Mat/UMat structure), multithreading (including "double buffering", as mentioned in the comments) is another possible reason, maybe caching as well (e. g. reading a block of data containing many frames from the HDD at once instead of reading and processing frames one by one).
I get the fps from video files using opencv.
It works well for all videos that I have, except those videos recorded by my phone (samsung note). I am getting fps=90000 by calling VideoCapture::get(CV_CAP_PROP_FPS) for. I verified the properties of video files taken by phone, they seem that no problem with recorded files (fps = 30), but when I get fps by opencv its erratic value!
Does any get this problem? any suggestion?
EDIT:
VideoCapture input_video("20.mp4"); // here I read a file, recorded by cameraphone
double fps=input_video.get(CV_CAP_PROP_FPS);
cout<<fps<<endl; // prints 90000 !!!!!
// continue without problem
I want to get framerate for video but I always get -nan on linux.
VideoCapture video(input);
if (!video.isOpened()) // zakoncz program w przypadku, problemu z otwarciem
{
exit(0);
}
double fps = video.get(CV_CAP_PROP_FPS);
My openCv version is 2.4.7. The same code works fine on windows.
My guess is that it's camera dependent. Some (API) functions are sometimes not implemented in OpenCV and/or supported by your camera. Best would be if you check the code on github.
Concerning your problem: I am able to get the frame rates with a normal webcam and a XIMEA camera with your code.
Tested on:
Ubuntu 15.04 64bit
OpenCV 3.0.0 compiled with Qt and XIMEA camera support
You could measure your frame rate yourself:
double t1 = (double)cv::getTickCount();
// do something
t1 = ((double)cv::getTickCount() - t1)/cv::getTickFrequency();
Gives you the time that //do something spent.
It is from a file, you can try to estimate it yourself.
VideoCapture video("name_of_video.format");
int frameCount = (int)video.get(CV_CAP_PROP_FRAME_COUNT) ;
//some times frame count is wrong, so you can verify
video.set(CV_CAP_PROP_POS_FRAMES , frameCount-1);
//try to read the last frame, if not decrement frame count
while(!(video.read(nextFrame))){
frameCount--;
video.set(CV_CAP_PROP_POS_FRAMES , frameCount-1);
}
//it is already set above, but just for clarity
video.set(CV_CAP_PROP_POS_FRAMES , frameCount-1);
double fps = (double)(1000*frameCount)/( video.get(CV_CAP_PROP_POS_MSEC));
cout << "fps: " << fps << endl;
This is how I get framerate when using CV_CAP_PROP_FPS fails
The question doesn't clarify if this refers to video from a live source (webcam) or from a video file.
If the latter, the capabilities of OpenCV will depend on the format and codecs used in the file. For some file formats, expect to get a 0 or NaN.
If the former, the real fps of the source may not be returned, especially if the requested framerate is not supported by the hardware, and a different one is used instead. For this case I would suggest an approach similar to #holzkohlengrill's, but only do that calculation after an initial delay of say 300ms (YMMV), as grabbing of the first frames and some initialisations happening can mess with that calculation.
Here is the situation :
we have managed to get the camera to work with OpenCv 2.4.0 and Qt 5.0.2.
The camera is supposed to be able to record 1080p videos at 30 fps.
However we are stuck at 10 fps when recording in 1920x1080.
Here is the code we are using :
Capture cv::VideoCapture;
Capture.open(0);
Capture.set(CV_CAP_PROP_FRAME_WIDTH, 1920):
Capture.set(CV_CAP_PROP_FRAME_HEIGHT, 1080);
We have already tried to use this command (that we got from Capturing 1080p at 30fps from logitech c920 with openCV 2.4.3):
Capture.set(CV_CAP_PROP_FOURCC, 'M', 'J', 'P', 'G');
but without any success.
We believe the camera's stream can be captured in h264 (thanks to the internal conversion the camera does) or in mjpg.
Like we said we are a bit confused/lost.
Any suggestion is welcomed !
Thanks
The solution for your problem is already mentioned in the other question you linked to: You have to set the codec before you set the wanted resolution:
Capture cv::VideoCapture;
Capture.open(0);
Capture.set(CV_CAP_PROP_FOURCC, CV_FOURCC('M','J','P','G'))
Capture.set(CV_CAP_PROP_FRAME_WIDTH, 1920):
Capture.set(CV_CAP_PROP_FRAME_HEIGHT, 1080);