在某些应用场合咱们可能须要经过一个设备经过WIFI将图像传到其它的机器进行显示或者图形分析,那怎么能够低成本地实现呢?其实很简单,咱们只须要一块 Raspberry Zero W 和一个RPI 摄像头就好了,两个加起来成本也只不过150左右。python
这个组合不仅仅只是实现一个图传,最重要的是Raspberry Zero上运行的是Linux,它几乎能够运行咱们各类各样的代码。将它做为一个小型的编程平台也何尝不可。编程
因为硬件部分太简单了没有必要浪费篇幅过多地讲述,那就直接进入软件部分。实现图传必然有两端:发送端与接收端。网络
发送端 - 运行于Raspberry Zero经过OpenCV直接读取视频流,而后将数据写入到Socket中发送出去。若是实时传递的话可能会因为网络通讯等的各类缘由致使丢包,或者说因为失去有效的网络链接而引起程序的异常,为了防止这种状况出现我使用了pyzmq这个包,发送端也是消息的发布方,将Socket的处理放到消息队列中,当订阅方从消息队列中读取信息时就从Socket中拿出排队的数据,这样处理起来就平滑多了。socket
接收端 - 可运行于全部能运行python环境的平台,它只负责从Socket中读取流数据而后经过OpenCV显示到窗口中,也是消息的订阅方。tcp
Python 中的Socket使用能够说是在众多语言中最简单的,关于Socket的知识在此很少讲,不懂的朋友能够先去找些资料先学习一下。ide
发布方与订阅方都须要安装pyzmq:性能
$ pip install pyzmq
若是在树莓上安装pyzmq会很是慢可能要等个10来20分钟的,不要觉得你的树莓挂了只是Raspberry Zero性能实在过低要进行本机编译实在是一件很是痛苦之事。学习
Raspberry Zero 端的发布方的代码以下:ui
import base64 import cv2 import zmq context = zmq.Context() footage_socket = context.socket(zmq.PUB) footage_socket.connect('tcp://*:5555') camera = cv2.VideoCapture(0) while True: try: success, frame = camera.read() if not success: break; frame = cv2.resize(frame, (640, 480)) # 将每一帧的画面大小设置为640x480 encoded, buffer = cv2.imencode('.jpg', frame) jpg_as_text = base64.b64encode(buffer) footage_socket.send(jpg_as_text) except KeyboardInterrupt: camera.release() cv2.destroyAllWindows() break
原理很是简单就是将每一帧的画面先转成base64的编码格式以字符流的方式写入到socket中传出去。编码
运行代码:
pi $ python streamer.py
import cv2 import zmq import base64 import numpy as np context = zmq.Context() footage_socket = context.socket(zmq.SUB) footage_socket.bind('tcp://10.0.0.25:5555') # 这里须要指定Steamer的发地址 footage_socket.setsockopt_string(zmq.SUBSCRIBE, np.unicode('')) while True: try: source = footage_socket.recv_string() img = base64.b64decode(source) npimg = np.fromstring(img, dtype=np.uint8) frame = cv2.imdecode(npimg, 1) frame = cv2.flip(frame, flipCode=-1) cv2.imshow("Stream", frame) cv2.waitKey(1) except KeyboardInterrupt: cv2.destroyAllWindows() break