You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python生成图像写入内存,供C++ Qt程序读取的实现方案咨询

实现Matplotlib图像无硬盘中转至Qt程序的方案

完全可以实现无硬盘中转的图像传递,以下是几种可行方案:

一、同进程Python Qt直接读取内存图像

如果Qt程序基于Python(PyQt/PySide)开发,可直接在内存中传递图像数据,无需额外进程通信:

Python生成图像并传递到Qt的代码示例

import matplotlib.pyplot as plt
from io import BytesIO
from PyQt6.QtGui import QPixmap, QPainter
from PyQt6.QtWidgets import QWidget, QApplication
import sys

# 生成Matplotlib图像到内存缓冲区
def generate_graph_in_memory():
    x = [1, 2, 3, 4, 5]
    y = [2, 3, 5, 7, 11]
    plt.plot(x, y, marker="o", linestyle="-")
    
    # 将图像写入BytesIO内存缓冲区
    buffer = BytesIO()
    plt.savefig(buffer, format='png')
    buffer.seek(0)  # 重置缓冲区指针到开头
    plt.close()  # 关闭绘图释放资源
    return buffer

class GraphWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.image_buffer = generate_graph_in_memory()
        self.pixmap = QPixmap()
        self.pixmap.loadFromData(self.image_buffer.getvalue())

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawPixmap(0, 0, self.pixmap.scaled(self.size()))

if __name__ == "__main__":
    app = QApplication(sys.argv)
    widget = GraphWidget()
    widget.resize(400, 300)
    widget.show()
    sys.exit(app.exec())

二、跨进程(Python → C++ Qt)的内存传递方案

若Python生成图像、C++ Qt负责渲染,需通过**进程间通信(IPC)**实现内存级数据传递,常用方式如下:

1. 共享内存(Shared Memory)

利用Qt的QSharedMemory类和Python的multiprocessing.shared_memory模块实现内存共享:

Python端代码(写入共享内存)

import matplotlib.pyplot as plt
from io import BytesIO
from multiprocessing import shared_memory
import struct

def generate_and_write_shared_memory():
    # 生成图像到内存缓冲区
    x = [1, 2, 3, 4, 5]
    y = [2, 3, 5, 7, 11]
    plt.plot(x, y, marker="o", linestyle="-")
    buffer = BytesIO()
    plt.savefig(buffer, format='png')
    img_data = buffer.getvalue()
    plt.close()

    # 创建共享内存,先写入数据长度,再写入图像数据
    shm = shared_memory.SharedMemory(create=True, size=struct.calcsize('Q') + len(img_data))
    # 写入数据长度(8字节无符号整数)
    struct.pack_into('Q', shm.buf, 0, len(img_data))
    # 写入图像数据
    shm.buf[struct.calcsize('Q'):] = img_data

    # 输出共享内存名称,供C++ Qt端读取
    print(f"Shared Memory Name: {shm.name}")
    input("Press Enter to release shared memory...")
    shm.close()
    shm.unlink()

if __name__ == "__main__":
    generate_and_write_shared_memory()

C++ Qt端代码(读取共享内存)

#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QSharedMemory>
#include <cstdint>

class GraphWidget : public QWidget {
    Q_OBJECT
public:
    explicit GraphWidget(const QString& shmName, QWidget *parent = nullptr) : QWidget(parent) {
        QSharedMemory sharedMemory;
        sharedMemory.setKey(shmName);
        if (!sharedMemory.attach()) {
            qDebug() << "Failed to attach shared memory";
            return;
        }

        // 读取数据长度
        uint64_t dataLen = *reinterpret_cast<uint64_t*>(sharedMemory.data());
        // 读取图像数据
        QByteArray imgData(reinterpret_cast<char*>(sharedMemory.data()) + sizeof(uint64_t), dataLen);
        pixmap.loadFromData(imgData);

        sharedMemory.detach();
    }

protected:
    void paintEvent(QPaintEvent *event) override {
        QPainter painter(this);
        painter.drawPixmap(0, 0, pixmap.scaled(size()));
    }

private:
    QPixmap pixmap;
};

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    if (argc < 2) {
        qDebug() << "Usage: ./qt_graph_reader <shared_memory_name>";
        return 1;
    }
    GraphWidget w(argv[1]);
    w.resize(400, 300);
    w.show();
    return a.exec();
}

#include "main.moc"

2. 本地套接字(Socket)

通过本地套接字传递图像字节数据,避免硬盘写入:

Python端(本地Socket发送示例)

import matplotlib.pyplot as plt
from io import BytesIO
import socket

def generate_and_send_via_socket():
    # 生成图像到内存
    x = [1, 2, 3, 4, 5]
    y = [2, 3, 5, 7, 11]
    plt.plot(x, y, marker="o", linestyle="-")
    buffer = BytesIO()
    plt.savefig(buffer, format='png')
    img_data = buffer.getvalue()
    plt.close()

    # 本地Socket发送
    with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
        s.connect('./matplotlib_graph.sock')
        # 先发送数据长度,再发送数据
        s.sendall(len(img_data).to_bytes(8, byteorder='big'))
        s.sendall(img_data)

if __name__ == "__main__":
    generate_and_send_via_socket()

C++ Qt端(本地Socket接收示例)

#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QLocalSocket>
#include <QByteArray>
#include <cstdint>

class GraphWidget : public QWidget {
    Q_OBJECT
public:
    explicit GraphWidget(QWidget *parent = nullptr) : QWidget(parent) {
        QLocalSocket socket;
        socket.connectToServer("./matplotlib_graph.sock");
        if (!socket.waitForConnected()) {
            qDebug() << "Failed to connect to server";
            return;
        }

        // 读取数据长度
        uint64_t dataLen;
        socket.read(reinterpret_cast<char*>(&dataLen), sizeof(dataLen));
        dataLen = qFromBigEndian(dataLen);

        // 读取图像数据
        QByteArray imgData = socket.read(dataLen);
        pixmap.loadFromData(imgData);

        socket.disconnectFromServer();
    }

protected:
    void paintEvent(QPaintEvent *event) override {
        QPainter painter(this);
        painter.drawPixmap(0, 0, pixmap.scaled(size()));
    }

private:
    QPixmap pixmap;
};

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    GraphWidget w;
    w.resize(400, 300);
    w.show();
    return a.exec();
}

#include "main.moc"

三、无硬盘中转的替代方案

若共享内存/IPC实现复杂,可选用以下轻量方案:

  • Base64编码传递:Python将图像字节数据编码为Base64字符串,通过标准输出、RPC或消息队列传递给Qt程序,Qt解码后加载为图像
  • ZeroMQ消息库:利用ZeroMQ的IPC模式传递图像二进制数据,简化跨进程通信逻辑

内容的提问来源于stack exchange,提问作者Falesz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 02:23:16