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

news2025/1/13 12:32:14

使用 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.coloradmin.cn/o/2275962.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RK3568 Android 13 内置搜狗输入法小计

问&#xff1a;为什么写&#xff1f; 答&#xff1a;网上搜出来的都试过了&#xff0c;不行&#xff01;下面直接上代码和注意事项&#xff01; 首先到这个目录&#xff08;/RK3568/Rockchip_Android13_SDK_Release/device/rockchip/rk356x/tl3568_evm/preinstall&#xff09…

【opencv】第8章 图像轮廓与图像分割修复

8.1 查找并绘制轮廓 一个轮廓一般对应一系列的点&#xff0c;也就是图像中的一条曲线。其表示方法可能 根据不同的情况而有所不同。在OpenCV 中&#xff0c;可以用findContours()函数从二值图 像中查找轮廓 8.1.1 寻找轮廓&#xff1a; findContours() 函数 findContours) 函…

BGP 泄露

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 目录 1. BGP 是什么&#xff1f; 2. 什么是 BGP 泄露&#xff1f; 3. 今天发生了什么&#xff1f; 4. 正常和被劫持状态下的路由示意图 5. 受影响区域 6. 责任在谁&#xff1f; 7. 有办法避免这…

数据结构与算法之二叉树: LeetCode 572. 另一棵树的子树 (Ts版)

另一棵树的子树 https://leetcode.cn/problems/subtree-of-another-tree/description/ 描述 给你两棵二叉树 root 和 subRoot检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false二叉树 tree …

动植物基因表达调控

1&#xff0c; on and off状态 以及表达的量 2&#xff0c; 基因调控的生物学影响&#xff1f; 超过400多种细胞类型&#xff0c;数目上37万亿 不是所有的基因都表达 为什么多核真核细胞需要基因调控&#xff1f; 单个细胞往多个细胞逐渐进化的过程&#xff0c;形成复杂的…

FreePBX 17 on ubuntu24 with Asterisk 20

版本配置&#xff1a; FreePBX 17&#xff08;最新&#xff09; Asterisk 20&#xff08;最新Asterisk 22&#xff0c;但是FreePBX 17最新只支持Asterisk 21&#xff0c;但是21非LTS版本&#xff0c;所以选择Asterisk 20&#xff09; PHP 8.2 Maria DB (v10.11) Node J…

“AI智能服务平台系统,让生活更便捷、更智能

大家好&#xff0c;我是资深产品经理老王&#xff0c;今天咱们来聊聊一个让生活变得越来越方便的高科技产品——AI智能服务平台系统。这个系统可是现代服务业的一颗璀璨明珠&#xff0c;它究竟有哪些魅力呢&#xff1f;下面我就跟大家伙儿闲聊一下。 一、什么是AI智能服务平台系…

Qt监控系统远程网络登录/请求设备列表/服务器查看实时流/回放视频/验证码请求

一、前言说明 这几个功能是近期定制的功能&#xff0c;也非常具有代表性&#xff0c;核心就是之前登录和设备信息都是在本地&#xff0c;存放在数据库中&#xff0c;数据库可以是本地或者远程的&#xff0c;现在需要改成通过网络API请求的方式&#xff0c;现在很多的服务器很强…

【网络协议】动态路由协议

前言 本文将概述动态路由协议&#xff0c;定义其概念&#xff0c;并了解其与静态路由的区别。同时将讨论动态路由协议相较于静态路由的优势&#xff0c;学习动态路由协议的不同类别以及无类别&#xff08;classless&#xff09;和有类别&#xff08;classful&#xff09;的特性…

安装完docker后,如何拉取ubuntu镜像并创建容器?

1. 先docker拉取ubuntu镜像 docker search ubuntu #搜索ubuntu 镜像 docker pull ubuntu:22.04 #拉取ubuntu 镜像 docker images #下载完成后&#xff0c;查看已经下载的镜像 docker run --name ubuntu_container -dit ubuntu:22.04 /bin/bash # docker container -l 2.…

互联网全景消息(10)之Kafka深度剖析(中)

一、深入应用 1.1 SpringBoot集成Kafka 引入对应的依赖。 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupI…

React Fiber框架中的Render渲染阶段——workLoop(performUnitOfWork【beginWork与completeWork】)

触发渲染过程——renderRoot renderRoot 是一个函数&#xff0c;用于触发渲染工作。它通常会调用并递归地执行一系列的渲染任务&#xff0c;直到完成整个更新过程。这个过程包括执行 Fiber 树中的 beginWork 和 completeWork&#xff0c;以及渲染新状态或 DOM。 function ren…

STM32F1学习——ADC模数转换器

一、ADC模数转换器 ADC的全称 Analog-Digital Converter 模拟-数字转换器&#xff0c;他可以用来将引脚上连续变换的模拟电压转换为内存中存储的数字变量。 ADC有两个重要指标&#xff0c;分辨率和频率。 STM32的ADC是 12位 逐次逼近型&#xff0c;1us转换时间&#xff0c;也就…

[每周一更]-(第131期):Go并发协程总结篇

Go语言的并发是通过协程&#xff08;goroutine&#xff09;实现的。Go协程是轻量级的线程&#xff0c;允许多个任务同时执行&#xff0c;且Go运行时会高效地管理它们。在Go中使用并发协程的方式非常简便&#xff0c;也很强大。以下是一些关于Go协程的基础用法和并发控制方法&am…

Ecdsa密钥在线生成工具

具体前往&#xff1a;ECC公钥私钥对在线生成器

llama.cpp 模型可视化工具 GGUF Visualizer

llama.cpp 模型可视化工具 GGUF Visualizer 1. GGUF Visualizer for VS Code (gguf-viz)1.1. Features1.2. Extension Settings References GGUF Visualizer https://marketplace.visualstudio.com/items?itemNameAgainstEntropy.gguf-viz 1. GGUF Visualizer for VS Code (g…

【DAPM杂谈之三】DAPM的初始化流程

本文主要分析DAPM的设计与实现 内核的版本是&#xff1a;linux-5.15.164&#xff0c;下载链接&#xff1a;Linux内核下载 主要讲解有关于DAPM相关的知识&#xff0c;会给出一些例程并分析内核如何去实现的 /**************************************************************…

HarmonyOS:@LocalBuilder装饰器: 维持组件父子关系

一、前言 当开发者使用Builder做引用数据传递时&#xff0c;会考虑组件的父子关系&#xff0c;使用了bind(this)之后&#xff0c;组件的父子关系和状态管理的父子关系并不一致。为了解决组件的父子关系和状态管理的父子关系保持一致的问题&#xff0c;引入LocalBuilder装饰器。…

Pytorch导出onnx模型并在C++环境中调用(含python和C++工程)

Pytorch导出onnx模型并在C环境中调用&#xff08;含python和C工程&#xff09; 工程下载链接&#xff1a;Pytorch导出onnx模型并在C环境中调用&#xff08;python和C工程&#xff09; 机器学习多层感知机MLP的Pytorch实现-以表格数据为例-含数据集和PyCharm工程中简单介绍了在…

git打补丁

1、应用场景 跨仓库升级 开发项目B使用的是开源项目A。开源项目A发现漏洞&#xff0c;作者进行了修复&#xff0c;我们可以通过使用git补丁的方式&#xff0c;将作者修改的内容复制到我 们的项目B中。 2、TortoiseGit方式 源仓库 格式化补丁 根据提交数量&#xff0c;生成…