英文:
Float division by zero in clip duration
问题
以下是您要翻译的内容:
"When using the main function for all the videos in a directory, this error 'division by zero' happens, but for just for a video file it doesn't happen, I used fmod
function instead of /
, but it has the math domain error, Could you please tell me how I can fix it?
! pip install python-opencv moviepy
from google.colab import drive
root = '/content/gdrive/'
drive.mount(root)
from datetime import timedelta
import cv2
import numpy as np
import os
# i.e if video of duration 30 seconds, saves 10 frame per second = 300 frames saved in total
SAVING_FRAMES_PER_SECOND = 10
def format_timedelta(td):
"""Utility function to format timedelta objects in a cool way (e.g 00:00:20.05)
omitting microseconds and retaining milliseconds"""
result = str(td)
try:
result, ms = result.split(".")
except ValueError:
return (result + ".00").replace(":", "-")
ms = int(ms)
ms = round(ms / 1e4)
return f"{result}.{ms:02}".replace(":", "-")
def get_saving_frames_durations(cap, saving_fps):
"""A function that returns the list of durations where to save the frames"""
s = []
# get the clip duration by dividing number of frames by the number of frames per second
clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS)
# use np.arange() to make floating-point steps
for i in np.arange(0, clip_duration, 1 / saving_fps):
s.append(i)
return s
def main(video_file):
filename, _ = os.path.splitext(video_file)
filename += "-opencv"
# make a folder by the name of the video file
if not os.path.isdir(filename):
os.mkdir(filename)
# read the video file
cap = cv2.VideoCapture(video_file)
# get the FPS of the video
fps = cap.get(cv2.CAP_PROP_FPS)
# if the SAVING_FRAMES_PER_SECOND is above video FPS, then set it to FPS (as maximum)
saving_frames_per_second = min(fps, SAVING_FRAMES_PER_SECOND)
# get the list of duration spots to save
saving_frames_durations = get_saving_frames_durations(cap, saving_frames_per_second)
# start the loop
count = 0
while True:
is_read, frame = cap.read()
if not is_read:
# break out of the loop if there are no frames to read
break
# get the duration by dividing the frame count by the FPS
frame_duration = count / fps
try:
# get the earliest duration to save
closest_duration = saving_frames_durations[0]
except IndexError:
# the list is empty, all duration frames were saved
break
if frame_duration >= closest_duration:
# if closest duration is less than or equals the frame duration,
# then save the frame
frame_duration_formatted = format_timedelta(timedelta(seconds=frame_duration))
cv2.imwrite(os.path.join(filename, f"frame{frame_duration_formatted}.jpg"), frame)
# drop the duration spot from the list, since this duration spot is already saved
try:
saving_frames_durations.pop(0)
except IndexError:
pass
# increment the frame count
count += 1
import os
for filename in os.listdir('/content/gdrive/MyDrive/x/train_videos/Red'):
if __name__ == "__main__":
a = main(filename)
英文:
When using the main function for all the videos in a directory, this error 'division by zero' happens, but for just for a video file it doesn't happen, I used fmod
function instead of /
, but it has the math domain error, Could you please tell me how I can fix it?
! pip install python-opencv moviepy
from google.colab import drive
root = '/content/gdrive/'
drive.mount( root )
from datetime import timedelta
import cv2
import numpy as np
import os
# i.e if video of duration 30 seconds, saves 10 frame per second = 300 frames saved in total
SAVING_FRAMES_PER_SECOND = 10
def format_timedelta(td):
"""Utility function to format timedelta objects in a cool way (e.g 00:00:20.05)
omitting microseconds and retaining milliseconds"""
result = str(td)
try:
result, ms = result.split(".")
except ValueError:
return (result + ".00").replace(":", "-")
ms = int(ms)
ms = round(ms / 1e4)
return f"{result}.{ms:02}".replace(":", "-")
def get_saving_frames_durations(cap, saving_fps):
"""A function that returns the list of durations where to save the frames"""
s = []
# get the clip duration by dividing number of frames by the number of frames per second
clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS)
# use np.arange() to make floating-point steps
for i in np.arange(0, clip_duration, 1 / saving_fps):
s.append(i)
return s
def main(video_file):
filename, _ = os.path.splitext(video_file)
filename += "-opencv"
# make a folder by the name of the video file
if not os.path.isdir(filename):
os.mkdir(filename)
# read the video file
cap = cv2.VideoCapture(video_file)
# get the FPS of the video
fps = cap.get(cv2.CAP_PROP_FPS)
# if the SAVING_FRAMES_PER_SECOND is above video FPS, then set it to FPS (as maximum)
saving_frames_per_second = min(fps, SAVING_FRAMES_PER_SECOND)
# get the list of duration spots to save
saving_frames_durations = get_saving_frames_durations(cap, saving_frames_per_second)
#start the loop
count = 0
while True:
is_read, frame = cap.read()
if not is_read:
# break out of the loop if there are no frames to read
break
# get the duration by dividing the frame count by the FPS
frame_duration = count / fps
try:
# get the earliest duration to save
closest_duration = saving_frames_durations[0]
except IndexError:
# the list is empty, all duration frames were saved
break
if frame_duration >= closest_duration:
# if closest duration is less than or equals the frame duration,
# then save the frame
frame_duration_formatted = format_timedelta(timedelta(seconds=frame_duration))
cv2.imwrite(os.path.join(filename, f"frame{frame_duration_formatted}.jpg"), frame)
# drop the duration spot from the list, since this duration spot is already saved
try:
saving_frames_durations.pop(0)
except IndexError:
pass
# increment the frame count
count += 1
import os
for filename in os.listdir('/content/gdrive/MyDrive/x/train_videos/Red'):
if __name__ == "__main__":
a=main(filename)
答案1
得分: 1
以下是您要翻译的内容:
"The issue looks like paths related.
When using for filename in os.listdir('/content/gdrive/MyDrive/x/train_videos/Red'):
The filename
excludes the directory name.
Instead of getting filename
:
/content/gdrive/MyDrive/x/train_videos/Red/vid1.mp4
/content/gdrive/MyDrive/x/train_videos/Red/vid2.mp4
/content/gdrive/MyDrive/x/train_videos/Red/vid3.mp4
...
We are getting filename
:
vid1.mp4
vid2.mp4
vid3.mp4
...
cap = cv2.VideoCapture(video_file)
tries to read the file from the default working directory (not sure where it is in Google Colab).
The video file doesn't exist in the default working directory.
We are getting zero framerate, and division by zero
exception when executing:
clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS)
.
Note that cap.get(cv2.CAP_PROP_FPS)
returns 0
if the file doesn't exist, or not a valid video file.
I recommend you to use the debugger for making sure that this is the case...
First, we may add protections form "division by zero" in get_saving_frames_durations
method:
def get_saving_frames_durations(cap, saving_fps):
"""A function that returns the list of durations where to save the frames"""
s = []
# get the clip duration by dividing number of frames by the number of frames per second
#clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS)
cap_fps = cap.get(cv2.CAP_PROP_FPS)
if cap_fps == 0:
cap_fps = 1 # Protection form "division by zero"
clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap_fps
if saving_fps == 0:
saving_period = 1 # Protection form "division by zero"
else:
saving_period = 1 / saving_fps
# use np.arange() to make floating-point steps
for i in np.arange(0, clip_duration, saving_period):
s.append(i)
return s
Second, we may skip the file when it's not a valid video file by checking cap.isOpened()
:
if not cap.isOpened():
return
Third, we may pass the "working directory" that contains the files to main
method, and use os.path.join(working_dir, filename)
where appropriate.
Updated code sample (without using Google Colab):
#from google.colab import drive
root = '/content/gdrive/'
#drive.mount( root )
from datetime import timedelta
import cv2
import numpy as np
import os
# i.e if video of duration 30 seconds, saves 10 frame per second = 300 frames saved in total
SAVING_FRAMES_PER_SECOND = 10
def format_timedelta(td):
"""Utility function to format timedelta objects in a cool way (e.g 00:00:20.05)
omitting microseconds and retaining milliseconds"""
result = str(td)
try:
result, ms = result.split(".")
except ValueError:
return (result + ".00").replace(":", "-")
ms = int(ms)
ms = round(ms / 1e4)
return f"{result}.{ms:02}".replace(":", "-")
def get_saving_frames_durations(cap, saving_fps):
"""A function that returns the list of durations where to save the frames"""
s = []
# get the clip duration by dividing number of frames by the number of frames per second
#clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS)
cap_fps = cap.get(cv2.CAP_PROP_FPS)
if cap_fps == 0:
cap_fps = 1 # Protection form "division by zero"
clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap_fps
if saving_fps == 0:
saving_period = 1 # Protection form "division by zero"
else:
saving_period = 1 / saving_fps
# use np.arange() to make floating-point steps
for i in np.arange(0, clip_duration, saving_period):
s.append(i)
return s
def main(working_dir, video_file):
filename, _ = os.path.splitext(video_file)
filename += "-opencv"
# read the video file
full_video_file = os.path.join(working_dir, video_file) # Join the working directory and the file name
cap = cv2.VideoCapture(full_video_file) #cap = cv2.VideoCapture(video_file)
if not cap.isOpened():
return # Skip the file if it's not a video file.
out_dir = os.path.join(working_dir, filename)
# make a folder by the name of the video file
if not os.path.isdir(out_dir): #if not os.path.isdir(filename):
os.mkdir(out_dir) #os.mkdir(filename)
# get the FPS of the video
fps = cap.get(cv2.CAP_PROP_FPS)
# if the SAVING_FRAMES_PER_SECOND is above video FPS, then set it to FPS (as maximum)
saving_frames_per_second = min(fps, SAVING_FRAMES_PER_SECOND)
# get the list of duration spots to save
saving_frames_durations = get_saving_frames_durations(cap, saving_frames_per_second)
#start the loop
count = 0
while True:
is_read, frame = cap.read()
if not is_read:
# break out of the loop if there are no frames to read
break
# get the duration by dividing the frame count by the FPS
frame_duration = count / fps
try:
# get the earliest duration to save
closest_duration = saving_frames_durations[0]
except IndexError:
# the list is empty, all duration frames were saved
break
if frame_duration >= closest_duration:
# if closest duration is less than or equals the frame duration,
# then save the frame
frame_duration_formatted = format_timedelta(timedelta(seconds=frame_duration))
cv2.imwrite(os.path.join(out_dir, f"frame{frame_duration_formatted}.jpg"), frame) #cv2.imwrite(os.path.join(filename, f"frame{frame_duration_formatted}.jpg"), frame)
# drop the duration spot from the list, since this duration spot is already saved
try:
saving_frames_durations.pop(0)
except IndexError:
pass
# increment the frame count
count += 1
import os
working_directory = '/content/gdrive/MyDrive/x/train_videos/Red' # Assume the output directory is the same as the input directory (name it "working directory")
for filename in os.listdir(working_directory):
if __name__ == "__main__":
a = main
<details>
<summary>英文:</summary>
The issue looks like paths related.
When using `for filename in os.listdir('/content/gdrive/MyDrive/x/train_videos/Red'):`
The `filename` excludes the directory name.
Instead of getting `filename`:
`/content/gdrive/MyDrive/x/train_videos/Red/vid1.mp4`
`/content/gdrive/MyDrive/x/train_videos/Red/vid2.mp4`
`/content/gdrive/MyDrive/x/train_videos/Red/vid3.mp4`
...
We are getting `filename`:
`vid1.mp4`
`vid2.mp4`
`vid3.mp4`
...
---
`cap = cv2.VideoCapture(video_file)` tries to read the file from the default working directory (not sure where it is in Google Colab).
The video file doesn't exist in the default working directory.
We are getting zero framerate, and `division by zero` exception when executing:
`clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS)`.
Note that `cap.get(cv2.CAP_PROP_FPS)` returns `0` if the file doesn't exist, or not a valid video file.
I recommend you to use the debugger for making sure that this is the case...
---
First, we may add protections form "division by zero" in `get_saving_frames_durations` method:
def get_saving_frames_durations(cap, saving_fps):
"""A function that returns the list of durations where to save the frames"""
s = []
# get the clip duration by dividing number of frames by the number of frames per second
#clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS)
cap_fps = cap.get(cv2.CAP_PROP_FPS)
if cap_fps == 0:
cap_fps = 1 # Protection form "division by zero"
clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap_fps
if saving_fps == 0:
saving_period = 1 # Protection form "division by zero"
else:
saving_period = 1 / saving_fps
# use np.arange() to make floating-point steps
for i in np.arange(0, clip_duration, saving_period):
s.append(i)
return s
---
Second, we may skip the file when it's not a valid video file by checking `cap.isOpened()`:
if not cap.isOpened():
return
---
Third, we may pass the "working directory" that contains the files to `main` method, and use `os.path.join(working_dir, filename)` where appropriate.
---
Updated code sample (without using Google Colab):
#from google.colab import drive
root = '/content/gdrive/'
#drive.mount( root )
from datetime import timedelta
import cv2
import numpy as np
import os
# i.e if video of duration 30 seconds, saves 10 frame per second = 300 frames saved in total
SAVING_FRAMES_PER_SECOND = 10
def format_timedelta(td):
"""Utility function to format timedelta objects in a cool way (e.g 00:00:20.05)
omitting microseconds and retaining milliseconds"""
result = str(td)
try:
result, ms = result.split(".")
except ValueError:
return (result + ".00").replace(":", "-")
ms = int(ms)
ms = round(ms / 1e4)
return f"{result}.{ms:02}".replace(":", "-")
def get_saving_frames_durations(cap, saving_fps):
"""A function that returns the list of durations where to save the frames"""
s = []
# get the clip duration by dividing number of frames by the number of frames per second
#clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS)
cap_fps = cap.get(cv2.CAP_PROP_FPS)
if cap_fps == 0:
cap_fps = 1 # Protection form "division by zero"
clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap_fps
if saving_fps == 0:
saving_period = 1 # Protection form "division by zero"
else:
saving_period = 1 / saving_fps
# use np.arange() to make floating-point steps
for i in np.arange(0, clip_duration, saving_period):
s.append(i)
return s
def main(working_dir, video_file):
filename, _ = os.path.splitext(video_file)
filename += "-opencv"
# read the video file
full_video_file = os.path.join(working_dir, video_file) # Join the working directory and the file name
cap = cv2.VideoCapture(full_video_file) #cap = cv2.VideoCapture(video_file)
if not cap.isOpened():
return # Skip the file if it's not a video file.
out_dir = os.path.join(working_dir, filename)
# make a folder by the name of the video file
if not os.path.isdir(out_dir): #if not os.path.isdir(filename):
os.mkdir(out_dir) #os.mkdir(filename)
# get the FPS of the video
fps = cap.get(cv2.CAP_PROP_FPS)
# if the SAVING_FRAMES_PER_SECOND is above video FPS, then set it to FPS (as maximum)
saving_frames_per_second = min(fps, SAVING_FRAMES_PER_SECOND)
# get the list of duration spots to save
saving_frames_durations = get_saving_frames_durations(cap, saving_frames_per_second)
#start the loop
count = 0
while True:
is_read, frame = cap.read()
if not is_read:
# break out of the loop if there are no frames to read
break
# get the duration by dividing the frame count by the FPS
frame_duration = count / fps
try:
# get the earliest duration to save
closest_duration = saving_frames_durations[0]
except IndexError:
# the list is empty, all duration frames were saved
break
if frame_duration >= closest_duration:
# if closest duration is less than or equals the frame duration,
# then save the frame
frame_duration_formatted = format_timedelta(timedelta(seconds=frame_duration))
cv2.imwrite(os.path.join(out_dir, f"frame{frame_duration_formatted}.jpg"), frame) #cv2.imwrite(os.path.join(filename, f"frame{frame_duration_formatted}.jpg"), frame)
# drop the duration spot from the list, since this duration spot is already saved
try:
saving_frames_durations.pop(0)
except IndexError:
pass
# increment the frame count
count += 1
import os
working_directory = '/content/gdrive/MyDrive/x/train_videos/Red' # Assume the output directory is the same as the input directory (name it "working directory")
for filename in os.listdir(working_directory):
if __name__ == "__main__":
a = main(working_directory, filename)
---
Note:
In case you like to save the output images in other directory you may have to pass the output directory as argument to `main`, and update the code accordingly.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论