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

如何通过ctypes将C++端OpenCV3的cv::Mat转为Python的Numpy数组并显示?

用ctypes将C++ OpenCV的cv::Mat转为Python Numpy数组并显示

我来帮你搞定这个跨语言图像转换的问题!结合你提到的两个导出函数,咱们分步骤实现,避开那些容易踩的坑。

第一步:确认C++端导出函数的正确性

首先要确保你的C函数是C语言调用约定导出的,不然ctypes会找不到函数名(C的名字修饰会搞乱函数名)。另外,建议把cv::Mat的type也返回,因为Numpy需要知道数据类型和通道数才能正确解析。

示例C++代码(适配你的共享内存逻辑):

#include <opencv2/opencv.hpp>
#include <cstdint>

// 假设这是你从共享内存读取到的图像,要确保它在Python使用期间不会被释放
cv::Mat g_shared_mat;

// 用extern "C"导出C风格函数,避免名字修饰
extern "C" {
    // 定义存储cv::Mat属性的结构体
    struct MatProperties {
        int rows;          // 图像高度
        int cols;          // 图像宽度
        size_t step;       // 每行字节数(含对齐)
        int mat_type;      // cv::Mat的type,比如CV_8UC3
    };

    // 导出获取属性的函数
    __declspec(dllexport) MatProperties get_mat_properties() {
        MatProperties props;
        props.rows = g_shared_mat.rows;
        props.cols = g_shared_mat.cols;
        props.step = g_shared_mat.step;
        props.mat_type = g_shared_mat.type();
        return props;
    }

    // 导出获取数据指针的函数
    __declspec(dllexport) uint8_t* get_mat_data() {
        return g_shared_mat.data;
    }
}

注意:__declspec(dllexport)是Windows下的导出标记,Linux/macOS下编译时加上-fPIC -shared参数即可,不需要这个标记。

第二步:Python端实现转换与显示

在Python里,我们用ctypes对接C++函数,再用Numpy直接映射C内存(避免拷贝,提升效率),最后显示图像。

示例Python代码:

import ctypes
import numpy as np
import cv2

# 1. 定义与C++对应的结构体类型
class MatProperties(ctypes.Structure):
    _fields_ = [
        ("rows", ctypes.c_int),
        ("cols", ctypes.c_int),
        ("step", ctypes.c_size_t),
        ("mat_type", ctypes.c_int)
    ]

# 2. 加载共享库(Windows用.dll,Linux用.so,macOS用.dylib)
lib = ctypes.CDLL("./your_shared_lib.so")  # 替换成你的库路径

# 3. 声明函数的返回类型,让ctypes正确解析返回值
lib.get_mat_properties.restype = MatProperties
lib.get_mat_data.restype = ctypes.POINTER(ctypes.c_uint8)

# 4. 获取图像属性和数据指针
props = lib.get_mat_properties()
data_ptr = lib.get_mat_data()

# 5. 将C内存映射为Numpy数组(无拷贝,直接使用原内存)
# 先创建一个ctypes数组,再转成Numpy数组
total_bytes = props.step * props.rows
c_buffer = ctypes.cast(data_ptr, ctypes.POINTER(ctypes.c_uint8 * total_bytes))[0]
img_raw = np.frombuffer(c_buffer, dtype=np.uint8)

# 6. 根据cv::Mat的type解析出正确的图像形状和通道数
# 从mat_type中提取深度和通道数
depth = props.mat_type & 0xFF
channels = 1 + (props.mat_type >> 8) & 0xFF

# 处理不同通道的情况
if channels == 1:
    # 单通道:直接截取每行有效宽度(排除对齐的额外字节)
    img_np = img_raw.reshape((props.rows, props.step))[:, :props.cols]
elif channels == 3:
    # 三通道:先截取有效字节,再转成(height, width, 3)的形状
    valid_bytes = props.cols * channels
    img_np = img_raw.reshape((props.rows, props.step))[:, :valid_bytes].reshape((props.rows, props.cols, channels))
    # 如果用cv2.imshow可以跳过这个转换;如果用matplotlib显示,需要转BGR到RGB
    img_np = cv2.cvtColor(img_np, cv2.COLOR_BGR2RGB)

# 7. 显示图像
cv2.imshow("Shared Memory Image", img_np)
cv2.waitKey(0)
cv2.destroyAllWindows()

关键注意事项

  • 内存生命周期:必须保证Python使用图像期间,C++端的g_shared_mat不能被释放或覆盖,否则Python里的Numpy数组会变成野指针,导致程序崩溃或显示乱码。
  • 数据类型适配:如果你的cv::Mat不是8位无符号类型(比如CV_16UC1或CV_32FC3),需要修改Numpy的dtype:比如np.uint16对应16位无符号,np.float32对应32位浮点。
  • 字节对齐:OpenCV的step可能比cols*channels大(为了内存对齐提升效率),所以必须用step*rows计算总字节数,再截取有效部分,否则图像会出现错位。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:44:41