自動跟隨機器人教程(五)軟體部分 樹莓派+電腦 攝像頭影象回傳
阿新 • • 發佈:2019-02-10
既然你熟悉了Socket程式設計,也可以另外再寫一個類似的簡易伺服器客戶端程式。樹莓派仍然作為伺服器,電腦仍然作為客戶端。只不過現在是樹莓派發送,電腦接收。這時的資料不再是控制指令,而是樹莓派USB攝像頭獲得的影象資料。(通過Opencv和python-imaging庫實現)這個程式可以與上一篇的程式同時執行,只需要用兩個獨立的埠就行。
程式的基本實現方式是通過opencv的庫把攝像頭獲取到的每一幅影象轉化為String,再利用python-imaging的壓縮為jpeg格式,然後用socket發出去。電腦收到每一小段資料後再把每一段的String轉為一楨影象,並顯示在視窗中。(你所看到的視訊,其實就是不停運動著的照片)。
如果熟悉Opencv的話,可以在這裡對影象進行處理,比如用haarcascade做一下影象識別(人臉識別、人體識別),既可以在傳送前,在樹莓派上就處理影象,也可以傳送後在電腦上進行處理。
由於本專案的最終要求是機器人要獨立執行,因此建議大部分處理在樹莓派上做,這樣就要考慮效能問題。樹莓派雖然能用haarcascade做人臉識別或者人體識別(上半身),但是效能還不夠,能達到的幀率較低,所以最終還是採用了顏色識別。實際執行效果更流暢,這個後面會詳細講到。
執行在小車樹莓派上的程式碼:
#!/usr/bin/python import socket, time import cv import cv2 import Image, StringIO #capture = cv.CaptureFromCAM(0) #cv.SetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH, 320) #cv.SetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT, 240) cap=cv2.VideoCapture(0) ret=cap.set(3,320) ret=cap.set(4,240) sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.bind(("0.0.0.0", 9996)) sock.listen(2) dst, dst_addr = sock.accept() print "Destination Connected by", dst_addr while True: #img = cv.QueryFrame(capture) ret, frame = cap.read() img=cv.fromarray(frame) pi = Image.fromstring("RGB", cv.GetSize(img), img.tostring()) buf = StringIO.StringIO() pi.save(buf, format = "JPEG") jpeg = buf.getvalue() buf.close() transfer = jpeg.replace("\n", "\-n") #print len(transfer), transfer[-1] try: dst.sendall(transfer + "\n") time.sleep(0.04) except Exception as ex: dst, dst_addr = sock.accept() print "Destination Connected Again By", dst_addr except KeyboardInterrupt: print "Interrupted" break dst.close() sock.close()
執行在電腦上的程式碼:
#!/usr/bin/python import cv2.cv as cv import cv2 import socket, time, Image, StringIO import numpy as np HOST, PORT = "10.0.1.13", 9996 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((HOST, PORT)) f = sock.makefile() cv.NamedWindow("camera_server") while True: msg = f.readline() if not msg: break jpeg = msg.replace("\-n", "\n") buf = StringIO.StringIO(jpeg[0:-1]) buf.seek(0) pi = Image.open(buf) img = cv.CreateImageHeader((320, 240), cv.IPL_DEPTH_8U, 3) cv.SetData(img, pi.tostring()) buf.close() frame_cvmat=cv.GetMat(img) frame=np.asarray(frame_cvmat) cv2.imshow('frame',frame) if cv2.waitKey(1)&0xFF ==ord('q'): break #cv.ShowImage("camera_server", img) #if cv.WaitKey(10) == 27: # break sock.close() cv.DestroyAllWindows()