问题来源及说明:
最近在做一个厨房实时监控的项目,共有两个摄像头监控两个厨房,我写了一个多进程的程序,单进程使用rtsp协议实时访问单路摄像头,开始画面一切正常,工作一段时间后总是会报错,missing picture in access unit,上网查询说是rtsp延迟导致,也有的说是图像处理的速度跟不上传输速度导致cv2.VideoCapture积累过多导致。
贴一下自己遇到的bug图:
1.[rtsp @ 0000028c04b0e640] RTP: PT=60: bad cseq 70bc expected=44c0 该bug是帧延迟后有时候会报出,然后一会程序就会停止
2.
[NULL @ 000002d5c65b5180] missing picture in access unit
未检测到图片2! 2020-07-13 03:00:35.651561
Process Process-2:
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\multiprocessing\process.py", line 258, in _bootstrap
self.run()
File "C:\ProgramData\Anaconda3\lib\multiprocessing\process.py", line 93, in run
self._target(*self._args, **self._kwargs)
File "D:\MonitoringSystem\main.py", line 251, in videoProcess2
raise
RuntimeError: No active exception to reraise
[NULL @ 000001a53de55180] missing picture in access unit
未检测到图片1! 2020-07-13 03:00:50.437611
暂无法解决!!
2023/07月份的时候又做了一个类似的项目,用后台python程式通过rtsp协议访问摄像头画面进行人头检测,运行本地视频一切正常但是运行摄像头实时视频出现了类似的'' 'error while decoding'.问题,本质还是处理速度跟不上传输速度问题,使用多线程的方式结合队列进行了解决。
先来看一个简单的读取RTSP的示例程序 :
import cv2
cap=cv2.VideoCapture("rtsp://admin:admin_123@172.0.0.0")
ret,frame = cap.read()
while ret:
ret,frame = cap.read()
cv2.imshow("frame",frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
cap.release()
这是一个读取视频然后实时显示的demo,因为仅仅是读取显示,并没与涉及到处理,所以速度跟的上不会出现丢帧或者帧显示不及时的问题。 其中frame值为每一帧的图像,但是如果在while 代码块中添加对每一帧的识别操作,比如加入Tensorflow识别一下其中的小动物,则会报出以上那个的错误导致这个while循环由于这个异常而中断。经过分析得知道:原来是由于FFMPEG Lib对在rtsp协议中的H264 vidos不支持,所以处理办法就是自己写两个不同的线程单独去处理接收每一帧的图像,然后另一个线程处理这每一帧的图像。
思路如下:使用队列,采取先入先出策略,在一个线程中开始接收数据,在另一个线程中处理逐帧数据。
代码如下:
import cv2
import queue
import time
import threading
q=queue.Queue()
def Receive():
print("start Reveive")
cap = cv2.VideoCapture("rtsp://admin:admin_123@172.0.0.0")
ret, frame = cap.read()
q.put(frame)
while ret:
ret, frame = cap.read()
q.put(frame)
def Display():
print("Start Displaying")
while True:
if q.empty() !=True:
frame=q.get()
cv2.imshow("frame1", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
if __name__=='__main__':
p1=threading.Thread(target=Receive)
p2 = threading.Thread(target=Display)
p1.start()
p2.start()
Receive作为接收数据线程,Display作为简单的处理即显示,这样就能很好的解决这个问题了。不过有一点要提醒一下,python多线程的如何杀死问题也是需要结局的,这个可以单独去网上查资料进行研究。