python视频延迟严重_利用多进程降低opencv视频延迟处理rtsp视频流
Python多進程opencv
前幾天遇到了一個問題,利用opencv程序調取rtsp視頻流,因為處理程序要消耗的CPU時間過于長,VideoCapture的read是按幀讀取,所以經常導致內存溢出,延時還高得出奇。
所以想到是不是可以利用多進程把讀取視頻和處理視頻分開,這樣就可以消除因處理圖片所導致的延遲。
所用庫
multiprocessing
gc
opencv-python
os
實現方法
一開始是想用多線程,但是因為GIL的存在,像實時處理視頻這樣的CPU密集型任務多線程等于沒用。然后就選擇了多進程。
然后要考慮怎樣在兩個進程中傳參的問題:
multiprocessing中有Quaue、SimpleQuaue等進程間傳參類,還有Manager這個大管家。
Quaue這一類都是嚴格的數據結構隊列類型
Manager比較特殊,它提供了可以在進程間傳遞的列表、字典等python原生類型
還要考慮怎樣才能達到處理進程可以在讀取進程中得到最新的一幀:
其實VideoCapture是一個天生的隊列,先進先出。如果要達到實時獲得最新幀的目的,就需要棧來存儲視頻幀,而不是隊列。
這樣的話,Quaue這一大類就都沒有可能了,肯定不能用它來傳參。
提到棧突然想到了python的列表,它的append和pop操作完全可以當”不嚴格“的棧來用。所以順理成章地multiprocessing.Manager.list就是最好的進程間傳參類型。
再就是傳參棧自動清理的問題,壓棧頻率肯定是要比出棧頻率高的,時間一長就會在棧中積累大量無法出棧的視頻幀,會導致程序崩潰,這就需要有一個自動清理機制:
設置一個傳參棧容量,每當達到這個容量就直接把棧清空,再利用gc庫手動發起一次python垃圾回收。這樣就不會導致嚴重的內存溢出和程序崩潰。
實現代碼
import os
import cv2
import gc
from multiprocessing import Process, Manager
# 向共享緩沖棧中寫入數據:
def write(stack, cam, top: int) -> None:
"""
:param cam: 攝像頭參數
:param stack: Manager.list對象
:param top: 緩沖棧容量
:return: None
"""
print('Process to write: %s' % os.getpid())
cap = cv2.VideoCapture(cam)
while True:
_, img = cap.read()
if _:
stack.append(img)
# 每到一定容量清空一次緩沖棧
# 利用gc庫,手動清理內存垃圾,防止內存溢出
if len(stack) >= top:
del stack[:]
gc.collect()
# 在緩沖棧中讀取數據:
def read(stack) -> None:
print('Process to read: %s' % os.getpid())
while True:
if len(stack) != 0:
value = stack.pop()
cv2.imshow("img", value)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
if __name__ == '__main__':
# 父進程創建緩沖棧,并傳給各個子進程:
q = Manager().list()
pw = Process(target=write, args=(q, "rtsp://xxx:xxx@192.168.1.102:554", 100))
pr = Process(target=read, args=(q,))
# 啟動子進程pw,寫入:
pw.start()
# 啟動子進程pr,讀取:
pr.start()
# 等待pr結束:
pr.join()
# pw進程里是死循環,無法等待其結束,只能強行終止:
pw.terminate()
實際上這個程序就是把VideoCapture的隊列讀取改成了棧讀取。這個程序可以寫成一個類,來作為一個新形式的VideoCapture。
TODO
并沒有加入進程鎖,只是有一些防止棧空出棧的判斷,這樣并不能達到進程安全。最好還是加鎖
總結
以上是生活随笔為你收集整理的python视频延迟严重_利用多进程降低opencv视频延迟处理rtsp视频流的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: informix和mysql的区别_DB
- 下一篇: redis 缓存预热_Redis:缓存雪
