前言
在做项目的时候,不同的程序负责不同的功能.但同时他们之间又是耦合的,一个程序的运行可能依赖于另一个程序的结果.以前都是基于ROS来完成这一工作,不过个人觉得ROS太笨重了,所以一直在找Python中有没有其它的工具能够实现同样的功能.经过各种搜索,自己稀里糊涂的用Redis完成了这一功能.
关于Redis能否像ROS一般的使用,我一直抱有疑问.但是当我在github上看到这个工作时,决定就用Redis的发布订阅功能来实现Python程序之间的通信.
Redis的安装与使用
Windows
安装redis,启动服务
去https://github.com/microsoftarchive/redis/releases下载zip安装包,解压即可。
然后将对应的路径添加到环境变量path中,就可以在cmd中使用命令redis-server
启动redis服务了
使redis成为Windows服务
由于上面虽然启动了redis服务,但是,只要一关闭cmd窗口,redis服务就关闭了。所以,把redis设置为一个windows服务。
Linux
TO DO
python使用redis服务
python使用redis服务时需要先安装redis包,pip install redis
具体实现
首先实现一个通用的类,用于实现发布订阅功能,内容如下:
import cv2
import redis, struct
import json
import numpy as np
def toRedisformat(data, datatype):
"""encode data to string format"""
if datatype == 'nparray':
h, w = data.shape[:2]
shape = struct.pack('>II', h, w)
encoded = shape + data.tobytes()
else:
encoded = json.dumps(data)
return encoded
def fromRedisFormat(data, datatype):
"""decode data"""
if datatype == 'nparray':
h, w = struct.unpack('>II', data[:8])
data = np.frombuffer(data, dtype=np.uint8, offset=8).reshape(h, w, 3)
else:
data = json.loads(data)
return data
class RedisCommunicator():
"""使用Redis进行发布订阅的类"""
def __init__(self, R, chn, datatype=None):
"""
初始化操作
:param R: Redis的池
:param chn: 通信的channel或者说话题
"""
self._Redis = R
self.chn = chn
self.subInited = False
self.datatype = datatype
def pub(self, data):
"""发送信息,借助json"""
data = toRedisformat(data, self.datatype)
self._Redis.publish(self.chn, data)
return True
def sub(self):
"""接收信息,借助json"""
if not self.subInited:
"""如果第一次接收,则初始化"""
self.subInited = True
self.subscriber = self._Redis.pubsub() # 打开收音机
self.subscriber.psubscribe(self.chn) # 调频道
self.subscriber.parse_response() # 准备接收, 再次调用parse_response开始接收
data = self.subscriber.get_message()
ret = False
if data:
ret = True
data = data['data']
data = fromRedisFormat(data, self.datatype)
return ret, data
其中,如果要存入Redis,内容必须字符串化.对于np array和其它类型数据,处理方式不同.处理np数组时,使用了struct包;处理其它数据类型时,使用了json包.
发布者的代码如下:
import redis
import cv2
from redis_utils import RedisCommunicator
RedisPool = redis.Redis(host='localhost', port=6379, db=0)
imgPubsub = RedisCommunicator(RedisPool, 'img', 'nparray')
cam = cv2.VideoCapture(0)
key = 0
while key != 27:
ret, img = cam.read()
imgPubsub.pub(img)
cv2.imshow('puber', img)
key = cv2.waitKey(1) & 0xFF
订阅者的代码如下:
import cv2
import redis
from redis_utils import RedisCommunicator
RedisPool = redis.Redis(host='localhost', port=6379, db=0)
imgPubsub = RedisCommunicator(RedisPool, 'img', 'nparray')
key = 0
while key != 27:
ret, img = imgPubsub.sub()
if ret:
cv2.imshow('suber1', img)
key = cv2.waitKey(1) & 0xFF
这样,就可以在不同的Python程序之间交换opencv的图像变量了,其它类型的数据同理.
评论(0)
您还未登录,请登录后发表或查看评论