既然你熟悉了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()