当前位置: 首页 > article >正文

图像处理中实现 C++ 和 Python 的高效通信——Boost.Interprocess mmap

使用 Boost.Interprocess 在 C++ 端创建共享内存,并使用 Python 的 mmap 模块进行读写操作。


整体流程

  1. C++ 端

    • 创建共享内存并写入原始图像数据。
    • 等待 Python 端处理完成。
    • 从共享内存中读取处理后的图像数据。
  2. Python 端

    • 读取共享内存中的原始图像数据。
    • 处理图像(例如转换为灰度图)。
    • 将处理后的图像数据写回共享内存。

C++ 端代码

C++ 端负责创建共享内存、写入原始图像数据,并读取 Python 处理后的图像数据。

#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace boost::interprocess;

int main() {
    // 读取原始图像
    cv::Mat image = cv::imread("input.jpg", cv::IMREAD_COLOR);
    if (image.empty()) {
        std::cerr << "Failed to load image!" << std::endl;
        return -1;
    }

    // 共享内存名称
    const std::string shm_name = "SharedImageMemory";

    // 创建共享内存对象
    shared_memory_object shm(open_or_create, shm_name.c_str(), read_write);

    // 设置共享内存大小(原始图像 + 处理后的图像)
    size_t image_size = image.total() * image.elemSize();
    shm.truncate(image_size * 2);  // 两倍大小,分别存储原始图像和处理后的图像

    // 映射共享内存
    mapped_region region(shm, read_write);

    // 将原始图像数据写入共享内存的前半部分
    std::memcpy(region.get_address(), image.data, image_size);
    std::cout << "Original image data written to shared memory." << std::endl;

    // 等待 Python 端处理完成
    std::cout << "Waiting for Python to process the image..." << std::endl;
    std::cin.get();

    // 从共享内存的后半部分读取处理后的图像数据
    cv::Mat processed_image(image.size(), image.type());
    std::memcpy(processed_image.data, static_cast<char*>(region.get_address()) + image_size, image_size);

    // 保存处理后的图像
    cv::imwrite("output_processed.jpg", processed_image);
    std::cout << "Processed image saved to output_processed.jpg." << std::endl;

    // 清理共享内存
    shared_memory_object::remove(shm_name.c_str());
    return 0;
}

Python 端代码

Python 端负责读取共享内存中的原始图像数据,处理图像,并将处理后的图像数据写回共享内存。

import mmap
import numpy as np
import cv2

# 共享内存名称(与 C++ 端一致)
SHARED_MEMORY_NAME = "SharedImageMemory"

# 图像尺寸和类型(需要与 C++ 端一致)
IMAGE_WIDTH = 640  # 图像的宽度
IMAGE_HEIGHT = 480  # 图像的高度
IMAGE_CHANNELS = 3  # 图像的通道数(例如,3 表示 RGB 图像)

# 计算图像的总字节数
image_size = IMAGE_WIDTH * IMAGE_HEIGHT * IMAGE_CHANNELS

# 打开共享内存
with mmap.mmap(-1, image_size * 2, tagname=SHARED_MEMORY_NAME, access=mmap.ACCESS_WRITE) as shm:
    # 读取原始图像数据(共享内存的前半部分)
    image_data = shm.read(image_size)
    image_array = np.frombuffer(image_data, dtype=np.uint8)
    original_image = image_array.reshape((IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS))

    # 处理图像(例如转换为灰度图)
    processed_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)

    # 将处理后的图像数据写回共享内存的后半部分
    shm.seek(image_size)  # 移动到共享内存的后半部分
    shm.write(processed_image.tobytes())

    print("Processed image data written back to shared memory.")

运行步骤

  1. C++ 端

    • 编译并运行 C++ 程序。程序会将原始图像写入共享内存,并等待 Python 端处理。
  2. Python 端

    • 运行 Python 脚本。脚本会读取共享内存中的原始图像,处理图像,并将处理后的图像写回共享内存。
  3. C++ 端

    • 在 Python 端处理完成后,按 Enter 键继续运行 C++ 程序。程序会从共享内存中读取处理后的图像并保存。

关键点说明

  1. 共享内存布局
    • 共享内存的前半部分存储原始图像,后半部分存储处理后的图像。
  2. 同步机制
    • 示例中使用简单的 std::cin.get() 等待用户输入作为同步机制。在实际应用中,可以使用更复杂的同步机制(如信号量或互斥锁)。
  3. 共享内存清理
    • C++ 端在程序结束前调用 shared_memory_object::remove 清理共享内存。
  4. 共享内存名称
    • C++ 和 Python 必须使用相同的共享内存名称(如 SharedImageMemory)。
  5. 图像尺寸和类型
    • Python 端需要知道图像的宽度、高度和通道数,以便正确解析共享内存中的数据。
  6. 共享内存大小
    • C++ 端通过 shm.truncate() 设置共享内存的大小,Python 端需要确保读取的字节数与 C++ 端一致。
  7. 数据格式
    • 共享内存中的数据是原始的字节流,Python 端需要使用 np.frombuffer 将其转换为 NumPy 数组,并重塑为图像形状。
  8. 同步
    • 在实际应用中,可能需要额外的同步机制(如信号量或互斥锁)来确保 C++ 和 Python 之间的数据一致性。

注意事项

  • 确保 C++ 和 Python 端的图像尺寸、通道数和数据类型一致。
  • 在实际应用中,可能需要处理更复杂的图像数据(如多通道、浮点类型等)。
  • 如果需要更高的性能,可以考虑使用 ZeroMQ 或 gRPC 等网络通信方式。

http://www.kler.cn/a/500661.html

相关文章:

  • 【物联网原理与运用】知识点总结(上)
  • 嵌入式Linux之文件IO
  • 【2024年华为OD机试】 (A卷,100分)- 二元组个数(Java JS PythonC/C++)
  • 【云计算】OpenStack云计算平台
  • 鸿蒙UI(ArkUI-方舟UI框架)
  • 大数据智能选课系统
  • 【Uniapp-Vue3】插槽Slots及具名插槽实现组件高度定制化
  • [SAP ABAP] APPEND INITIAL LINE 追加空行
  • 苍穹外卖08——(涉及接收日期格式数据、ApachePOI导出报表、sql获取top10菜品数据)
  • doris:模型注意事项
  • npm 与 pnpm:JavaScript 包管理工具的对比与选择
  • 泛目录和泛站有什么差别
  • 跳表和Mysql联合索引的最左原则和索引下推的优化
  • 禅道使用实践(2)-产品篇
  • Golang笔记——rune和byte
  • Linux 容器漏洞
  • Spark Streaming专题
  • MySQL面试题--最最最详细MySQL面试题和解答
  • React中透过render函数学习(一)——workInProgress与双缓存机制
  • 现代 CPU 的高性能架构与并发安全问题
  • 【ESP32】ESP-IDF开发 | WiFi开发 | 基站模式 + AP扫描和AP连接例程
  • iOS实际开发中使用Alamofire实现多文件上传(以个人相册为例)
  • Kafka 主题管理
  • Java面试核心知识4
  • 系统架构设计师考点—信息安全和网络安全
  • 若依前后端分离项目部署