如何在 C++ 中使用 ZeroMQ 通信多个图像?
Posted
技术标签:
【中文标题】如何在 C++ 中使用 ZeroMQ 通信多个图像?【英文标题】:How to communicate multiple images using ZeroMQ in C++? 【发布时间】:2019-10-24 02:39:15 【问题描述】:我想实现可以通过 ZeroMQ 通信多个图像的程序。 我可以使用 OpenCV 在 C++ 上显示多个图像,但我无法以某种方式在 Python 上显示,尽管编译器没有输出错误。
如何将多个图像从 C++ 传递到 Python?
C++ 代码:
Mat img0;
Mat img1;
Mat img2;
img0 = imread("images.jpeg");
img1 = imread("images1.jpeg");
img2 = imread("image2.jpg");
if(img0.empty()) return -1;
if(img1.empty()) return -1;
if(img2.empty()) return -1;
ShowManyImages("IMAGE",3,img0,img1,img2);
// Let structure for zeroMQ
int32_t info[3];
info[0] = (int32_t)img0.rows;
info[1] = (int32_t)img0.cols;
info[2] = (int32_t)img0.type();
info[3] = (int32_t)img1.rows;
info[4] = (int32_t)img1.cols;
info[5] = (int32_t)img1.type();
info[6] = (int32_t)img2.rows;
info[7] = (int32_t)img2.cols;
info[8] = (int32_t)img2.type();
zmq::context_t context (1);
zmq::socket_t socket (context, ZMQ_REQ);
socket.connect ("tcp://localhost:5555");
for(i=0; i<9; i++ )
zmq::message_t msg0 ( (void*)&info[i], sizeof(int32_t), NULL );
socket.send(msg0, ZMQ_SNDMORE);
void* data0 = malloc(img0.total() * img0.elemSize());
memcpy(data0, img0.data, img0.total() * img0.elemSize());
zmq::message_t msg00(data0, img0.total() * img0.elemSize(), my_free, NULL);
socket.send(msg00);
void* data1 = malloc(img1.total() * img1.elemSize());
memcpy(data1, img1.data, img1.total() * img1.elemSize());
zmq::message_t msg11(data1, img1.total() * img1.elemSize(), my_free, NULL);
socket.send(msg11);
void* data2 = malloc(img2.total() * img2.elemSize());
memcpy(data2, img2.data, img2.total() * img2.elemSize());
zmq::message_t msg22(data2, img2.total() * img2.elemSize(), my_free, NULL);
socket.send(msg22);
Python 代码:
import zmq
import cv2
import struct
import numpy as np
# Connection String
conn_str = "tcp://*:5555"
# Open ZMQ Connection
ctx = zmq.Context()
sock = ctx.socket(zmq.REP)
sock.bind(conn_str)
while(True):
# Receve Data from C++ Program
byte_rows, byte_cols, byte_mat_type, data= sock.recv_multipart()
# Convert byte to integer
rows = struct.unpack('i', byte_rows)
cols = struct.unpack('i', byte_cols)
mat_type = struct.unpack('i', byte_mat_type)
if mat_type[0] == 0:
# Gray Scale
image = np.frombuffer(data, dtype=np.uint8).reshape((rows[0],cols[0]))
else:
# BGR Color
image = np.frombuffer(data, dtype=np.uint8).reshape((rows[0],cols[0],3))
cv2.imshow('Python',image)
cv2.waitKey()
此致,
【问题讨论】:
您能否发布您从已发布的 C++/python 分布式计算代码模型中在 python 端收到的确切值? 我从REQ
修改为XREQ
。然后,我只能看到三个显示img0
的窗口。但我想观看显示每张图片的每个窗口,例如img0
,img1
,img2
。我认为这是sock.recv_multipart()
发生的,因为c++ 程序发送每个图像信息,我将Python 程序从byte_rows, byte_cols, byte_mat_type, data= sock.recv_multipart()
恢复到byte_rows0, byte_cols0, byte_mat_type0, byte_rows1, byte_cols1,byte_mat_type1, byte_rows2, byte_cols2, byte_mat_type2, data= sock.recv_multipart()
。我该如何解决这个问题?
【参考方案1】:
问:如何将多个图像从 C++ 传递到 Python?
上面的代码使用 REQ/REP
Scalable Formal Communication Pattern Archetype,但它不会尝试发送和 REP
-ly 到任何已经交付的 REQ
-est.
如果不尝试 .send()
和 REP
-ly,REQ
-方将永远无法发送任何下一条消息。
如果这是您第一次使用 ZeroMQ, 在深入了解更多细节之前,您可以先看看“ZeroMQ Principles in less than Five Seconds”
解决方案?
尽量使用 PUSH/PULL
原型,不需要响应。
接下来,尝试决定,仅使用第一张图像发送所有元数据是否是一个相当可靠的假设(我宁愿编写,最好使用符合struct.pack()/struct.unpack()
的 BLOB 和每个人中的所有byte_rows, byte_cols, byte_mat_type, data
,单个-frame,微不足道的消息负载映射)。
Python 端只会一步读取单帧 BLOB,可能会测试签名,如果需要,.unpack()
前导几个字节来学习图像大小,.unpack()
图像的“其余部分”-数据,你就完成了。这不是很可爱吗?
另外请注意,并非所有平台都共享相同类型的 Endian-ness(因此最好将您的 c 端代码设计为在“网络”中显式字节排序 -Endian 排序 :o)只是为了安全如果托管设备/平台进一步发展,下一次可能会变成不同的字节序。显式排序就是相同的显式排序,因为您的代码从第一天开始就坚持使用)
我明白了。所以你说我必须使用 PUSH/PULL 对吗?但我将我的程序从 C++ 中的 ZMQ_REQ 修改为 ZMQ_XREQ 并在 python 中从 zmq.REP 修改为 zmq.XREQ。然后,我可以在 python 中观看三个窗口,但只显示 img0。我知道这是因为 sock.recv_multipart() 而发生的。但我不知道如何修改它。我还应该使用 PUSH/PULL 来实现吗? – user36327 7 小时前
不,我没有告诉任何人必须使用PUSH/PULL
,这是一个人的建议,他从 v2.1+ 开始就使用 ZeroMQ
XREQ/XREP
有效地短路了理论上无限链 REQ.send()s-REP.recv()s-REP.send()s-REQ.recv 的 dFSA 步进()s-REQ...-REP...-REP...-REQ...-REQ...-...-[... ad-infinitum-or-deadlock, 以两者为准第一个 :o) ]
问题在于期望事情一定会发生,而这实际上不需要像预期的那样发生:
MASK = 'Python: The Image#0: was decoded to be 1:'
order_ORDER = 0
while( True ): # THIS WILL RUN FOREVER, WON'T IT?
#####################################################################################
order_ORDER += 1
#####################################################################################
( byte_rows, # EXPECTS ALL THIS TO .recv() EACH TIME
byte_cols, # EXPECTS ALL THIS TO .recv() EACH TIME
byte_mat_type, # EXPECTS ALL THIS TO .recv() EACH TIME
data # EXPECTS ALL THIS TO .recv() EACH TIME
) = sock.recv_multipart() # in Data from C++ Program
#####################################################################################
rows = struct.unpack( 'i', byte_rows) # EXPECTS THIS TO BE CORRECT EACH TIME
cols = struct.unpack( 'i', byte_cols) # EXPECTS THIS TO BE CORRECT EACH TIME
mat_type = struct.unpack( 'i', byte_mat_type) # EXPECTS THIS TO BE CORRECT EACH TIME
#####################################################################################
if mat_type[0] == 0: # IF mat_type[0] WAS == 0 ?in 2nd, 3rd?
# # # # # # # # # # # # # # # Gray Scale: # IF mat_type[0] WAS == 0 ?in 2nd, 3rd?
image = np.frombuffer( data,
dtype = np.uint8
).reshape( ( rows[0],
cols[0]
)
)
print "IMAGE WAS of TYPE == ZERO, HAVING SHAPE OF: ", image.shape, image.dtype
imgType = 'Grayscale'
else: # IF mat_type[0] WAS != 0 ?in 2nd, 3rd?
# # # # # # # # # # # # # # # # BGR Color # IF mat_type[0] WAS != 0 ?in 2nd, 3rd?
image = np.frombuffer( data,
dtype = np.uint8
).reshape( ( rows[0],
cols[0],
3
)
)
print "IMAGE WAS of TYPE != ZERO, HAVING SHAPE OF: ", image.shape, image.dtype
imgType = 'Blue-Green-Red'
###################################################################################
cv2.imshow( MASK.format( imgType, order_ORDER ), image )
cv2.waitKey()
###################################################################################
# LOOP AGAIN
###################################################################################
【讨论】:
我明白了。所以你说我必须使用PUSH/PULL
对吗?但我在 c++ 中将程序从 ZMQ_REQ
修改为 ZMQ_XREQ
,在 python 中从 zmq.REP
修改为 zmq.XREQ
。然后,我可以在 python 中观看三个窗口,但只显示img0
。我知道这是因为sock.recv_multipart()
而发生的。但我不知道如何修改它。我还应该使用PUSH/PULL
来实现吗?【参考方案2】:
我发现了几个问题。
您正在创建一个大小为 3 个整数的数组,然后将 9 个整数存储到其中
int32_t info[3];
您发送和接收的消息部分不匹配。
您按此顺序发送(末尾有 3 个数据)byte_rows, byte_cols, byte_mat_type, byte_rows, byte_cols, byte_mat_type,byte_rows, byte_cols, byte_mat_type, data, data, data
您按此顺序接收(每个元部分之后的数据)
byte_rows, byte_cols, byte_mat_type, data, byte_rows, byte_cols, byte_mat_type, data, byte_rows, byte_cols, byte_mat_type, data
【讨论】:
以上是关于如何在 C++ 中使用 ZeroMQ 通信多个图像?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 ZeroMQ 从 C# 客户端向 C++ 服务器发送消息