首页 > 解决方案 > 如何在 C++ 中使用 ZeroMQ 通信多个图像?

问题描述

我想实现可以通过 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);

蟒蛇代码:

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()

真挚地,

标签: pythonc++opencvzeromq

解决方案


如何将多个图像从 C++ 传递到 Python?

上面的代码使用REQ/REPScalable Formal Communication Pattern Archetype,但它不会尝试发送和REP-ly 到任何已经交付的REQ-est。

如果不尝试-ly,-side 将永远无法发送任何下一条消息.send()REPREQ

如果这是您使用ZeroMQ的第一次体验,
您可以在这里先看看“ ZeroMQ原则在不到5 秒内”,然后再深入了解更多细节。


解决方案 ?

尝试使用PUSH/PULL不需要响应的 Archetype。

接下来,尝试确定仅使用第一张图像发送所有元数据是否是一个合理稳健的假设(我宁愿编写,最好使用struct.pack()/struct.unpack()兼容的 BLOB 和byte_rows, byte_cols, byte_mat_type, data所有人,单帧,微不足道的消息有效负载映射)。

Python 端只需一步读取单帧 BLOB,可能会测试签名,如果需要,.unpack()前导几个字节来学习图像大小,.unpack()图像数据的“其余部分”,你就完成了。这不是很可爱吗?

另请注意,并非所有平台都共享相同类型的 Endian-ness(因此最好将您的 c 端代码设计为具有显式字节顺序的“网络”-Endian 顺序 :o)只是为了在托管时安全起见设备/平台进一步发展,下一次可能会变得具有不同的字节序。显式排序是相同的显式排序,因为您的代码自第 1 天以来一直坚持使用)


我懂了。所以你说我必须使用 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已经有效地短路了理论上无限链的 dFSA 步进 REQ.send()s-REP.recv()s-REP.send()s-REQ.recv()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
    ###################################################################################

推荐阅读