使用Python,OpenCV捕获关键事件,并进行视频剪辑
生活随笔
收集整理的這篇文章主要介紹了
使用Python,OpenCV捕获关键事件,并进行视频剪辑
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
使用Python,OpenCV捕獲關鍵事件,并進行視頻剪輯
- 1. 效果圖
- 2. 原理
- 2.1 步驟
- 2.2 如何找到HSV空間值呢?
- [[[60 255 255]]]
- 3. 源碼
- 3.1 keyclipwriter.py
- 3.2 save_key_events.py
- 參考
上一篇博客介紹了如何使用Python、OpenCV寫入視頻文件,這一篇將介紹如何做有趣的視頻剪輯,而不是保留整個視頻文件;
總體目標是構建視頻概要,將視頻流的最關鍵,突出和有趣部分提煉成一系列短視頻文件。
使用場景有:
- 訪問在區域中檢測到的運動物體;
- 截取入侵者進入房子或公寓的片段;
什么才是視頻的關鍵幀、有趣部分,則完全取決于您的需求和目標;
使用此方法,可以將小時級的視頻流素材縮小為多個秒級的有趣事件的小視頻,有效地產生視頻概要。
1. 效果圖
檢測畫面中的綠色盆,并將其生成gif圖,如下:
2. 原理
2.1 步驟
- 定義關鍵事件;
- 將包含事件的視頻片段寫入到視頻文件;
利用線程以確保在輸入流和輸出視頻剪輯文件中執行I / O時,不會放慢主程序的速度。
利用內置的Python數據結構,如DEQUE隊列以按順序存放關鍵幀;
2.2 如何找到HSV空間值呢?
比如要尋找綠色,可以找到綠色對應的BGR(0,255,0) ,利用opencv轉換為HSV,然后取[ H-10,S,V]為下限 – [ H+10,S,V]為上限;
green = np.uint8([[[0, 255, 0]]])
hsv_green = cv2.cvtColor(green, cv2.COLOR_BGR2HSV)
print(hsv_green)
[[[60 255 255]]]
3. 源碼
3.1 keyclipwriter.py
# 導入必要的包
from collections import deque # 導入隊列,FIFO(first in first out)先進先出原則
from threading import Thread
from queue import Queue
import time
import cv2class KeyClipWriter:# bufSize 要在內存緩沖區中緩存的最大幀數# timeout 超時時間def __init__(self, bufSize=64, timeout=1.0):# 存儲在內存中要保留的最大緩沖區大小 以及睡眠超時期間self.bufSize = bufSizeself.timeout = timeout# 初始化幀的緩沖區(64幀)、Q:待寫入的視頻幀、視頻寫入類、 多線程(以避免I/O延遲)# recordering boolean類型指示錄制是否已啟動self.frames = deque(maxlen=bufSize)self.Q = Noneself.writer = Noneself.thread = Noneself.recording = Falsedef update(self, frame):# 更新幀緩沖區self.frames.appendleft(frame)# 如果正在記錄,將幀加入隊列if self.recording:self.Q.put(frame)def start(self, outputPath, fourcc, fps):# 展示正在記錄關鍵事件幀# 表明正在錄制,啟動視頻寫入類,初始化需要寫入視頻文件的幀隊列self.recording = Trueself.writer = cv2.VideoWriter(outputPath, fourcc, fps,(600,600), True)self.Q = Queue()# 循環遍歷所有幀,并加入隊列for i in range(len(self.frames), 0, -1):self.Q.put(self.frames[i - 1])# 開啟一個單獨的線程寫入幀到視頻文件self.thread = Thread(target=self.write, args=())self.thread.daemon = Trueself.thread.start()def write(self):# 保持循環while True:# 如果停止了錄制,退出線程if not self.recording:return# 判斷隊列是否已經沒有關鍵事件幀了if not self.Q.empty():# 獲取隊列中的下一幀并寫入視頻文件frame = self.Q.get()self.writer.write(frame)# 如果隊列已經空了,sleep超時時間以不浪費cpu周期# 使用隊列時空閑一會兒尤其重要,隊列數據結構是線程安全的,暗示必須在更新內部緩沖區之前獲取鎖/信號量。# 如果不sleep,當緩沖區為空時,然后寫入和更新方法將不斷為鎖而戰斗。相反,最好讓視頻寫入類等待一會兒,直到需要寫入文件的隊列中存在積壓的幀。else:time.sleep(self.timeout)def flush(self):# 通過刷新所有剩余幀來清空隊列while not self.Q.empty():frame = self.Q.get()self.writer.write(frame)def finish(self):# 表明結束錄制、加入線程# 刷新隊列中的所有幀到視頻文件# 釋放視頻寫入指針self.recording = Falseself.thread.join()self.flush()self.writer.release()
3.2 save_key_events.py
# USAGE
# python save_key_events.py --output output# 導入必要的包
from pyimagesearch.keyclipwriter import KeyClipWriter
from imutils.video import VideoStream
import argparse
import datetime
import imutils
import time
import cv2# 構建命令行參數及解析
# --output 輸出視頻剪輯文件的路徑及名稱
# --picamera 是否使用樹莓攝像頭,默認-1:不是
# --fps 輸出視頻剪輯的幀率(即每秒的幀數) 默認20
# --codec 輸出視頻剪輯的四維編解碼器 默認MJPG
# --buffer-size 視頻剪切類的緩沖區大小 默認32,用于存儲來自相機傳感器最近輪詢幀的內存緩沖區的大小。
# 較大的緩沖大小將允許在“關鍵事件”中包含在輸出視頻剪輯中的“關鍵事件”之前和之后的更多上下文,而較小的緩沖大小將在“關鍵事件”之前和之后存儲更少的幀;
ap = argparse.ArgumentParser()
ap.add_argument("-o", "--output", required=True,help="path to output directory")
ap.add_argument("-p", "--picamera", type=int, default=-1,help="whether or not the Raspberry Pi camera should be used")
ap.add_argument("-f", "--fps", type=int, default=20,help="FPS of output video")
ap.add_argument("-c", "--codec", type=str, default="MJPG",help="codec of output video")
ap.add_argument("-b", "--buffer-size", type=int, default=32,help="buffer size of video clip writer")
args = vars(ap.parse_args())# 初始化視頻流,并預熱相機傳感器2s
print("[INFO] warming up camera...")
vs = VideoStream(usePiCamera=args["picamera"] > 0).start()
time.sleep(2.0)# 定義綠色球的較低和上邊界HSV顏色空間
greenLower = (29, 86, 6)
greenUpper = (64, 255, 255)# 初始化關鍵事件剪輯類,
# 初始化用于計算尚未包含任何有趣事件的連續幀數的整數。
kcw = KeyClipWriter(bufSize=args["buffer_size"])
consecFrames = 0# 保持循環
while True:# 獲取當前幀,縮放,初始化一個布爾類型值updateConsecFrames表示是否連續幀計數器應該被更新frame = vs.read()frame = imutils.resize(frame, width=600)updateConsecFrames = True# 高斯模糊幀,并將其RGB顏色空間轉換為HSV顏色空間,因此可以使用顏色閾值blurred = cv2.GaussianBlur(frame, (11, 11), 0)hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)# 為綠色構建一個顏色mask,然后執行一系列腐蝕膨脹操作已移除mask中小斑點# cv2.inRange實際進行顏色閾值處理,cv2.erode腐蝕,cv2.dilate膨脹操作mask = cv2.inRange(hsv, greenLower, greenUpper)mask = cv2.erode(mask, None, iterations=2)mask = cv2.dilate(mask, None, iterations=2)# 在mask中查找輪廓cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cnts = imutils.grab_contours(cnts)# 當發現輪廓時繼續處理if len(cnts) > 0:# 尋找mask中最大的輪廓,計算最小外接圓c = max(cnts, key=cv2.contourArea)((x, y), radius) = cv2.minEnclosingCircle(c)updateConsecFrames = radius <= 10# 只有當外接圓輪廓達到一定值時處理if radius > 10:# 重置連續幀計數器為0,繪制外接圓輪廓到幀上consecFrames = 0cv2.circle(frame, (int(x), int(y)), int(radius),(0, 0, 255), 2)# 如果還沒開始計關鍵事件幀數,開始記錄if not kcw.recording:timestamp = datetime.datetime.now()p = "{}/{}.avi".format(args["output"],timestamp.strftime("%Y%m%d-%H%M%S"))kcw.start(p, cv2.VideoWriter_fourcc(*args["codec"]),args["fps"])# 如果幀中沒有任何事件,將沒有關鍵事件幀的幀計數if updateConsecFrames:consecFrames += 1# 更新關鍵事件幀緩存區kcw.update(frame)# 如果沒有關鍵事件的幀達到一定數量,計數記錄剪輯if kcw.recording and consecFrames == args["buffer_size"]:kcw.finish()# 展示幀cv2.imshow("Frame", frame)key = cv2.waitKey(1) & 0xFF# 按下‘q’鍵,退出循環if key == ord("q"):break# 如果還在錄制中,結束錄制
if kcw.recording:kcw.finish()# 清理工作,釋放窗口,釋放視頻文件寫入指針
cv2.destroyAllWindows()
vs.stop()
參考
- https://www.pyimagesearch.com/2016/02/29/saving-key-event-video-clips-with-opencv/
總結
以上是生活随笔為你收集整理的使用Python,OpenCV捕获关键事件,并进行视频剪辑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Python,OpenCV和Haar
- 下一篇: 军团蛋可以开到天焰菲尔吗