修改一下配置文件就可以運行了
配置文件
config.py
video_path = 'xxxx/dataset/data/huaping/BXDQ05-花屏-1.mp4'#要處理的視頻路徑
frame_path = 'xxxx/dataset/frame'#處理成幀之后保存的路徑
flow_path = 'xxxx/dataset/flow'#處理成光流之后保存的路徑
save_video_path = 'xxxx/fetch-flow/output/result.mp4'#最終將光流幀變成視頻的路徑
fps = 30
2.將視頻拆分為幀
fetchFrame.py
from __future__ import print_function
import sys
import numpy as np
import os
import imageio#用于讀取和寫入圖像和視頻的庫
import cv2
import config
Height = 512
Width = 512def get_frame(file_dir):with imageio.get_reader(file_dir, 'ffmpeg') as vid:# 使用imageio庫打開視頻文件,并創建一個讀取器對象。此對象被命名為vid。'ffmpeg'是用于讀取視頻的編解碼器。nframes = vid.get_meta_data()['nframes']#從視頻元數據中獲取幀數,并保存到nframes變量中。for i, frame in enumerate(vid):n_frames = iframe = cv2.resize(frame, (Width, Height), interpolation = cv2.INTER_CUBIC)imageio.imwrite(config.frame_path+'/'+str(i)+'.jpg', frame)#將調整大小后的幀保存為JPEG文件。文件的路徑和名稱是由前面的路徑、字符串"frame_"和當前幀索引組合而成的。np.save('nframes.npy', n_frames)#將視頻的總幀數保存到一個NumPy文件中。文件名是'nframes.npy',而文件中的數據是n_frames變量。
2.計算光流
fetchFlow.py
import os
import numpy as np
import cv2
from glob import glob_IMAGE_SIZE = 256# 用于計算視頻中每一幀之間的光流。它首先根據視頻路徑獲取所有以'.jpg'結尾的幀圖像文件路徑,并按順序排序。然后,它使用OpenCV庫讀取并轉換每一幀的圖像,計算當前幀與前一幀之間的光流,并將光流添加到一個列表中。最后,返回包含所有光流的列表。
import os
import cv2
from glob import globdef cal_for_frames(video_path):# 獲取視頻路徑下的所有jpg圖片路徑print(video_path)# 對圖片路徑進行排序frames = [f for f in os.listdir(video_path)]frames = sorted(frames, key=lambda x:int(x[:-4]))#字符串排序順序會是1,10,11這樣,所以要進行關鍵字排序 frames = [os.path.join(video_path, f) for f in frames]print(frames)flow = []prev = cv2.imread(frames[0]) # 讀取第一幀圖像prev = cv2.cvtColor(prev, cv2.COLOR_BGR2GRAY) # 將第一幀圖像轉換為灰度圖像for i, frame_curr in enumerate(frames):print(frame_curr)curr = cv2.imread(frame_curr) # 讀取當前幀圖像curr = cv2.cvtColor(curr, cv2.COLOR_BGR2GRAY) # 將當前幀圖像轉換為灰度圖像tmp_flow = compute_TVL1(prev, curr) # 計算當前幀和前一幀之間的光流flow.append(tmp_flow) # 將光流添加到列表中prev = curr # 更新前一幀圖像print(i)return flow # 返回光流列表def compute_TVL1(prev, curr, bound=15):"""計算TV-L1光流。參數:prev: numpy.ndarray, 輸入圖像序列中的前一幀圖像。curr: numpy.ndarray, 輸入圖像序列中的當前幀圖像。bound: int, 光流值的邊界限制,默認為15。返回值:flow: numpy.ndarray, 計算得到的光流圖像。"""# 創建TV-L1光流估計算法對象TVL1 = cv2.DualTVL1OpticalFlow_create()# 使用TV-L1算法計算光流flow = TVL1.calc(prev, curr, None)assert flow.dtype == np.float32# 將光流值進行縮放和取整操作flow = (flow + bound) * (255.0 / (2*bound))flow = np.round(flow).astype(int)# 將光流值限制在0-255范圍內flow[flow >= 255] = 255flow[flow <= 0] = 0return flowdef save_flow(video_flows, flow_path):"""保存視頻的光流圖參數:video_flows:視頻的光流圖(三維數組)flow_path:保存光流圖的路徑(字符串)返回值:無"""for i, flow in enumerate(video_flows):# 保存u分量的光流圖cv2.imwrite(os.path.join(flow_path.format('u'), "{:06d}.jpg".format(i)),flow[:, :, 0])# 保存v分量的光流圖cv2.imwrite(os.path.join(flow_path.format('v'), "{:06d}.jpg".format(i)),flow[:, :, 1])#u代表水平分量,v代表垂直分量def extract_flow(video_path,flow_path):flow = cal_for_frames(video_path)print("finish1")save_flow(flow, flow_path)print('finish2')print('complete:' + flow_path)return
3.將幀寫入視頻
main.py
import imageio
import PIL.Image as Image
import numpy as np
from fetchFlow import extract_flow
from fetchFrame import get_frame
import configvideo_path = config.video_path
fps = config.fps
flow_path = config.flow_path
frame_path = config.frame_path
save_video_path = config.save_video_path#get_frame(video_path)
extract_flow(frame_path, flow_path)flow_list = [Image.open(os.path.join(flow_path,f)) for f in os.listdir(flow_path)]
print(flow_list)
with imageio.get_writer(save_video_path, fps = fps) as video:for image in flow_list:image = image.convert('RGB')image = np.array(image)video.append_data(image)
參考:提取光流