Python樹(shù)莓派學(xué)習(xí)筆記之UDP傳輸視頻幀操作詳解
本文實(shí)例講述了Python樹(shù)莓派學(xué)習(xí)筆記之UDP傳輸視頻幀操作。分享給大家供大家參考,具體如下:
因?yàn)槲以谧约汗P記本電腦上沒(méi)能成功安裝OpenCV-Contrib模塊,因此不能使用人臉識(shí)別等高級(jí)功能,不過(guò)已經(jīng)在樹(shù)莓派上安裝成功了,所以我想實(shí)現(xiàn)把樹(shù)莓派上采集的視頻幀傳輸?shù)絇C的功能,這樣可以省去給樹(shù)莓派配顯示屏的麻煩,而且以后可能可以用在遠(yuǎn)程監(jiān)控上。
1 UDP還是TCP
首先考慮用哪種傳輸方式,平常TCP用的非常多,但是像視頻幀這種數(shù)據(jù)用TCP不是太合適,因?yàn)橐曨l數(shù)據(jù)的傳輸最先要考慮的是速度而不是準(zhǔn)確性,視頻幀的數(shù)據(jù)量很大,幀間隔也非常短,需要盡量保證傳輸速度,同時(shí)丟失一些數(shù)據(jù)是無(wú)所謂的。TCP需要維護(hù)連接、保證數(shù)據(jù)包正確,會(huì)耗費(fèi)一些時(shí)間,因此應(yīng)該使用UDP,就像所有參考書(shū)上說(shuō)的,UDP不在乎是否建立連接,也不管數(shù)據(jù)是否能被準(zhǔn)確接收,只關(guān)心能否把數(shù)據(jù)發(fā)送出去而已。
在Python的socket代碼中也可直觀地看到UDP的特點(diǎn),對(duì)于發(fā)送方,我們通過(guò)server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)創(chuàng)建UDP套接字對(duì)象,然后執(zhí)行server.connect((HOST,PORT)) 指定發(fā)送方地址,但其實(shí)connect函數(shù)直接就返回了,不像TCP中的客戶端會(huì)等待連接成功,接著就可直接在套接字對(duì)象上調(diào)用send函數(shù)發(fā)送數(shù)據(jù)了,這個(gè)過(guò)程根本沒(méi)確立連接。
2 圖像傳輸中的編解碼
但是用UDP傳輸圖像有一個(gè)很關(guān)鍵的問(wèn)題需要考慮,就是圖像的大小。根據(jù)UDP協(xié)議,單個(gè)包的數(shù)據(jù)大小最大只能65507個(gè)字節(jié)(去掉包頭),而一般直接從攝像頭采集的圖像幀的大小比這個(gè)數(shù)要大得多,以我的邏輯C270為例,單幅圖像的大小為480X640X3個(gè)字節(jié),遠(yuǎn)大于65507,因此一個(gè)包是沒(méi)法發(fā)送完的。解決方法有兩種,一種是把圖像拆成幾次進(jìn)行發(fā)送,相應(yīng)的接收端用個(gè)循環(huán)多次接收,這種方法可以完整地接收數(shù)據(jù),但是速度肯定受到影響,而且可能要添加一些自定義規(guī)則,徒增麻煩;另一種方法就是發(fā)送前先對(duì)圖像進(jìn)行編碼壓縮,接收后再解碼,清晰度會(huì)有所下降,但是可以保持速度上的優(yōu)勢(shì),這種方式比較合適。
OpenCV中的imencode和imdecode方法可分別用于圖像的編碼和解碼。imencode根據(jù)指定的標(biāo)識(shí)將圖像數(shù)據(jù)編碼并存入緩存區(qū),函數(shù)原型為cv2.imencode(ext, img[, params]) → retval, buf,ext為文件擴(kuò)展名,指定了存儲(chǔ)格式,如'.jpg';img為需要編碼的圖像數(shù)據(jù); params為指定的編碼標(biāo)識(shí),其形式為paramId_1, paramValue_1, paramId_2, paramValue_2, ... ,對(duì)于jpg格式,可以指定標(biāo)識(shí)為CV_IMWRITE_JPEG_QUALITY ,其對(duì)應(yīng)的值在0到100之間,表示了壓縮質(zhì)量,值越大壓縮率越大,編碼后的數(shù)據(jù)量越小,但解碼后的圖像質(zhì)量也越差。
imdecode從緩存區(qū)讀取圖像數(shù)據(jù),通過(guò)指定標(biāo)識(shí),可以實(shí)現(xiàn)指定的解碼格式。imdecode的函數(shù)原型為cv2.imdecode(buf, flags) → retval ,其中flags指定圖像的讀取類型,實(shí)際上就是指定了以多少深度多少通道讀取圖像,比如CV_LOAD_IMAGE_ANYDEPTH(即整數(shù)2)表示單個(gè)通道,深度不變的灰度圖;CV_LOAD_IMAGE_COLOR(即整數(shù)1)表示3通道、8位深度的彩色圖。
3 樹(shù)莓派程序
結(jié)合套接字對(duì)象和編解碼函數(shù),就可以編寫(xiě)發(fā)送端的代碼了,不過(guò)還有一個(gè)需要注意的地方是發(fā)送和接收的數(shù)據(jù)格式問(wèn)題,套接字的發(fā)送和接收都是字節(jié)流,或者說(shuō)是byte數(shù)組,發(fā)送數(shù)據(jù)時(shí)需要以字節(jié)流格式發(fā)送,接收數(shù)據(jù)后需要把字節(jié)流類型轉(zhuǎn)換成合適的數(shù)據(jù)類型。
從攝像頭獲取的圖像是480X640X3的numpy.ndarray類型,通過(guò)imencode編碼,得到?X1的numpy.ndarray對(duì)象,經(jīng)測(cè)試,這個(gè)對(duì)象可以直接發(fā)送出去;在接收端,獲得的是byte數(shù)組,這個(gè)數(shù)組直接做imdecode的參數(shù)會(huì)報(bào)錯(cuò),經(jīng)調(diào)試,發(fā)現(xiàn)還需要把數(shù)組轉(zhuǎn)換成numpy.ndarray類型。樹(shù)莓派作為發(fā)送端,其Python代碼如下:
import cv2
import numpy
import socket
import struct
HOST='192.168.1.122'
PORT=9999
server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #socket對(duì)象
server.connect((HOST,PORT))
print('now starting to send frames...')
capture=cv2.VideoCapture(0) #VideoCapture對(duì)象,可獲取攝像頭設(shè)備的數(shù)據(jù)
try:
while True:
success,frame=capture.read()
while not success and frame is None:
success,frame=capture.read() #獲取視頻幀
result,imgencode=cv2.imencode('.jpg',frame,[cv2.IMWRITE_JPEG_QUALITY,50]) #編碼
server.sendall(struct.pack('i',imgencode.shape[0])) #發(fā)送編碼后的字節(jié)長(zhǎng)度,這個(gè)值不是固定的
server.sendall(imgencode) #發(fā)送視頻幀數(shù)據(jù)
print('have sent one frame')
except Exception as e:
print(e)
server.sendall(struct.pack('c',1)) #發(fā)送關(guān)閉消息
capture.release()
server.close()
在代碼中,首先把編碼后的字節(jié)長(zhǎng)度發(fā)送了過(guò)去,目的是讓接收端可以進(jìn)行簡(jiǎn)單的校驗(yàn),并且接收端可以據(jù)此判斷是否應(yīng)該關(guān)閉程序,相應(yīng)的,自定義單字節(jié)的1為關(guān)閉消息。
4 PC端程序
自己的電腦作為接收端,為了解碼數(shù)據(jù),需要把原始字節(jié)流轉(zhuǎn)成numpy.ndarray對(duì)象,代碼如下:
import cv2
import numpy
import socket
import struct
HOST='192.168.191.122'
PORT=9999
buffSize=65535
server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #創(chuàng)建socket對(duì)象
server.bind((HOST,PORT))
print('now waiting for frames...')
while True:
data,address=server.recvfrom(buffSize) #先接收的是字節(jié)長(zhǎng)度
if len(data)==1 and data[0]==1: #如果收到關(guān)閉消息則停止程序
server.close()
cv2.destroyAllWindows()
exit()
if len(data)!=4: #進(jìn)行簡(jiǎn)單的校驗(yàn),長(zhǎng)度值是int類型,占四個(gè)字節(jié)
length=0
else:
length=struct.unpack('i',data)[0] #長(zhǎng)度值
data,address=server.recvfrom(buffSize) #接收編碼圖像數(shù)據(jù)
if length!=len(data): #進(jìn)行簡(jiǎn)單的校驗(yàn)
continue
data=numpy.array(bytearray(data)) #格式轉(zhuǎn)換
imgdecode=cv2.imdecode(data,1) #解碼
print('have received one frame')
cv2.imshow('frames',imgdecode) #窗口顯示
if cv2.waitKey(1)==27: #按下“ESC”退出
break
server.close()
cv2.destroyAllWindows()
5 測(cè)試
因?yàn)槲覙?shù)莓派上的OpenCV只關(guān)聯(lián)了Python2,因此以python2 UDP_Frame_Send.py 的命令啟動(dòng)發(fā)送程序(接好攝像頭);電腦上,在開(kāi)始菜單中輸入cmd進(jìn)入Windows的控制臺(tái),進(jìn)入程序文件目錄,輸入python UDP_Frame_Recv.py啟動(dòng)接收程序,結(jié)果表明可以比較流暢地窗口顯示,不過(guò)有幾個(gè)問(wèn)題,一是在樹(shù)莓派上,程序有時(shí)候打不開(kāi)攝像頭,需要重啟幾次程序,二是在電腦上,recvfrom這個(gè)函數(shù)是阻塞式的,在Windows系統(tǒng)的控制臺(tái)中似乎沒(méi)辦法用鍵盤(pán)中斷強(qiáng)制從這個(gè)函數(shù)退出,所以如果發(fā)送端出錯(cuò)接收端的程序就沒(méi)法正常退出了,對(duì)此可以用TCP&UDP調(diào)試助手手動(dòng)發(fā)送單個(gè)字節(jié)的1來(lái)終止程序。
更多關(guān)于Python相關(guān)內(nèi)容可查看本站專題:《Python Socket編程技巧總結(jié)》、《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》、《Python入門(mén)與進(jìn)階經(jīng)典教程》及《Python文件與目錄操作技巧匯總》
希望本文所述對(duì)大家Python程序設(shè)計(jì)有所幫助。
- 為什么說(shuō)python更適合樹(shù)莓派編程
- 樹(shù)莓派升級(jí)python的具體步驟
- python3實(shí)現(xiàn)raspberry pi(樹(shù)莓派)4驅(qū)小車控制程序
- python3實(shí)現(xiàn)網(wǎng)頁(yè)版raspberry pi(樹(shù)莓派)小車控制
- 樹(shù)莓派4B+opencv4+python 打開(kāi)攝像頭的實(shí)現(xiàn)方法
- 樹(shù)莓派使用python-librtmp實(shí)現(xiàn)rtmp推流h264的方法
- 樹(shù)莓派與PC端在局域網(wǎng)內(nèi)運(yùn)用python實(shí)現(xiàn)即時(shí)通訊
- 樹(shù)莓派采用socket方式文件傳輸(python)
- 樹(shù)莓派用python中的OpenCV輸出USB攝像頭畫(huà)面
- python樹(shù)莓派紅外反射傳感器
- Python+樹(shù)莓派+YOLO打造一款人工智能照相機(jī)
- 在樹(shù)莓派2或樹(shù)莓派B+上安裝Python和OpenCV的教程
- Python實(shí)現(xiàn)樹(shù)莓派攝像頭持續(xù)錄像并傳送到主機(jī)的步驟
相關(guān)文章
python?pandas分割DataFrame中的字符串及元組的方法實(shí)現(xiàn)
本文主要介紹了python?pandas分割DataFrame中的字符串及元組的方法實(shí)現(xiàn),主要介紹了3種方法,具有一定的參考價(jià)值,感興趣的可以了解一下2022-03-03
MoviePy簡(jiǎn)介及Python視頻剪輯自動(dòng)化
MoviePy是一個(gè)用于視頻編輯的Python模塊,可用于基本操作(如剪切、拼接、字幕插入)、視頻合成、視頻處理或創(chuàng)建高級(jí)效果等。本文給大家介紹MoviePy簡(jiǎn)介及Python視頻剪輯自動(dòng)化的相關(guān)知識(shí),感興趣的朋友一起看看吧2020-12-12
一起來(lái)學(xué)習(xí)Python的元組和列表
這篇文章主要為大家詳細(xì)介紹了Python元組和列表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03
微信跳一跳python輔助軟件思路及圖像識(shí)別源碼解析
這篇文章主要介紹了微信跳一跳python輔助軟件思路及圖像識(shí)別源碼解析,需要的朋友可以參考下2018-01-01
Python學(xué)習(xí)之while 循環(huán)語(yǔ)句
這篇文章主要給大家介紹了關(guān)于Python中while循環(huán)語(yǔ)句的相關(guān)資料,使用while循環(huán)語(yǔ)句可以解決程序中需要重復(fù)執(zhí)行的操作,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-10-10
基于python-opencv3實(shí)現(xiàn)圖像顯示和保存操作
這篇文章主要介紹了基于python opencv3的圖像顯示和保存操作方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-06-06
文件上傳服務(wù)器-jupyter 中python解壓及壓縮方式
這篇文章主要介紹了文件上傳服務(wù)器-jupyter 中python解壓及壓縮方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-04-04

