[Python]透过OpenCV读取RTSP讯号呈现在Tkinter并录影

前言

原本採用web架构,但web对于RTSP支援程度较差(MJPG才是网页常见的格式,原生支援度高),目前使用的作法是透过架NodeJS接收RTSP串流,再经由websocket传输到浏览器画面上,但这样多一转换层,除了效能的疑虑,也会有一些系统不稳定的风险,假如websocket断掉,影像就进不来了,而且同一时间要连的RTSP不只有一个,不确定websocket是否能承受大量的资讯传输,因此觉得还是client直接接收RTSP串流比较稳一点;原本的想法是在react里面埋nodejs,透过VNC抓RTSP的dll元件来去达成目的,但工程浩大,也还不知道怎么做,最后整个重写,使用python tkinter来呈现RTSP摄影机的影像了。

安装opencv for python套件

这篇的重点就是要用OpenCV来读RTSP,当然套件是不能少的,先pip一下吧

> pip install opencv-python

接着读取RTSP的影像串流,呈现在画面上拨放它

URL我们先用国外测试的RTSP网址:rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov,用VNC稍作测试可以播放后,就把它放进来opencv套件吧

from cv2 import cv2video = cv2.VideoCapture('rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov')

这样子相当于已经準备好跟RTSP的连线了,再来我们使用read()来取每一格frame,那他回传的是一个阵列,第一个回传状态,第二个才是frame,所以我们用(status,frame)去接他,并用while去接每一格frame,while跳出条件当然是status啰,也就是当RTSP串流播放完毕跳出迴圈,另外,我会习惯再加上手动停止的flag,所以看起来会是这样...

(status, frame) = video.read()while self.__active and status:    (status, frame) = video.read()

取到frame后,会处理一个色彩空间转换的步骤,把BGR转换成我们常见的RGBA,让他生成pixel阵列后,再透过PIL套件转成Image物件

imgArray = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)image = Image.fromarray(imgArray)photo = ImageTk.PhotoImage(image=image)

最后,把RTSP影像放在tkinter的Label widget做呈现啰

# 建立承载RTSP影像串流的容器物件window = tk.Label(bg="black", image=photo, width=320, height=240)# avoid garbage collection(避免资源被回收)(把图片注册到物件中,并自订属性,避免被回收)window.rtspImage = photo# 放置在画面上window.place(x=0, y=0, anchor='nw')

最后的最后,非常重要的一环,资源释放,一定要切断跟RTSP的连线,否则容易占用记忆体空间

video.release()

我到底看了什么? 录下来吧

到这边,客户又给了一个新需求,要再检视摄影机RTSP串流的时候,同步录影下来,还好我们有OpenCV大神加持,没问题,马上录;使用VideoWriter()提供的写入影像功能就可以达成目的了

record = cv2.VideoWriter([档案路径名称], [影片编码], [FPS], ([影片宽度], [影片高度]))

但是笔者在实做过程中,编码如果跟来源不一样,都没有办法成功录进去档案里,于是再多做了一些处理,就是取得来源RTSP串流的编码、FPS与宽高

# 取得来源RTSP影像的编码def getSourceFourcc(sourceVideo):    code = sourceVideo.get(cv2.CAP_PROP_FOURCC)    code = "".join([chr((int(code) >> 8 * i) & 0xFF) for i in range(4)])    return coderecordForucc = cv2.VideoWriter_fourcc(*getSourceFourcc(video))recordFPS = int(video.get(cv2.CAP_PROP_FPS))recordWidth = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))recordHeight = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))# 建立录影实体物件record = cv2.VideoWriter('CameraRecord.avi', recordForucc, recordFPS, (recordWidth, recordHeight))

接着,在每次成功取得frame后,就write到档案中,这个动作会根据设定的FPS来写到影片档案中

record.write(frame)  # 录製影片到档案

最后最后,很重要,要记得释放,影片档案才不会一直被占用住喔

record.release()

关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章