大家好!在前面的文章中,我們介紹了許多影像處理的技術,包括 2D 圖像置入、深度圖生成與應用、前後景分離等。今天,我們要將目光轉移到影片處理上,特別是「影片幀區分割」,也就是將影片中畫面變動較大的區段切分出來。透過自動化場景偵測,程式能在影片長度較長的情況下有效地分割幀區,取代人工一幀一幀判讀的繁瑣工作。如果你覺得概念較抽象,可以參考這個 影片 的 3:30 處,了解幀區分割的應用場景。
今天要介紹的是 Python 中兩種常見的影片幀區分割技術——OpenCV 和 FFmpeg。我們將比較它們的優缺點,並結合實際測試結果來更深入理解其表現。
本次測試影片:Emma Watson Once Mistook Jimmy Fallon for Jimmy Kimmel
優點:
缺點:
程式碼範例:
import datetime
import cv2
def main():
cap = cv2.VideoCapture('../test_video.mp4')
ret, prev_frame = cap.read()
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
threshold = 750000
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
output_filename_template = 'segment_{}.mp4'
segment_index = 0
def start_new_writer(frame, segment_index):
height, width, _ = frame.shape
filename = output_filename_template.format(segment_index)
return cv2.VideoWriter(filename, fourcc, 30, (width, height))
out = start_new_writer(prev_frame, segment_index)
while True:
ret, curr_frame = cap.read()
if not ret:
break
curr_gray = cv2.cvtColor(curr_frame, cv2.COLOR_BGR2GRAY)
diff = cv2.absdiff(prev_gray, curr_gray)
non_zero_count = cv2.countNonZero(diff)
if non_zero_count > threshold:
segment_index += 1
out.release()
out = start_new_writer(curr_frame, segment_index)
out.write(curr_frame)
prev_gray = curr_gray
cap.release()
out.release()
if __name__ == '__main__':
start_time = datetime.datetime.now()
main()
end_time = datetime.datetime.now()
print('Time taken:', end_time - start_time)
切分效果 (共切出 60 個片段):
優點:
缺點:
adaptive_threshold
和 min_content_val
才能達到理想效果。程式碼範例:
import os
from scenedetect import detect, split_video_ffmpeg
from scenedetect.detectors import AdaptiveDetector
from datetime import datetime
def split_video_by_ffmpeg(movie_path, output_dir, adaptive_threshold, min_content_val):
start_time = datetime.now()
scene_list = detect(movie_path, AdaptiveDetector(adaptive_threshold=adaptive_threshold, min_content_val=min_content_val))
split_video_ffmpeg(movie_path, scene_list, output_dir=output_dir)
end_time = datetime.now()
print(f"Total time taken: {end_time - start_time} seconds")
return len(scene_list)
def main():
movie_path = "/renhe's code/test_video.mp4"
output_dir = "/renhe's code/benchmarks/emma/"
adaptive_threshold_values = [1.5, 2.0, 2.5, 3.0, 3.5]
min_content_val_values = [5.0, 10.0, 15.0, 20.0, 25.0]
for adaptive_threshold in adaptive_threshold_values:
for min_content_val in min_content_val_values:
test_output_dir = os.path.join(output_dir, f"{adaptive_threshold}_{min_content_val}")
os.mkdir(test_output_dir)
split_video_by_ffmpeg(movie_path, test_output_dir, adaptive_threshold, min_content_val)
if __name__ == "__main__":
main()
切分效果 (參數使用預設值,共切出 18 個片段):
其他參數分析
圖 1: Total Frame Blocks vs. Min Content Value
此圖展示了隨著 min_content_val
變化,總幀區塊數的變化情況。結果表明,較低的 adaptive_threshold
可以捕捉到更多的場景變化。
圖 2: Total Time Taken vs. Min Content Value
總耗時隨著 min_content_val
增加而減少,特別在較低的 adaptive_threshold
下更明顯。
圖 3: Total Time Taken vs. Total Frame Blocks
顯示了總幀區塊數與總耗時的正相關性,隨著幀區塊數增加,耗時也隨之增加。
我們針對兩種方法進行了效能測試,結果如下:
adaptive_threshold
和 min_content_val
才能提升效果。adaptive_threshold
和 min_content_val
參數,以提升偵測準確度。今天我們比較了 OpenCV 和 FFmpeg 這兩種常見的影片幀區分割技術。根據具體需求選擇適合的方法,並根據影片特性調整參數,可以顯著提升處理效率與準確度。