The problem maybe is with the codec of the camera stream and not with the FPS itself, for example, if your camera only supports YUYV it is probably that you could only work with some specific FPS, try with the app guvcview to check this in a GUI.
Try to change the codec to MJPG and then change the FPS using CAP_PROP_FPS. I'm using a Logitech C922 pro and this works for me to configure 1080p and 30fps, if you have other camera probably yu need to use a lower resolution to achieve 30fps:
import cv2 as cv
def decode_fourcc(v):
v = int(v)
return "".join([chr((v >> 8 * i) & 0xFF) for i in range(4)])
def setfourccmjpg(cap):
oldfourcc = decode_fourcc(cap.get(cv.CAP_PROP_FOURCC))
codec = cv.VideoWriter_fourcc(*'MJPG')
res=cap.set(cv.CAP_PROP_FOURCC,codec)
if res:
print("codec in ",decode_fourcc(cap.get(cv.CAP_PROP_FOURCC)))
else:
print("error, codec in ",decode_fourcc(cap.get(cv.CAP_PROP_FOURCC)))
cap = cv.VideoCapture(CAMERANUM)
cu.setfourccmjpg(cap)
w=1920
h=1080
fps=30
res1=cap.set(cv.CAP_PROP_FRAME_WIDTH,w)
res2=cap.set(cv.CAP_PROP_FRAME_HEIGHT,h)
res3=cap.set(cv.CAP_PROP_FPS,fps)
then resume your normal video capture polling loop.
Answer from Francisco Carlos Calderon on Stack OverflowThe problem maybe is with the codec of the camera stream and not with the FPS itself, for example, if your camera only supports YUYV it is probably that you could only work with some specific FPS, try with the app guvcview to check this in a GUI.
Try to change the codec to MJPG and then change the FPS using CAP_PROP_FPS. I'm using a Logitech C922 pro and this works for me to configure 1080p and 30fps, if you have other camera probably yu need to use a lower resolution to achieve 30fps:
import cv2 as cv
def decode_fourcc(v):
v = int(v)
return "".join([chr((v >> 8 * i) & 0xFF) for i in range(4)])
def setfourccmjpg(cap):
oldfourcc = decode_fourcc(cap.get(cv.CAP_PROP_FOURCC))
codec = cv.VideoWriter_fourcc(*'MJPG')
res=cap.set(cv.CAP_PROP_FOURCC,codec)
if res:
print("codec in ",decode_fourcc(cap.get(cv.CAP_PROP_FOURCC)))
else:
print("error, codec in ",decode_fourcc(cap.get(cv.CAP_PROP_FOURCC)))
cap = cv.VideoCapture(CAMERANUM)
cu.setfourccmjpg(cap)
w=1920
h=1080
fps=30
res1=cap.set(cv.CAP_PROP_FRAME_WIDTH,w)
res2=cap.set(cv.CAP_PROP_FRAME_HEIGHT,h)
res3=cap.set(cv.CAP_PROP_FPS,fps)
then resume your normal video capture polling loop.
Not all openCV parameters are supported by all cameras from an opencv standpoint. Each camera has a different set of parameters that need to be set. You need to find out what parameters are supported by your camera...
Opencv-Python cv2.CV_CAP_PROP_FPS error - Stack Overflow
Opencv Camera Properties : CAP_PROP_FOURCC Not working
Python OpenCV video.get(cv2.CAP_PROP_FPS) returns 0.0 FPS - Stack Overflow
set property of cv2.VideoCapture is returning false for cv2.CAP_PROP_FPS
In OpenCV 3.2, drop the CV in front of the flag.
This should work just fine
videoCapture = cv2.VideoCapture(file_path)
fps = videoCapture.get(cv2.CAP_PROP_FPS)
size = (int(videoCapture.get(cv2.CAP_PROP_FRAME_WIDTH)),
int(videoCapture.get(cv2.CAP_PROP_FRAME_HEIGHT)))
Eshirima answer solved the problem. But just for reference i want to show you one more way of performing these operations as mentioned in docs: https://docs.opencv.org/2.4/modules/highgui/doc/reading_and_writing_images_and_video.html#videocapture-get
videoCapture = cv2.VideoCapture(file_path)
width = int(videoCapture.get(3))
height = int(videoCapture.get(4))
fps = int(videoCapture.get(5))
Performing pip install python-opencv fixed the problem and the FPS is correctly detected.
EDIT: tested with python 3.8 and indeed it is pip install opencv-python. Cannot remember two years ago what python I was using.
EDIT November 2022: please also check Perry's answer below, if you are using a newer opencv-python version
The recent versions of opencv-python will give an error called AttributeError because cv2 doesn't have any attribute named cv.
Instead use the following
import cv2
vidcap = cv2.VideoCapture('some_video.avi')
fps = vidcap.get(cv2.CAP_PROP_FPS)
print(f"{fps} frames per second")
This will give the frames per second value
Setting a frame rate doesn't always work like you expect. It depends on two things:
- What your camera is capable of outputting.
- Whether the current capture backend you're using supports changing frame rates.
So point (1). Your camera will have a list of formats which it is capable of delivering to a capture device (e.g. your computer). This might be 1920x1080 @ 30 fps or 1920x1080 @ 60 fps and it also specifies a pixel format. The vast majority of consumer cameras do not let you change their frame rates with any more granularity than that. And most capture libraries will refuse to change to a capture format that the camera isn't advertising.
Even machine vision cameras, which allow you much more control, typically only offer a selection of frame rates (e.g. 1, 2, 5, 10, 15, 25, 30, etc). If you want a non-supported frame rate at a hardware level, usually the only way to do it is to use hardware triggering.
And point (2). When you use cv.VideoCapture you're really calling a platform-specific library like DirectShow or V4L2. We call this a backend. You can specify exactly which backend is in use by using something like:
cv2.VideoCapture(0 + cv2.CAP_DSHOW)
There are lots of CAP_X's defined, but only some will apply to your platform (e.g CAP_V4L2 is for Linux only). On Windows, forcing the system to use DirectShow is a pretty good bet. However as above, if your camera only reports it can output 30fps and 60fps, requesting 10fps will be meaningless. Worse, a lot of settings simply report True in OpenCV when they're not actually implemented. You've seen that most of the time reading parameters will give you sensible results though, however if the parameter isn't implemented (e.g exposure is a common one that isn't) then you might get nonsense.
You're better off waiting for a period of time and then reading the last image.
Be careful with this strategy. Don't do this:
while capturing:
res, image = cap.read()
time.sleep(1)
you need to make sure you're continually purging the camera's frame buffer otherwise you will start to see lag in your videos. Something like the following should work:
frame_rate = 10
prev = 0
while capturing:
time_elapsed = time.time() - prev
res, image = cap.read()
if time_elapsed > 1./frame_rate:
prev = time.time()
# Do something with your image here.
process_image()
For an application like a hand detector, what works well is to have a thread capturing images and the detector running in another thread (which also controls the GUI). Your detector pulls the last image captured, runs and display the results (you may need to lock access to the image buffer while you're reading/writing it). That way your bottleneck is the detector, not the performance of the camera.
I could not set the FPS for my camera so I manage to limit the FPS based on time so that only 1 frame per second made it into the rest of my code. It is not exact, but I do not need exact, just a limiter instead of 30fps. HTH
import time
fpsLimit = 1 # throttle limit
startTime = time.time()
cv = cv2.VideoCapture(0)
While True:
frame = cv.read
nowTime = time.time()
if (int(nowTime - startTime)) > fpsLimit:
# do other cv2 stuff....
startTime = time.time() # reset time
I'm working on an application in python using opencv for use in athletic coaching. I'd like it to run at 60fps, but I can't seem to get it to that speed. I've determined that the part that is slowing everything down is the capture process; frames aren't getting from the camera to the cpu fast enough. All testing I've done so far indicates that the processing and the rendering are not the bottleneck; it's specifically the video input that is slowing everything down.
Now, I know it is possible for the camera to run at 60fps, because when I open up the same camera in guvcview (at the same resolution), I can get a full 60fps.
I don't want to share my entire project, but here's the part that manages frame capture: https://pastebin.com/nnx32rQK. My main app calls the get_frame() function in its own thread. I'm running this on an intel NUC6CAYH (celeron CPU, 2.3 ghz), running linux.
Any help would be welcome!
EDIT: I went into more detail below, but it looks like having the cap.read() within the Feed class is a whole lot slower than just accessing cap.read() directly..... and I have no idea why
For OpenCV 3.x:
cap = cv2.VideoCapture(1)
cap.set(cv2.CAP_PROP_FPS, 60)
For OpenCV 2.x:
cap = cv2.VideoCapture(1)
cap.set(cv2.cv.CV_CAP_PROP_FPS, 60)
This worked correctly with my "PS3 Eye" camera.
I don't know if that's still valid, but some time ago, something like one year and a half, I encountered that exactly problem. I contacted with a developer of OpenCV and he told me that the access and ability to change some of the properties of a capture weren't implemented yet and some other just worked for certain kinds of camera. I finally took a look to libdc1394 (working in linux) and made some functions that converted the data retrieved by libdc1394 to IplImages from OpenCV. It wasn't a such a tough task.
CV_CAP_PROP_FPS only works on videos as far as I know. If you want to capture video data from a webcam you have to time it correctly yourself. For example use a timer to capture a frame from the webcam every 40ms and then save as 25fps video.
You can use VideoCapture::set(CV_CAP_PROP_FPS) to set the desired FPS for a webcam. However, you can't use get for some reason.
Note that sometimes the driver will choose a different FPS than what you have requested depending on the limitations of the webcam.
My workaround: capture frames during a few seconds (4 is fine in my tests, with 0.5 seconds of initial delay), and estimate the fps the camera outputs.
A bit too late but searching on same topic (not specific to Vivotek Camera but more on mpeg problem with openCV) :
- Video is encoded
- OpenCV uses FFMPEG
- Encoding use key frames
- When skipping some frames encoding can't give you the exact frame you want
see similar question :
Getting individual frames using CV_CAP_PROP_POS_FRAMES in cvSetCaptureProperty
How can I get one single frame from a video file?
Problem with CV_CAP_PROP_POS_FRAMES setting next frame number
desired position key frame (this is where the cursor will stop) | | | | | > | | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||Sample code using openCV 2.4.8 / VS2013 with trackbar :
- tested with AVI format [MPEG4 Video (H264)] : setting frame position works fine
tested with MPG format [MPEG1/MPEG2] : setting frame position works fine
double currentPos = capture.get(CV_CAP_PROP_POS_FRAMES); std::cout << "CV_CAP_PROP_POS_FRAMES = " << currentPos << std::endl; // position_slider 0 - 100 double noFrame = position_slider*nbFrames / 100; // solution 1 bool success = capture.set(CV_CAP_PROP_POS_FRAMES, noFrame); // solution 2 double frameRate = capture.get(CV_CAP_PROP_FPS); double frameTime = 1000.0 * noFrame / frameRate; bool success = capture.set(CV_CAP_PROP_POS_MSEC, frameTime); if (!success) { std::cout << "Cannot set frame position from video file at " << noFrame << std::endl; return; } currentPos = capture.get(CV_CAP_PROP_POS_FRAMES); if (currentPos != noFrame) { std::cout << "Requesting frame " << noFrame << " but current position == " << currentPos << std::endl; } success = capture.read(frame_aux); if (!success) { std::cout << "Cannot get frame from video file " << std::endl; return; } imshow("test", frame_aux);
Just as BlouBlou said, when you read some high compression video format with FFMPEG, it used "key frame" technology to decode video. So set CV_CAP_PROP_POS_FRAMES property will not work as you want.
I tested 5 mpeg videos to read all frames from them. Get total frame count using long totalFrameNumber = capture.get(CV_CAP_PROP_FRAME_COUNT);
Then I read each video twice, first time not set CV_CAP_PROP_POS_FRAMES to 0, second time set it.
It did drop some frames when you set CV_CAP_PROP_POS_FRAMES to 0, about 10 frames each video. I guess because the key frame is not in the first frame of the video, so FFMPEG skip some frames to the first key frame. But some video format such as .avi won't appear such problem. I hope my real experience will save other people much time (well I spent to find this page not too long but enough).
Anyway, highly recommend not to using CV_CAP_PROP_POS_FRAMES to get a specific frame when you face mpeg format video. It is a smart choice to set CV_CAP_PROP_POS_MSEC:)