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

如何为外部启动的Python实例提供C程序的FITS图像数据访问权限?

跨平台实现C与Python共享内存处理图像的方案

核心思路

要让Python进程直接访问C程序中float* img的内存,跨平台的核心是共享内存机制,同时传递图像尺寸等元数据给Python脚本。下面分通用方案和分平台实现两种方式说明,针对你提到的“将每个像素除以2”的场景给出具体代码。


一、通用跨平台方案:共享内存+命令行传参

这种方式依赖Python 3.8+的multiprocessing.shared_memory,C侧通过系统调用创建共享内存区域,拷贝图像数据后启动Python进程,通过命令行传递共享内存名称、图像尺寸等参数。

C语言端实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <process.h>
#else
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif

// 跨平台创建共享内存
void* create_shared_memory(size_t size, const char* name, int* fd_or_handle) {
#ifdef _WIN32
    HANDLE hMapFile = CreateFileMapping(
        INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, name);
    if (hMapFile == NULL) return NULL;
    void* ptr = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, size);
    *fd_or_handle = (int)hMapFile;
    return ptr;
#else
    int fd = shm_open(name, O_CREAT | O_RDWR, 0666);
    if (fd == -1) return NULL;
    ftruncate(fd, size);
    void* ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    *fd_or_handle = fd;
    return ptr;
#endif
}

// 跨平台释放共享内存
void release_shared_memory(void* ptr, size_t size, int fd_or_handle, const char* name) {
#ifdef _WIN32
    UnmapViewOfFile(ptr);
    CloseHandle((HANDLE)fd_or_handle);
    DeleteFileA(name);
#else
    munmap(ptr, size);
    close(fd_or_handle);
    shm_unlink(name);
#endif
}

int main() {
    // 模拟图像数据
    int rx = 100, ry = 100, nchans = 3;
    size_t img_size = rx * ry * nchans * sizeof(float);
    float* img = malloc(img_size);
    // 初始化图像数据
    for (size_t i = 0; i < rx*ry*nchans; i++) {
        img[i] = i * 1.0f;
    }

    // 创建共享内存
    const char* shm_name = "FITS_IMAGE_SHM";
    int shm_handle;
    void* shm_ptr = create_shared_memory(img_size, shm_name, &shm_handle);
    if (!shm_ptr) {
        perror("Failed to create shared memory");
        free(img);
        return 1;
    }

    // 拷贝图像到共享内存
    memcpy(shm_ptr, img, img_size);

    // 构造Python执行命令
    char cmd[512];
    snprintf(cmd, sizeof(cmd), 
             "python image_processor.py %s %d %d %d", 
             shm_name, rx, ry, nchans);
    
    // 执行脚本并等待完成
    int ret = system(cmd);
    if (ret != 0) {
        fprintf(stderr, "Python script execution failed\n");
        release_shared_memory(shm_ptr, img_size, shm_handle, shm_name);
        free(img);
        return 1;
    }

    // 读取处理后的图像数据
    memcpy(img, shm_ptr, img_size);

    // 释放资源
    release_shared_memory(shm_ptr, img_size, shm_handle, shm_name);
    free(img);
    return 0;
}

Python脚本端(image_processor.py)

import sys
import numpy as np
from multiprocessing import shared_memory

def main():
    if len(sys.argv) != 5:
        print("Usage: python image_processor.py <shm_name> <rx> <ry> <nchans>")
        sys.exit(1)
    
    shm_name = sys.argv[1]
    rx = int(sys.argv[2])
    ry = int(sys.argv[3])
    nchans = int(sys.argv[4])
    total_elements = rx * ry * nchans

    # 连接共享内存
    shm = shared_memory.SharedMemory(name=shm_name)
    # 创建numpy数组直接映射共享内存(无拷贝)
    img_array = np.ndarray((rx, ry, nchans), dtype=np.float32, buffer=shm.buf)

    # 执行处理:每个元素除以2
    img_array /= 2.0

    # 关闭共享内存
    shm.close()

if __name__ == "__main__":
    main()

二、分平台优化方案

Linux/macOS:直接传递内存指针

类Unix系统中父子进程共享内存空间,可通过fork启动Python进程并直接传递指针地址,无需拷贝数据。

C端示例

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main() {
    int rx = 100, ry = 100, nchans = 3;
    size_t img_size = rx * ry * nchans * sizeof(float);
    float* img = malloc(img_size);
    for (size_t i = 0; i < rx*ry*nchans; i++) {
        img[i] = i * 1.0f;
    }

    pid_t pid = fork();
    if (pid == 0) {
        // 子进程启动Python脚本
        char ptr_str[64], rx_str[16], ry_str[16], nchans_str[16];
        snprintf(ptr_str, sizeof(ptr_str), "%p", img);
        snprintf(rx_str, sizeof(rx_str), "%d", rx);
        snprintf(ry_str, sizeof(ry_str), "%d", ry);
        snprintf(nchans_str, sizeof(nchans_str), "%d", nchans);
        execlp("python", "python", "image_processor_unix.py", 
               ptr_str, rx_str, ry_str, nchans_str, NULL);
        perror("execlp failed");
        exit(1);
    } else if (pid > 0) {
        // 父进程等待子进程完成
        wait(NULL);
        printf("First element after processing: %f\n", img[0]);
        free(img);
    } else {
        perror("fork failed");
        free(img);
        return 1;
    }
    return 0;
}

Python脚本(image_processor_unix.py)

import sys
import numpy as np
import ctypes

def main():
    if len(sys.argv) != 5:
        print("Usage: python image_processor_unix.py <ptr_addr> <rx> <ry> <nchans>")
        sys.exit(1)
    
    ptr_addr = int(sys.argv[1], 16)
    rx = int(sys.argv[2])
    ry = int(sys.argv[3])
    nchans = int(sys.argv[4])
    total_elements = rx * ry * nchans

    # 将地址转为float数组指针
    img_ptr = ctypes.cast(ptr_addr, ctypes.POINTER(ctypes.c_float * total_elements))
    # 转为numpy数组直接映射内存
    img_array = np.ctypeslib.as_array(img_ptr.contents).reshape((rx, ry, nchans))

    # 处理:除以2
    img_array /= 2.0

if __name__ == "__main__":
    main()

Windows:命名管道传递内存映射句柄

Windows下可通过命名管道传递内存映射文件的句柄,Python用ctypes获取句柄并映射内存,逻辑与通用方案一致,可直接复用通用方案代码。


注意事项

  • Python版本要求:通用方案需Python 3.8及以上,因为multiprocessing.shared_memory是3.8版本引入的
  • 内存同步:必须等待Python进程处理完成后,C程序再读取共享内存,避免竞态条件
  • 权限问题:Windows下共享内存名称需加Global\前缀以全局可见,Linux/macOS下名称长度不能超过限制
  • astropy集成:Python脚本中可直接用astropy.io.fits读写FITS文件,或基于映射的numpy数组做进一步处理

内容的提问来源于stack exchange,提问作者Adrian K-B.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:35:23