Using video filter results in ZeroDivisionError
faxm0dem opened this issue · 5 comments
Using the video
filter with the following config item:
- "empty": [["video", "tumbleweed.gif", 5]]
I get the following error trace :
Loading video: tumbleweed.gif
[ERROR:0] global /tmp/scratch/3942/pip-install-5mr76rqs/opencv-python_bb4cd8da7f5644bc83c7d0718e3f53ca/opencv/modules/videoio/src/cap.cpp (140) open VIDEOIO(CV_IMAGES): raised OpenCV exception:
OpenCV(4.4.0) /tmp/scratch/3942/pip-install-5mr76rqs/opencv-python_bb4cd8da7f5644bc83c7d0718e3f53ca/opencv/modules/videoio/src/cap_images.cpp:253: error: (-5:Bad argument) CAP_IMAGES: can't find starting number (in the name of file): tumbleweed.gif in function 'icvExtractPattern'
Traceback (most recent call last):
File "/home/me/git/virtual_webcam_background/./virtual_webcam.py", line 154, in <module>
layers = reload_layers(config)
File "/home/me/git/virtual_webcam_background/./virtual_webcam.py", line 60, in reload_layers
layers.append((layer_type, filters.get_filters(config, layer_filters)))
File "/home/me/git/virtual_webcam_background/filters/__init__.py", line 39, in get_filters
image_filters.append(image_filter_class(config=config,
File "/home/me/git/virtual_webcam_background/filters/video.py", line 69, in __init__
self.reload_video()
File "/home/me/git/virtual_webcam_background/filters/video.py", line 81, in reload_video
self.image = next(self.generator)
File "/home/me/git/virtual_webcam_background/filters/video.py", line 28, in lazy_load_video
every_nth_frame = np.ceil(fps / target_fps)
ZeroDivisionError: division by zero
I am not sure how opencv calculates the FPS of a GIF, but it seems that it return 0
.
The relevant code is
if target_fps <= 0 or target_fps > fps:
target_fps = fps
every_nth_frame = np.ceil(fps / target_fps) # division by zero happens here
so it must have target_fps > fps
(so target_fps=5
is changed to fps
) and fps=0
(because of the division by zero error)
Can you try:
if fps <= 0:
fps = 1
if target_fps <= 0 or target_fps > fps:
target_fps = fps
every_nth_frame = np.ceil(fps / target_fps) # division by zero happens here
It would also be interesting, if you could add a print(fps)
before the block and tell me what fps opencv calculcates. I wonder if it uses 0
for "No FPS given in the file".
I checked and it does calculate 0.
I tried using the gif and also a conversion to mp4 (using ffmpeg defaults).
Also, I forced the fps to 1 as requested, and it get:
Loading video: tumbleweed.mp4
============================================
Found a frame rate of 0
============================================
Finished loading video: tumbleweed.mp4
Error loading video (format not supported by OpenCV?): tumbleweed.mp4
Loading video: tumbleweed.mp4
============================================
Found a frame rate of 0
============================================
Finished loading video: tumbleweed.mp4
Error loading video (format not supported by OpenCV?): tumbleweed.mp4
I guess I'm only having a format issue here. Maybe some missing explicit requirement ?
The gif should most likely work once the frame rate issue is resolved. For mp4 it depends on which video codec ffmpeg is using and if opencv can read it.
The error is returned when the filter cannot read the first frame of a video. When I see it correctly, you may get problems when your frame rate is larger than the number of images in the video.
For fps=5
frame_no += 1
if (frame_no % every_nth_frame) != 0:
continue
skips the first 4 frames. When the video has less frames, the loop ends and the generator is finished without returning a frame at all. reload_video
reads the first frame returned by the generator when opening the video and generates the error when the generator does not return at least one frame.
You could test with fps=1
if the video formats are supported, then every_nth_frame
should be 1 and the generator returns at least the first frame of the video, if the video can be read by OpenCV.
Whatever video file I choose, I get the same error. I'm guessing we're chasing a red herring here
I don't have the time to write a minimum example right now, but you could look at lazy_load_video
and try to extract the minimum code for testing. You need to create a VideoCapture
object and then test .isOpened()
and .read()
.
When every file fails, I could imagine wrong paths (relative to the wrong directory?). I am not sure if you wouldn't get some "file not found" exception, though.