前幾天做實驗的時候,用到了opencv-python讀視頻並進行檢測。
用的就是傳統的一樣的方法,cv2.VideoCapture(video_path),read()方法讀取一幀,然後再把讀到幀送入檢測器,此處貼一部分代碼上去。
import cv2
video_path = "F:/1/1.mp4"
capture = cv2.VideoCapture(video_path)
while True:
ret, frame = capture.read()
if not ret:
break
results = detector.predict(frame)
cv2.waiiKey(-1)
但是這樣存在一些問題, 在特定的應用上每幀都檢測的話,時間效率上很差。
於是我對代碼進行了一些改進,設定每秒檢測一次。
import cv2
video_path = "F:/1/1.mp4"
capture = cv2.VideoCapture(video_path)
fps = capture.get(cv2.CAP_PROP_FPS) # 視頻的幀率FPS
total_frame = capture.get(cv2.CAP_PROP_FRAME_COUNT) # 視頻的總幀數
for i in range(int(total_frame)):
ret, frame = capture.read()
if not ret:
break
if i % fps == 0:
results = detector.predict(frame)
cv2.waitKey(-1)
這樣修改之後,每秒會選取一幀進行檢測,速度明顯快了許多。但是呢,自己又測試了一下,這樣大部分的時間都會浪費在讀視頻幀的過程中。
例如:我的視頻是30FPS,也就是說每30幀取出來1幀進行檢測,這就浪費了29幀的讀取時間。
還樣的方式還是太耗時,於是再次進行了一波改進:
read函數其實是grab和retrieve函數的結合
–grab函數 捕獲下一幀
–retrieve函數 對該幀進行解碼
思路就是:只捕獲,但是不解碼,對於需要的幀再進行解碼。
附上我參考的博客:
read、grab、retrieve函數詳細解釋
import cv2
video_path = "F:/1/1.mp4"
capture = cv2.VideoCapture(video_path)
fps = capture.get(cv2.CAP_PROP_FPS) # 視頻的幀率FPS
total_frame = capture.get(cv2.CAP_PROP_FRAME_COUNT) # 視頻的總幀數
for i in range(int(total_frame)):
ret = capture.grab()
if not ret:
print("Error grabbing frame from movie!")
break
if i % fps == 0:
ret, frame = capture.retrieve()
if ret:
results = detector.predict(frame)
else:
print("Error retrieving frame from movie!")
break
cv2.waitKey(-1)
這樣,速度就更快了。
此外,還有一個方法是人爲設定讀取的幀數,利用set函數,但是在測試中,有的視頻無法讀取幀。就只簡單附在後面,供大家參考吧。
i = 100 # 人爲設定要讀取的視頻幀,從0開始計數
capture.set(cv2.CAP_PROP_POS_FRAMES, i)
ret, frame = capture.read()