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
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
python - Understanding the function CAP_PROP_FPS in cv2 - Stack Overflow
VideoCapture.get(cv::CAP_PROP_FPS) is wrong for some special video
Windows get camera cv2.CAP_PROP_FPS incorrect value for low fps.
set property of cv2.VideoCapture is returning false for cv2.CAP_PROP_FPS
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.
The get() for CAP_PROP_FRAME_COUNT is never supposed to be accurate! If you check the opencv source code. You can find this:
int64_t CvCapture_FFMPEG::get_total_frames() const
{
int64_t nbf = ic->streams[video_stream]->nb_frames;
if (nbf == 0)
{
nbf = (int64_t)floor(get_duration_sec() * get_fps() + 0.5);
}
return nbf;
}
This means it will first look into the stream header for nb_frames, which you can check with ffprobe. If there is no such field, then there is no better way to get frame number than directly decoding the video. The opencv did a rough estimation by get_duration_sec() * get_fps() + 0.5 which surely not mean for accuracy.
Thus, to obtain the correct frame number you have to decode and read through the entire stream, or you have to ask the video generator to generate correct stream header with nb_frames field.
It is unfortunately to see after almost 10 years opencv still does not correct the implementation: we should use av_read_frame(fmt_ctx, &pkt) to read and parse all packet without actual decode them.
I personally stopped relies on opencv for video decoding more than 10 years ago, but recently I have to collaborate with some project using opencv to do so. I have to call ffprobe in a subprocess to get the correct frame counts:
ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 input.mp4
CV_CAP_PROP_FRAME_COUNT gives the property of 'number of frames', that comes from the video header. The other number is basically "How many frames can I read from this video file?".
If the video contains frames that cannot be read/decoded (e.g., due to being corrupted), OpenCV skips those frames (after trying to read them) and gives you the next valid frame. So the difference between your two numbers is the number of frames that couldn't be read.
Also, if your video header is corrupted and/or cannot be parsed by the underlying codecs that OpenCV uses, then those numbers can be different too.
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))
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.
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...
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