Bootstrap

图像处理中实现 C++ 和 Python 的高效通信——ZeroMQ & protobuf

在开发需要 C++ 和 Python 交互的应用程序时,特别是对于图像处理等任务,建立有效的通信机制至关重要。将图像向量从 C++ 应用程序传输到 Python 应用程序进行推理,使用 ZeroMQ 进行进程间通信 (IPC),使用协议缓冲区 (protobuf) 进行序列化。

概述

解决方案涉及三个主要步骤:

  • 使用 protobuf 在 C++ 中序列化图像数据。
  • 使用 ZeroMQ 传输序列化数据。
  • 在 Python 中对图像数据进行反序列化和处理。

这种方法可确保高效的数据传输、同步和完整性,使其适用于实时或高性能应用程序。

1、 搭建 C++ 和 Python 开发环境

a. 安装 ZeroMQ 库

对于 C++,安装 ZeroMQ 库 (libzmq) 和 C++ 绑定 (cppzmq):

sudo apt install libzmq3-dev

对于 Python,安装 pyzmq 库:

pip install pyzmq

b. 协议缓冲区(protobuf)

为 C++ 和 Python 安装 protobuf 库,安装 protobuf 编译器 (protoc):

sudo apt install -y libprotobuf-dev protobuf-compiler
pip install protobuf

2、详细步骤

2.1 使用 Protobuf 在 C++ 中进行序列化

a. 定义 Protobuf 消息

首先,定义一个 protobuf 消息来表示一张图片和一个图片向量。将此定义保存在名为 image_vector.proto 的文件中:

// image_vector.proto
syntax = "proto3";

message Image {
    bytes data = 1;
    int32 width = 2;
    int32 height = 3;
    int32 channels = 4;
}

message ImageVector {
    repeated Image images = 1;
}
b. 生成 Protobuf 类

使用 protobuf 编译器从 .proto 文件生成 C++ 和 Python 类:

protoc --cpp_out=. image_vector.proto
protoc --python_out=. image_vector.proto
c. 在 C++ 中序列化图像

在您的 C++ 应用程序中,使用生成的 protobuf 类序列化图像向量。

2.2 使用 ZeroMQ 传输数据

ZeroMQ 简化了 C++ 和 Python 应用程序之间的数据传输。在这里,我们实现了一个 C++ 客户端和一个 Python 服务器。

a. C++ 客户端

C++ 客户端将图像序列化并发送到服务器:

#include <zmq.hpp>
#include <opencv2/opencv.hpp>
#include <fstream>
#include "image_vector.pb.h"

void send_images(const std::vector<cv::Mat>& images, zmq::socket_t& socket) {
    ImageVector image_vector;

    for (const auto& img : images) {
        Image* image = image_vector.add_images();
        image->set_data(img.data, img.total() * img.elemsize());
        image->set_width(img.cols);
        image->set_height(img.rows);
        image->set_channels(img.channels());
    }

    std::string serialized_data;
    image_vector.SerializeToString(&serialized_data);

    zmq::message_t request(serialized_data.size());
    memcpy(request.data(), serialized_data.data(), serialized_data.size());
    socket.send(request, zmq::send_flags::none);

    zmq::message_t reply;
    socket.recv(reply, zmq::recv_flags::none);
    std::string reply_str(static_cast<char*>(reply.data()), reply.size());
    std::cout << "Received reply: " << reply_str << std::endl;
}

int main() {
    zmq::context_t context(1);
    zmq::socket_t socket(context, ZMQ_REQ);
    socket.connect("tcp://localhost:5555");

    std::vector<cv::Mat> images = ...; // Your vector of images
    send_images(images, socket);

    return 0;
}
b. Python 服务器

Python 服务器接收序列化的图像、对其进行反序列化、处理并返回响应:

import zmq
import cv2
import numpy as np
from image_vector_pb2 import ImageVector

def process_images(images):
    processed_images = [cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) for img in images]
    return processed_images

def main():
    context = zmq.Context()
    socket = context.socket(zmq.REP)
    socket.bind("tcp://*:5555")

    while True:
        message = socket.recv()

        image_vector = ImageVector()
        image_vector.ParseFromString(message)

        images = []
        for image in image_vector.images:
            img_array = np.frombuffer(image.data, dtype=np.uint8)
            img = img_array.reshape((image.height, image.width, image.channels))
            images.append(img)

        processed_images = process_images(images)

        response = "Processed {} images".format(len(processed_images))
        socket.send_string(response)

if __name__ == "__main__":
    main()

3、结论

该解决方案利用 ZeroMQ 的高性能功能进行 IPC 和 protobuf 进行高效序列化,从而实现 C++ 和 Python 应用程序之间的无缝通信和同步。

;