A video is a series of images, or frames, shown in rapid succession. Its frame rate, measured in frames per second (FPS), dictates the display speed. For instance, a 30 FPS video shows 30 frames each second. The frame count and frame rate determine a video's detail, smoothness, file size, and the processing power needed for playback or editing.
Higher frame rates and more frames result in finer detail and smoother motion but at the cost of larger file sizes and greater processing requirements. Conversely, lower frame rates and fewer frames reduce detail and smoothness but save on storage and processing needs.
In this article, you will see how to reduce the frame rate per second for a video, and total number of frames in a video using the Python programming language.
But before that, let's see why you would want to reduce the number of frames and frame rate of a video.
Why Reduce the Number of Frames and the Frame Rate of a Video?
Reducing the number of frames and frame rate of a video can be beneficial for several reasons:
Storage Efficiency: Videos with fewer frames and lower frame rates take up less disk space, which is helpful when storage capacity is limited or for easier online sharing.
Bandwidth Conservation: Such videos use less network bandwidth, making them suitable for streaming over slow or unstable internet connections.
Performance Optimization: They require fewer computational resources, ideal for low-end devices or resource-intensive processes like deep learning algorithms.
Let's now see how to reduce video frame rates in Python.
Reducing Frame Rates Without Video Processing
One of the simplest ways to reduce the frame rate of a video without applying any preprocessing to the video is to use the moviepy library in Python, which is a powerful and easy-to-use library for video editing and manipulation.
The following script installs the moviepy and deepface libraries. We will use the deepface
library in a later section of the article.
! pip install deepface
! pip install moviepy
Next, we import the libraries required to run scripts in this article.
from moviepy.editor import VideoFileClip
import cv2
import glob
import os
from deepface import DeepFace
import numpy as np
from moviepy.editor import *
import math
To reduce the frame rate of a video, we will define a function that takes a video path, an output directory, and a new frame rate as inputs and reduces the frame rate of the video accordingly. The function performs the following steps:
- It extracts the file name from the video path using the
os.path.basename
function. - Loads the video using the
VideoFileClip
class and prints the original frame rate using thefps
attribute. - Reduces the frame rate of the video using the
.set_fps
method and passes the new frame rate as an argument. - Finally, it writes the modified video to the output directory using the
write_videofile
method.
The function looks like this:
def reduce_fps(video_path, output_directory, new_fps):
# Extract file name
file_name = os.path.basename(video_path)
# Load the video
video = VideoFileClip(video_path)
# print the original FPS
print(f"Orignal FPS: {video.fps}")
# Reduce the FPS
video = video.set_fps(new_fps)
# Write the modified video
output_path = os.path.join(output_directory, file_name)
video.write_videofile(output_path, fps=new_fps)
To use the function, specify the input video path, the output directory, and the new frame rate.
For example, if you want to reduce the frame rate of a video named input_video.mp4
to 10 FPS and save the modified video to a directory named D:\Datasets\Reduced FPS Videos
, you can do this:
input_video = r"D:\Datasets\input_video.mp4"
output_directory = r"D:\Datasets\Reduced FPS Videos"
new_fps = 10
reduce_fps(input_video,
output_directory,
new_fps)
The function will print the original and the new frame rate and write the modified video to the output directory. You can see the output in the image below:
Output:
Reducing FPS of Videos with Special Characters in Names
Sometimes, you might encounter videos that have special characters in their names, such as ---#input_video.mp4
. These characters can cause problems when writing the modified video using the moviepy
library because they can be interpreted as commands or arguments by the underlying ffmpeg
tool that moviepy
uses.
For example, if you try to reduce the frame rate of a video named ---#input_video.mp4
using the same function as before, you will get an error like this:
input_video = r"D:\Datasets\---#input_video.mp4"
output_directory = r"D:\Datasets\Reduced FPS Videos"
new_fps = 10
reduce_fps(input_video,
output_directory,
new_fps)
Output:
To avoid this error, you need to modify the function slightly. Instead of writing the modified video directly to the output path with the same file name, you need to write the video using a temporary output path with a different file name, such as temp.mp4
.
You can then rename the temporary file to the actual file name using the shutil.move
function
Here is a modified reduce_fps
function that writes video files with special characters in their names.
def reduce_fps(video_path, output_directory, new_fps):
# Extract file name
file_name = os.path.basename(video_path)
# Load the video
video = VideoFileClip(video_path)
# Reduce the FPS
video = video.set_fps(new_fps)
# Prepare the output path with a temporary file name
temp_output_path = os.path.join(output_directory, "temp.mp4")
print(f"Temporary output path is: {temp_output_path}")
# Write the modified video to the temporary file
video.write_videofile(temp_output_path, fps=new_fps)
# Prepare the final output path
final_output_path = os.path.join(output_directory, file_name)
print(f"Final output path is: {final_output_path}")
# Rename the temporary file to the final file name
shutil.move(temp_output_path, final_output_path)
The function will print the temporary and the final output paths and write the modified video to the output directory. You can see the output in the image below:
Output:
Reducing Number of Frames with Video Processing
You have already seen how to reduce the frame rate of a video without video processing in Python. Sometimes, you might need to reduce the total number of frames in a video without losing much information from the video.
A possible solution for that is to extract frames at regular intervals. This way, the total number of frames can be reduced and also the maximum information from the video can be retained. This can be particularly handy when you want to do some processing on video frames, but processing each frame can be costly.
For example, in the following script, we define the reduce_total_frames
function that reduces the total number of frames in a video and extracts faces from it. The function takes three arguments: the video path, the output directory, and the number of frames to capture.
Next, the function reads the video file and gets the total number of frames, the frame rate, and the file name. The function calculates the interval for capturing frames by dividing the total number of frames by the number of frames to capture.
The function loops over the video frames and checks if the current frame index is divisible by the interval. If it is, the function tries to extract the face from the frame using the DeepFace.extract_faces
function. The function uses the retinaface
backend, a state-of-the-art face detector.
If the function detects a face with a high confidence score, it converts the face image to the format expected by the moviepy
library and appends it to a list. The function increments the captured frame count by 1.
The function creates a video clip from the list of face images using the ImageSequenceClip
class from the moviepy
library and writes it to the output path.
The following script defines the reduce_total_frames
function that performs the above steps.
def reduce_total_frames(video_path, directory, frames_to_capture):
faces = []
cap = cv2.VideoCapture(video_path) # Read video file
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print("==================================")
print(f"Original total number of frames: {total_frames}")
print("===================================")
fps = cap.get(cv2.CAP_PROP_FPS)
fps = math.ceil(fps)
path = os.path.basename(video_path)
# Calculate interval for capturing frames
interval = max(1, float(total_frames) / float(frames_to_capture))
interval = np.round(interval)
print("===============================")
print(f"Interval to process frame : {interval}")
print("===============================")
frame_index = 0
captured_frame_count = 0
while cap.isOpened() and captured_frame_count < frames_to_capture:
ret, frame = cap.read()
if not ret:
break
# Capture frames at calculated intervals
if frame_index % interval == 0:
print(f"processing frame number {frame_index + 1}")
try:
face_props = DeepFace.extract_faces(img_path=frame,
target_size=(224, 224),
detector_backend="retinaface",
enforce_detection=False)
if face_props:
frame = cv2.cvtColor(face_props[0]['face'], cv2.COLOR_BGR2RGB)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
confidence = face_props[0]['confidence']
if confidence > 0.990:
features_dict = {"frames": frame, "confidence": confidence}
faces.append(features_dict)
captured_frame_count += 1
except Exception as e:
print(f"Error processing frame at index {frame_index}: {e}")
if captured_frame_count % 10 == 0:
print("============================")
print(f"Total frames processed: {captured_frame_count}")
print("============================")
frame_index += 1
image_frames = []
for video_frame in faces:
a = video_frame['frames']
image_frame = np.interp(a, (a.min(), a.max()), (0, 255)).astype(np.uint8)
image_frames.append(image_frame)
# Create a video clip from the frames
clip = ImageSequenceClip(image_frames, fps = fps)
final_output_path = os.path.join(directory, path)
clip.write_videofile(final_output_path)
The function will print the original and the reduced number of frames, the interval, the frame index, the captured frame count, and the output path. You can see the output in the image below:
Output:
Conclusion
In this article, you learned to reduce video frame rate and frame count using Python with moviepy
and DeepFace
libraries. You also discovered how to handle videos with special characters in their names. These techniques save storage space, reduce bandwidth usage, and enhance performance, especially for demanding video processing tasks like deep learning.
I hope you found this article helpful. If you have any questions or feedback, please share them below.