场景: 采用深度学习的方案处理视频流的任务,比如:视频跟踪,视频中的行人检测,车辆检测等其他任务,一般会采用opencv读取视频流,然后再一帧一帧的处理。
问题: 但是在这个过程中由于算力的限制,计算的速度会小于视频帧读取的速度,就是会出现计算结果延时的情况,但是采用cv2.VideoCapture()读取的时候,它会逐帧读取,就是它不是每次读取最新的帧,所以时间久了,这个队列就会溢出,程序就会自动停止。
解决思路
- 主要的思路就是用python的multiprocessing多进程或pytorch的multiprocessing,在我的例子中二者是通用的。
- 同时在__main__中要加上mp.set_start_method(‘spawn’)
- 注意pytorch模型的初始化,要保证每个进程都分别初始化了自己的模型,就是你有多少个进程,那么就要启动几个模型
其中的第3点是非常关键的,平时的python多进程只需要注意第一点就好了。
Code
class mulProcessone_camera(object):
"""
data:2019-06-11
use:采用多线程的方式来读取摄像头的视频,模拟达到实时的效果
"""
def __init__(self, vediopath):
self.vedio_path = vediopath
def image_put(self, q):
cap = cv2.VideoCapture('rtsp://admin:shenlan2018@171.211.126.205:1554/h264/ch1/main/av_stream')
if cap.isOpened():
print('HIKVISION')
else:
cap = cv2.VideoCapture('rtsp://admin:shenlan2018@171.211.126.205:1554/h264/ch1/main/av_stream')
print('DaHua')
while True:
if q.qsize() > 2: # 第3张图片的时候,队列就吐出一张只有两张了
q.get()
else:
pass
print(q.qsize())
q.put(cap.read()[1]) # 3张图片,到达队列的maxsize
def image_get(self, q):
# cv2.namedWindow('window', flags=cv2.WINDOW_FREERATIO)
self.processfunc = Detector() # 分别初始化
while True:
try:
frame = q.get() # 获得图像
# frame = cv2.resize(frame, (640,360))
self.processfunc.detect(frame) # 让他一直启动
except:
print('wrong with deepsort qsize:%d'%q.qsize())
def run_single_camera(self): # 启动服务
queue = mp.Queue(maxsize=3)
self.processes = [mp.Process(target=self.image_put, args=(queue,)),
mp.Process(target=self.image_get, args=(queue,))]
[process.start() for process in self.processes]
[process.join() for process in self.processes]
def endprocess(self):
[process.terminate() for process in self.processes]
[process.join() for process in self.processes]
def main(vedio_path):
mulp = mulProcessone_camera(vedio_path)
mulp.run_single_camera() # 启动服务
mulp.endprocess() # 结束进程
if __name__=="__main__":
mp.set_start_method('spawn')
vedio_path = 'rtsp://admin:shenlan2018@171.211.126.205:1554/h264/ch1/main/av_stream'
main(vedio_path)
解释:
- self.processfunc = Detector() ,这个就是pytorch推理模型类的初始化,这句可以放两个位置,分别是 image_put(从视频流中获得一张图像压入队列)和image_get(从队列中获得一张图片,并用pytorch模型进行处理),self.processfunc 可以放在以上两个函数的while True的前面,这样process.start()启动进行时,就是启动[mp.Process(target=self.image_put, args=(queue,)), mp.Process(target=self.image_get, args=(queue,))]其中的目标函数。
- image_put和image_get中分别有个while True,所以process.start()启动的时候,就是执行的其中的内容。