Unable to get OpenCV 3.1 FPS over ~15 FPS - python

I have some extremely simple performance testing code below for measuring the FPS of my webcam with OpenCV 3.1 + Python3 on a Late 2011 Macbook Pro:
cap = cv2.VideoCapture(0)
count = 0
start_time = time.perf_counter()
end_time = time.perf_counter()
while (start_time + 1) > end_time:
count += 1
cap.read()
# Attempt to force camera FPS to be higher
cap.set(cv2.CAP_PROP_FPS, 30)
end_time = time.perf_counter()
print("Got count", count)
Doing no processing, not even displaying the image or doing this in another thread, I am only getting around 15 FPS.
Trying to access the FPS of the camera with cap.get(cv2.CAP_PROP_FPS) I get 0.0.
Any ideas why?
I've already searched the internet a fair amount for answers, so things I've thought about:
I build OpenCV with release flags, so it shouldn't be doing extra debugging logic
Tried manually setting the FPS each frame (see above)
My FPS with other apps (e.g. Camera toy in Chrome) is 30FPS
There is no work being done in the app on the main thread, so putting the video capture logic in another thread as most other posts suggest shouldn't make a difference
** EDIT **
Additional details: it seems like the first frame I capture is quick, then subsequent frames are slower; seems like this could be a buffer issues (i.e. the camera is being paused after the first frame because a new buffer must be allocated to write to?)
Tweaked the code to calculate the average FPS so far after each read:
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_CONVERT_RGB, False)
cap.set(cv2.CAP_PROP_FPS, 30)
start_time = time.perf_counter()
count = 0
cv2.CAP_PROP_FPS
end_time = time.perf_counter()
while True:
count += 1
ret, frame = cap.read()
end_time = time.perf_counter()
print("Reached FPS of: ", count / (end_time - start_time))
And I get one frame around 30FPS, and then subsequent frames are slower:
Reached FPS of: 27.805818385257446
Reached FPS of: 19.736237223924398
Reached FPS of: 18.173748156583795
Reached FPS of: 17.214809956810114
Reached FPS of: 16.94737657138959
Reached FPS of: 16.73624509452099
Reached FPS of: 16.33156408530572
** EDIT **
Still no luck as of 10/20. My best bet is there are some issues with memory transfer since the camera itself can definitively capture at 30 FPS based on the ability of other apps.

IT'S NOT ANSWER. Since the comment in original question is too long for your attention. I post outside instead.
First, it's normal when CV_CAP_PROP_FPS return 0. OpenCV for Python just a wrapper for OpenCV C++. As far as I know, this property only works for video file, not camera. You have to calculate FPS yourself (like your edited).
Second, OpenCV have a bug that always convert the image get from camera to RGB https://github.com/opencv/opencv/issues/4831. Normal camera usually use YUYV color. It's take a lot of time. You can check all supported resolution + fps https://trac.ffmpeg.org/wiki/Capture/Webcam. I see some camera not support RGB color and OpenCV force to get RGB and take terrible FPS. Due to camera limitation, in the same codec, the higher resolution, the slower fps. In different supported codec, the bigger output in same resolution, the slower fps. For example, my camera support yuyv and mjpeg, in HD resolution, YUYV have max 10 fps while MJPEG have max 30 fps.
So, first you can try ffmpeg executable to get frames. After identifying where error come from, if ffmpeg works well, you can use ffmpeg library (not ffmpeg executable) to get frame from your camera (OpenCV using ffmpeg for most video I/O including camera).
Be aware that the I only work with ffmpeg and OpenCV in C++ language, not Python. Using ffmpeg library is another long story.
Good luck!

Related

OpenCV frame rate when reading video different than what used for capture

I am using OpenCV to capture videos with a number of different cameras (OpenCV 4.5.1.48 on Ubuntu 18.04). For all the cameras I set the capturing frame rate to 30fps, but I noticed when reading the fps of the recorded video through
import cv2
cap = cv2.VideoCapture(input_video_path)
fps = cap.get(cv2.CAP_PROP_FPS)
print(fps)
that the values are never exactly 30 fps, but rather
30.00030000300003
30.000299988570422
29.997772583098968
...
and so on. Is this behaviour expected? When I right click on the videos and look at the video properties, it always says 30 fps.
The videos I am recording are around 10 minutes, but if I cut a smaller section of the video (e.g. 30 seconds) than the departure from 30 fps is even greater and OpenCV would read even 29 fps instead of 30.
Would there be any real downsize from rounding the detected frame rate to an integer when processing the video? In the specific I am looking to record an output video at 10 fps taking one every three frames of the original video, so I'm wondering if setting the frame rate of the video writer to 10 fps is correct or if I should be using one third of the fps read by OpenCV.

How to change frame rate FPS of an existing video using openCV python

I am trying to change the Frame rate i.e., FPS of an existing video using openCV library in python. Below is the code that I am trying to execute. Even after setting the FPS property using cv2.CAP_PROP_FPS the video is not playing faster in the cv2.imshow() method. Even After setting the FPS property the getter returns the older FPS value. So how do I set the FPS value higher and make the video play faster?
Used version:
python = 3.7.4 and
opencv-python - 4.1.0.25
import cv2
video = cv2.VideoCapture("yourVideoPath.mp4");
video.set(cv2.CAP_PROP_FPS, int(60))
if __name__ == '__main__':
print("Frame rate : {0}".format(video.get(cv2.CAP_PROP_FPS)))
while video.isOpened():
ret1, frame2 = video.read()
cv2.imshow("Changed", frame2)
if cv2.waitKey(10) & 0xFF == ord('q'): # press q to quit
break
video.release()
cv2.destroyAllWindows()
If you're only trying to play the video in the displayed window, the limiting factor is not the fps of the video but the time spent waiting with the code waitKey(10) which makes the program wait for 10ms between each frame.
The read() method of the VideoCapture class simply returns the next frame with no concept of waiting or frame rate. The only thing preventing this code running as fast as it can is the waitKey(10) section, which is thus the main factor determining speed. To change the frame rate as seen through the imshow() method, you'd need to edit the time spent waiting. This is likely the dominant factor, but not the only one as the reading of a frame does take time.
If you're actually trying to change the playback rate of an existing file and have that saved to that file, I am unsure if OpenCV actually supports this, and I imagine it would be dependent on what back end you're using - OpenCV implements the VideoCapture class using different 3rd party backends.. As per the documentation of VideoCapture.set() I'd investigate the return value of video.set(cv2.CAP_PROP_FPS, int(60)) as the documentation suggests it will return true if this has changed something.
As an alternative you could investigate using something like FFMPEG which supports this relatively easily. If you want to stick with OpenCV I know from personal experience you can do this with the VideoWriter class. In this method you would read in the video frame by frame using the VideoCapture class, and then save it at the desired frame rate with VideoWriter. I suspect FFMPEG will likely meet your needs however!

How to run specific code after n seconds on a video

I am working on python3 and using Microsoft azure face API function 'CF.face.detect' to detect faces in a video.
I want to detect faces after every 1 second in the video that means run CF.face.detect once/second on video frame.
Please tell how to do it
Thanks in advance
If you know how many fps your video has, you could read the frames one by one and detect on every n-th frame, n being the number of fps of a video you're processing.
fps = x
cnt = 0
for f in get_frames():
if cnt % fps == 0:
# run algorithm here
cv.imwrite(f)
After you have gone through the video then you can run the algorithm. But I would suggest to run the algorithm in the loop and save the frame then, preferably with drawn result (squares for detection)

High FPS livestream over ethernet using Python

I plan on building a ROV and I am working on my video feed atm. I will be using fiber optics for all communications and I am tinkering with opencv to stream a webcam feed with python. I might choose to use IP cameras but I wanted to learn more about how to capture frames from a webcam in python first. Since I didn't know what I was going to use in the end I bought a cheap-as-they-get noname USB webcam just to try and get everything working. This camera feed is going to be used for navigation, a seperate video recorder will probably be used for recording video.
Enough about that, now to my issue. I am getting only 8 FPS when I am capturing the frames but I suspect that is due to the cheap webcam. The webcam is connected to a pcduino 3 nano which is connected to a arduino for controlling thrusters and reading sensors. I never thought of how to utilize hardware in encoding and decoding images, I don't know enough about that part yet to tell if I can utilize any of the hardware.
Do you guys believe it's my web cam that is the bottleneck? Is it a better idea to use a IP camera or should I be able to get a decent FPS using a webcam connected to a pcduino 3 nano capturing frames with opencv or perhaps some other way? I tried capturing frames with Pygame which gave me the same result, I also tried mjpg-streamer.
Im programming in Python, this is the test I made:
import cv2, time
FPS = 0
cap = cv2.VideoCapture(0)
last = time.time()
for i in range(0,100):
before = time.time()
rval, frame = cap.read()
now = time.time()
print("cap.read() took: " + str(now - before))
if(now - last >= 1):
print(FPS)
last = now
FPS = 0
else:
FPS += 1
cap.release()
And the result is in the line of:
cap.read() took: 0.118262052536
cap.read() took: 0.118585824966
cap.read() took: 0.121902942657
cap.read() took: 0.116680860519
cap.read() took: 0.119271993637
cap.read() took: 0.117949008942
cap.read() took: 0.119143009186
cap.read() took: 0.122378110886
cap.read() took: 0.116139888763
8
The webcam should explicitly state its frame rate in its specifications, and that will definitively tell you whether the bottleneck is the camera.
However, I would guess that the bottleneck is the pcDuino3. Most likely it can't decode the video very fast and that causes the low frame rate. You can try this exact code on an actual computer to verify this. Also, I believe OpenCV and mjpg-streamer both use libjpeg to decode the jpeg frames, so their similar frame rate is not surprising.

How to set framerate with OpenCV camera capture

How can I set the capture framerate, using OpenCV in Python? Here's my code, but the resulting framerate is less than the requested 30fps. Also, quality of video very bad.
import cv
cv.NamedWindow ('CamShiftDemo', 1)
device = -1
cap = cv.CaptureFromCAM(device)
size = (640,480)
cv.SetCaptureProperty(cap, cv.CV_CAP_PROP_FPS,30)
cv.SetCaptureProperty(cap, cv.CV_CAP_PROP_FRAME_WIDTH, size[0])
cv.SetCaptureProperty(cap, cv.CV_CAP_PROP_FRAME_HEIGHT, size[1])
while True:
frame = cv.QueryFrame(cap)
cv.ShowImage('CamShiftDemo', frame)
cv.WaitKey(10)
You are limited by the hardware, namely:
your camera's capture capabilities, and
your computer's system resources.
If either of these cannot handle the requested capture parameters (in your case 640x480 resolution at 30fps), you're out of luck. Parameters you give to OpenCV are merely suggestions -- it tries to match them as best it can.
What model camera are you using? I would first look at the model specs to see if they advertise the parameters you desire.

Categories

Resources