[英]Parse video at lower frame rate
我目前正在做一個項目,我需要解析視頻並將其傳遞給多個模型。 視頻以 60fps 的速度播放。 我不需要通過模型運行每一幀。 我在嘗試跳過不需要的幀時遇到了一些問題。 我嘗試了兩種方法,它們都相當慢。
方法 1 代碼片段:這里的問題是我仍在閱讀視頻的每一幀。 只有每 4 幀通過我的模型運行。
cap = cv2.VideoCapture(self.video)
while cap.isOpened():
success, frame = cap.read()
if count % 4 !=0:
count += 1
continue
if success:
''Run frame through models''
else:
break
方法 2 代碼片段:此方法較慢。 在這種情況下,我試圖避免閱讀不必要的幀。
cap = cv2.VideoCapture(video)
count=0
while True:
if count % 4 != 0:
cap.set(cv2.CV_CAP_PROP_POS_FRAMES, count*15)
count+=1
success, frame = cap.read()
關於如何以最有效的方式實現這一目標的任何建議將不勝感激。
由於視頻壓縮的工作方式:通過使用關鍵幀,通過更改 CV_CAP_PROP_POS_FRAMES 來獲取和設置幀不准確(而且速度很慢)。
根本不使用 read() 函數可能會有所幫助。 而是使用grab() 並且只檢索() 所需的幀。 來自文檔:(讀取)方法/函數在一次調用中結合了 VideoCapture::grab() 和 VideoCapture::retrieve()。
Grab()獲取幀數據,然后retrieve() 對其進行解碼(計算量很大的部分)。 您可能想要做的只是抓取要跳過的幀而不是檢索它們。
根據您的系統和 opencv 版本,您還可以使用硬件加速對視頻進行 ffmpeg 解碼。
據我所知,您正在嘗試每四幀處理一次。 您正在使用條件:
if count % 4 != 0
而是在 4 幀中觸發 3 幀(您正在處理幀 1、2、3、5、6、7 等)! 使用相反的:
if count % 4 == 0
此外,盡管代碼片段,這兩種方法似乎沒有處理相同的幀。 盡管在這兩種情況下,您的計數器似乎在每一幀中都增加了 1,但您實際上在第二種情況下指向了該計數器的 15xframe ( cap.set(cv2.CV_CAP_PROP_POS_FRAMES, count*15)
。
對你的代碼也有一些評論(也許我誤解了一些東西):
情況1:
while cap.isOpened():
success, frame = cap.read()
if count % 4 !=0:
count += 1
continue
在這里,您似乎只計算了一些幀(如上所述,4 中的 3 個),因為跳過了 4 的倍數的幀:在這種情況下,不滿足條件count % 4 !=0
並且您的計數器沒有更新,盡管您閱讀了一個幀. 所以,你這里有一個不准確的計數器。 雖然沒有顯示您如何以及在何處處理幀以判斷該部分。
案例2:
while True:
if count % 4 != 0:
cap.set(cv2.CV_CAP_PROP_POS_FRAMES, count*15)
count+=1
success, frame = cap.read()
在這里,您僅在滿足條件時才讀取幀,因此在此代碼片段中,您實際上並未讀取任何幀,因為第 0 幀不會觸發條件! 如果您在 if 范圍之外更新計數器,則此處不清楚。 但如果你這樣做,你也應該在那里閱讀一個框架。 無論如何,應該透露更多的代碼來說明。
作為一般建議,您應該在每次讀取幀時更新計數器。
與其對幀數設置閾值,這將使 opencv 處理所有幀(您正確指出,這會減慢視頻處理速度),最好使用CAP_PROP_POS_MSEC
鏈接並將該處理卸載到cv2
。 通過使用此選項,您可以將cv2
配置為每第 n 毫秒采樣 1 幀。 因此,在vidcap.set(cv2.CAP_PROP_POS_MSEC, (frame_count * subsample_rate))
設置subsample_rate=1000
將每 1 秒采樣 1 幀(因為 1000 毫秒等於 1 秒)。 希望這可以提高您的視頻處理速度。
def extractImagesFromVideo(path_in, subsample_rate, path_out, saveImage, resize=(), debug=False):
vidcap = cv2.VideoCapture(path_in)
if not vidcap.isOpened():
raise IOError
if debug:
length = int(vidcap.get(cv2.cv2.CAP_PROP_FRAME_COUNT))
width = int(vidcap.get(cv2.cv2.CAP_PROP_FRAME_WIDTH))
height = int(vidcap.get(cv2.cv2.CAP_PROP_FRAME_HEIGHT))
fps = vidcap.get(cv2.cv2.CAP_PROP_FPS)
print 'Length: %.2f | Width: %.2f | Height: %.2f | Fps: %.2f' % (length, width, height, fps)
success, image = vidcap.read() #extract first frame.
frame_count = 0
while success:
vidcap.set(cv2.CAP_PROP_POS_MSEC, (frame_count*subsample_rate))
success, image = vidcap.read()
if saveImage and np.any(image):
cv2.imwrite(os.path.join(path_out, "%s_%d.png" % (frame_count)), image)
frame_count = frame_count + 1
return frame_count
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.