使用python和树莓派实现远程监控
前言
前段時間因為各種雜事纏身,一直沒時間自己玩玩。今天元旦,打算給自己放個假,所以就尋思著玩玩手邊吃了幾個月灰的樹莓派?;诵r間自己寫了點代碼,實現了在樹莓派端啟動服務器,并實時將從連接到樹莓派的攝像頭讀取的數據傳輸到服務器上,在客戶端接收服務器的數據并實時顯示圖像。功能很簡單,代碼也很簡陋,希望勿噴。
我并沒有做完整圖像處理的功能,本來打算放yolo上去進行實時目標檢測,于是我試著在樹莓派上跑了yolo,但是跑一個epoch進行預測花了將近40s,這個速度太感人了,讓我完全打消了前面的年頭。不過如果在配置稍微好點的服務器上還是可行的,但是對于樹莓派也真的別期待有多好的效果了。
依賴庫
樹莓派(服務器端)
安裝系統
關于樹莓派的系統如何安裝我就不做介紹了,網上很多,也很容易。下面直接給個鏈接,照著做就是了:
https://www.cnblogs.com/suzhengsheng/p/5044924.html
安裝好官方的raspbian系統后,最好先更新一下(不是必須的):
安裝opencv
通常安裝opencv有兩種方式:使用apt-get直接從軟件源獲取編譯好的opencv,或是自己從官網下載源碼編譯后安裝。我個人比較喜歡后者,通常在自己的電腦上都會自己取編譯想要用的版本。但是在樹莓派上編譯著實比較麻煩,各種依賴庫的問題,如果不想折騰的話建議還是使用前者的方法。
sudo apt-get install libopencv-dev sudo apt-get install python-opencv安裝PIL
PIL(python image library)是十分好用的一個可用于python的圖像處理庫,后面要用到它進行圖像的壓縮。
sudo apt-get install python-imaging其他
如果還碰到其他的庫沒有的情況,請自行使用pip安裝。
客戶端
我的客戶端就是自己的筆記本,環境都是很早就配好的,因為經常用到opencv、numpy等庫??紤]到有些人的電腦可能沒有安裝好,所以還是簡要介紹一下。自己配開發環境是最基本的技能了。
numpy
太常用了,不過安裝是不要用pip來,可能會報錯,我通常是使用如下指令來安裝:
sudo apt-get install python-numpyPIL
指令同樹莓派。
sudo apt-get install python-imagingopencv
可以直接apt-get安裝,不過不能指定版本;我個人喜歡用opencv3.0以上的,所以是從源碼安裝的。相關安裝教程請問度娘,花些時間就能搞定。
其他
如果在后面運行程序時碰到了某些庫沒有,可以考慮用pip安裝或是向前面一樣使用sudo apt-get install python-(庫的名字)。
程序實現
使用python在本地讀取攝像頭并實時顯示
在進入正題之前,我們要先實現在本地讀取攝像頭,測試正常通過后再放到服務器上測試。
創建一個python腳本,名字為:local_camera.py,代碼如下:
程序很簡單,不多說了,運行通過后,再往下一步走。
數據源端
創建一個python腳本,名字為:src_camera,py,代碼如下:
import cv2 import time import socket import Image import StringIO# 獲取攝像頭 cap = cv2.VideoCapture(0) # 調整采集圖像大小為640*480 cap.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, 480)# 這里的HOST對應樹莓派的IP地址(自己輸入ifconfig查),端口號自己隨便定一個即可,但注意后面的程序中要保持統一 HOST, PORT = '192.168.0.113', 9999 # 連接服務器 sock =socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((HOST, PORT))while True:# 獲取一幀圖像ret, img = cap.read()# 如果ret為false,表示沒有獲取到圖像,退出循環if ret is False:print("can not get this frame")continue # 將opencv下的圖像轉換為PIL支持的格式pi = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))buf = StringIO.StringIO()# 緩存對象pi.save(buf, format='JPEG')# 將PIL下的圖像壓縮成jpeg格式,存入buf中jpeg = buf.getvalue()# 從buf中讀出jpeg格式的圖像buf.close()transfer = jpeg.replace('\n', '\-n')# 替換\n為\-n,因為后面傳輸時,終止的地方會加上\n,可以便于區分print len(transfer), transfer[-1]sock.sendall(transfer + "\n")# 通過socket傳到服務器# time.sleep(0.2)sock.close()這部分代碼實現的功能是:在樹莓派端讀取攝像頭,使用socket包連接到服務器,并將從攝像頭讀取的數據發送到服務器上。
注釋都在程序中。程序中我們使用socket包來將數據傳到服務器,為了減少數據量,所以我們還需要對原始圖像進行壓縮。而壓縮則是通過PIL將圖像壓縮成jpeg格式,而PIL支持的圖像格式與opencv不同,所以在程序中還對其進行了轉換。
服務器端
創建一個python腳本,名字為:server_camera,py,代碼如下:
import socket import timesock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(("192.168.0.113", 9999))# 注意bind的這里,IP地址和端口號都要與前面的程序中一樣 sock.listen(2)# 監聽端口# 等待數據源端連接 src, src_addr = sock.accept() print "Source Connected by", src_addr# 等待目標端連接 dst, dst_addr = sock.accept() print "Destination Connected by", dst_addrwhile True:msg = src.recv(1024 *1024)if not msg:breaktry:dst.sendall(msg)except Exception as ex:dst, dst_addr = sock.accept()print "Destination Connected Again by", dst_addrexcept KeyboardInterrupt:print "Interrupted"breaksrc.close() dst.close() sock.close()這個服務器端可以說是很簡陋了,整體流程是:監聽端口–>等待數據端連接–>等待目標端連接–>從數據端接受數據,轉發給目標端。
目標端(客戶端)
創建一個python腳本,名字為:dst_camera,py,代碼如下:
import cv2 import socket import time import Image import StringIO import numpy as np# 注意IP地址和端口號與前面的程序中的保持一致 HOST, PORT = "192.168.0.113", 9999 # 連接到服務器 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((HOST, PORT)) f = sock.makefile()cv2.namedWindow("camera")while True:# 從服務器讀取數據,一行的結尾是'\n',注意我們前面已經將每一幀數據的'\n'替換成'\-n',而結尾就是'\n'msg = f.readline()if not msg:breakprint len(msg), msg[-2]# 將'\-n'換回來成'\n'jpeg = msg.replace("\-n", "\n")buf = StringIO.StringIO(jpeg[0:-1])# 緩存數據buf.seek(0)pi = Image.open(buf)# 使用PIL讀取jpeg圖像數據# img = np.zeros((640, 480, 3), np.uint8)img = cv2.cvtColor(np.asarray(pi), cv2.COLOR_RGB2BGR)# 從PIL的圖像轉成opencv支持的圖像 buf.close()cv2.imshow("camera", img)# 實時顯示if cv2.waitKey(10) == 27:breaksock.close() cv2.destroyAllWindows()目標端,也可以說是客戶端,這是真正的我們可以看到實際輸出的部分了。從服務器讀出數據然后顯示即可。
運行結果
接下來看下運行結果了。
結果截圖:
數據源端和服務器端:
目標端:
我看了下,實時顯示的效果還行。如果你想要控制幀率,可以在src_camera.py中更改time.sleep(0.2)這句代碼的參數,來控制延時時間。
可能遇到的錯誤
對號入座:
- HIGHGUI ERROR: V4L: index 0 is not correct!:http://blog.csdn.net/youhongaa/article/details/55054970
- socket.error:[errno 99] cannot assign requested address and namespace in python:https://stackoverflow.com/questions/19246103/socket-errorerrno-99-cannot-assign-requested-address-and-namespace-in-python
參考資料:
樹莓派+python opencv實現遠程監控:寫的很不錯,但是它用的是老版本的opencv,不保證一定能運行成功。
總結
以上是生活随笔為你收集整理的使用python和树莓派实现远程监控的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 三维重建学习(2):相机标定基础
- 下一篇: 三维重建学习(3):张正友相机标定推导