请输入
菜单

FIX Shared Memory DLL

作者: JT下载

FIX Shared Memory DLL

  • 通过共享内存与 FIX 检测软件进行进程间通信的开发包。
  • 通过动态链接库调用,纯 C API,无编译器版本限制。

与源码集成方案 (fixSharedMemory_src/) 的区别

FIX 同时提供了源码集成方案 (fixSharedMemory_src/),以下是两者的主要区别:

DLL 方案(本目录,推荐) 源码方案 (fixSharedMemory_src/)
集成方式 链接 .lib + 部署 .dll .h/.cpp 编译到自己项目中
API 风格 纯 C 函数 (extern "C"),opaque handle C++ 类 (fixSharedMemoryManager),std::function 回调
编译器要求 任意 C/C++ 编译器 需与 FIX 相同的 MSVC 版本(ABI 兼容)
语言兼容 C / C++ / C# (P/Invoke) / Python (ctypes) 等 仅 C++
外部依赖 无(FS_LOG_* 默认空操作)
接口复杂度 15 个函数,同步/异步二选一 底层接口,需自行管理共享内存读写细节
状态反馈 有完整的双向通信(见下) 单向发送,无返回状态
适用场景 大多数客户集成 需要深度定制或直接访问底层协议

关键改进:双向状态反馈

源码方案的 fixSharedMemoryManager单向通信——sendVolumeData() 仅返回数据是否成功写入共享内存(FSMemoryStatus),之后客户端无法得知 FIX 是否收到数据、处理是否成功、失败原因是什么。发送投影数据时,如果同时接收重建后的体数据,可以间接确认处理完成;但如果不需要接收体数据,或处理中途出错,客户端同样无法感知。

DLL 方案在内部自动建立了双向响应通道(response channel),解决了这些问题:

  • 同步 APISendVolumeAndWait / SendProjectionAndWait)阻塞等待直到 FIX 处理完成,返回完整结果:成功/失败状态码、错误消息文本、总耗时
  • 异步 APISendVolumeAsync / SendProjectionAsync)通过回调实时通知:处理进度(0%~100%)、完成/失败状态、错误消息
  • 无论发送体数据还是投影数据,都有一致的状态反馈机制
  • 超时自动检测,不会无限等待

不确定选哪个?选 DLL 方案——代码最少、集成最快、无编译器版本限制、有完整的状态反馈。

文件说明

复制代码
FIX安装目录/src/fixSharedMemory_dll/
  fixSharedMemory_api.h          <- 头文件(唯一需要 include 的文件)
  fixSharedMemoryDll.dll         <- 动态链接库
  fixSharedMemoryDll.lib         <- 导入库(链接用)
  fixSharedMemory_dll_README.md  <- 本文档
  example.cpp                    <- 完整示例代码
  main.cpp                       <- 测试程序源码(来自 test_fixSharedMemoryDll)
  test_fixSharedMemoryDll.exe    <- 预编译测试程序(可直接运行验证连接)

环境要求

  • Windows 10/11 x64
  • MSVC 2022(或任何支持 C/C++ 的 Windows 编译器)
  • 无其他第三方依赖

Visual Studio 项目配置

  1. 头文件路径:项目属性 → C/C++ → 常规 → 附加包含目录,添加 fixSharedMemory_api.h 所在路径
  2. 库文件路径:项目属性 → 链接器 → 常规 → 附加库目录,添加 fixSharedMemoryDll.lib 所在路径
  3. 链接库:项目属性 → 链接器 → 输入 → 附加依赖项,添加 fixSharedMemoryDll.lib
  4. 部署 DLL:将 fixSharedMemoryDll.dll 复制到可执行文件所在目录

也可以使用 #pragma comment(lib, "fixSharedMemoryDll.lib") 替代第 3 步。

所有文件在同一目录下,头文件和库路径可以指向同一个目录。

快速验证

安装后可直接运行 test_fixSharedMemoryDll.exe 验证与 FIX 软件的连接:

复制代码
test_fixSharedMemoryDll.exe -d E:\3D\data\tif -n myVolume -t teaching1 -r ResultPath -w 120
test_fixSharedMemoryDll.exe -d D:\data.raw -n rawVol -x 1536 -y 1536 -z 256
test_fixSharedMemoryDll.exe -d E:\3D\proj\tif -n PROJ1 -p --recon-config D:\rc.json -w 300

该测试程序支持 TIFF 文件夹和 RAW 文件两种数据输入方式,可指定体数据或投影数据模式。


快速上手(30 秒看完)

只需 3 个函数就能完成一次体数据检测:fsChannelCreatefsChannelSendVolumeAndWaitfsChannelDestroy

c 复制代码
#include "fixSharedMemory_api.h"
#pragma comment(lib, "fixSharedMemoryDll.lib")

int main(void)
{
    /* ① 连接 FIX 软件(确保 FIX 已启动) */
    FSChannelHandle ch = fsChannelCreate(NULL);
    if (!ch) {
        printf("连接失败! 请先启动 FIX 检测软件\n");
        return -1;
    }

    /* ② 发送体数据, 等待检测完成 */
    int ret = fsChannelSendVolumeAndWait(
        ch,
        myVolumeData,                /* 你的体数据指针 */
        "sample_001",                /* 给这份数据起个名字 */
        "TeachingFileName",          /* 教学文件名称, 没有就传 NULL */
        "D:\\Results",               /* 结果(Results, XML)保存到哪个文件夹, 不需要就传 NULL */
        256, 256, 100,               /* 宽, 高, 深度(切片数) */
        FS_IMAGE_C_GRAY16U,          /* 像素类型: 16位无符号 (最常用) */
        0.05, 0.05, 0.05,           /* 体素尺寸 X/Y/Z, 单位 mm */
        60000,                       /* 超时 60 秒, 传 0 也是 60 秒 */
        NULL, NULL, 0                /* 不需要详细结果, 全传 NULL/0 */
    );

    if (ret == FS_API_OK)
        printf("检测完成!\n");
    else
        printf("检测失败, 错误码: %d\n", ret);

    /* ③ 用完释放 */
    fsChannelDestroy(ch);
    return 0;
}

就这么简单。 下面的内容是进阶用法和参数详解,需要时再看。


完整代码示例

示例 A:最简同步检测(带错误信息)

c 复制代码
#include <stdio.h>
#include "fixSharedMemory_api.h"
#pragma comment(lib, "fixSharedMemoryDll.lib")

int doInspection(void* volumeData,
                 uint32_t width, uint32_t height, uint32_t depth)
{
    /* 连接 */
    FSChannelHandle ch = fsChannelCreate(NULL);
    if (!ch) {
        printf("连接失败! 请确认 FIX 软件已启动\n");
        return -1;
    }

    /* 发送并等待 */
    FSResultC result = {0};          /* 用于接收耗时等详细信息 */
    char msg[512] = {0};             /* 用于接收错误/完成消息文本 */

    int ret = fsChannelSendVolumeAndWait(
        ch,
        volumeData, "my_sample",
        "C:\\Teaching\\my.tch",      /* 教学文件, 没有传 NULL */
        "C:\\Results",               /* 结果目录, 不需要传 NULL */
        width, height, depth,
        FS_IMAGE_C_GRAY16U,          /* 16-bit 灰度, 最常见 */
        0.05, 0.05, 0.05,           /* 体素尺寸 mm */
        120000,                      /* 大数据建议加长超时 */
        &result,                     /* [输出] 详细结果 */
        msg, sizeof(msg)             /* [输出] 消息文本 */
    );

    /* 检查结果 */
    switch (ret) {
    case FS_API_OK:
        printf("检测完成! 耗时 %lld ms, 消息: %s\n",
               (long long)result.elapsedMs, msg);
        break;
    case FS_API_ERROR_TIMEOUT:
        printf("超时了! 已等待 %lld ms\n", (long long)result.elapsedMs);
        break;
    default:
        printf("失败! 错误码=%d, 消息: %s\n", ret, msg);
        break;
    }

    /* 释放 */
    fsChannelDestroy(ch);
    return ret;
}

示例 B:异步检测(不阻塞主线程)

c 复制代码
#include <stdio.h>
#include <windows.h>      /* Sleep */
#include "fixSharedMemory_api.h"
#pragma comment(lib, "fixSharedMemoryDll.lib")

/* === 回调函数 (DLL 内部线程调用, 不是主线程!) === */

void onProgress(uint32_t requestId, double progress,
                const char* message, void* userData)
{
    printf("进度: %.0f%% - %s\n", progress * 100.0, message ? message : "");
}

void onDone(uint32_t requestId, uint32_t taskStatus,
            const char* message, int64_t elapsedMs, void* userData)
{
    volatile int* flag = (volatile int*)userData;

    if (taskStatus == FS_TASK_C_COMPLETED)
        printf("完成! 耗时 %lld ms\n", (long long)elapsedMs);
    else
        printf("失败! 状态=%u, 消息: %s\n", taskStatus, message);

    *flag = 1;  /* 通知主线程 */
}

int main(void)
{
    /* 连接 */
    FSChannelHandle ch = fsChannelCreate(NULL);
    if (!ch) { printf("连接失败\n"); return -1; }

    /* 设置回调 */
    volatile int done = 0;
    fsChannelSetProgressCallback(ch, onProgress, NULL);
    fsChannelSetCompletionCallback(ch, onDone, (void*)&done);

    /* 发送 (立即返回, 不阻塞) */
    uint32_t reqId = fsChannelSendVolumeAsync(
        ch, myVolumeData, "sample",
        "C:\\Teaching\\my.tch", "C:\\Results",
        256, 256, 100, FS_IMAGE_C_GRAY16U,
        0.05, 0.05, 0.05);

    if (reqId == 0) {
        printf("发送失败: %s\n", fsChannelGetLastError(ch));
        fsChannelDestroy(ch);
        return -1;
    }

    printf("已发送, requestId=%u, 主线程可以做其他事...\n", reqId);

    /* 主线程等回调通知 (实际项目中用事件/消息循环代替) */
    while (!done) Sleep(100);

    fsChannelDestroy(ch);
    return 0;
}

示例 C:掉线重连

c 复制代码
FSChannelHandle ch = NULL;

/* 连接函数, 可反复调用 */
int connectToFIX(void)
{
    /* 如果旧句柄还在, 先释放 */
    if (ch) {
        fsChannelDestroy(ch);
        ch = NULL;
    }

    ch = fsChannelCreate(NULL);
    if (!ch) return -1;   /* FIX 没启动 */

    /* 重连后回调需要重新设置 */
    fsChannelSetProgressCallback(ch, onProgress, NULL);
    fsChannelSetCompletionCallback(ch, onDone, NULL);
    return 0;
}

/* 使用时: 发现断了就重连 */
void sendData(void* data, uint32_t w, uint32_t h, uint32_t d)
{
    if (!ch || !fsChannelIsConnected(ch)) {
        if (connectToFIX() != 0) {
            printf("FIX 未启动, 无法发送\n");
            return;
        }
    }
    fsChannelSendVolumeAsync(ch, data, "sample", NULL, NULL,
                             w, h, d, FS_IMAGE_C_GRAY16U,
                             0.05, 0.05, 0.05);
}

API 详细说明

1. 生命周期管理

fsChannelCreate

c 复制代码
FSChannelHandle fsChannelCreate(const char* serverName);

创建通道并连接到 FIX 服务端(一步到位)。内部自动分配资源、连接共享内存、启动接收线程。

参数 类型 说明
serverName const char* 要连接的共享内存名称。传 NULL 使用默认值 "FIXSharedMemory"(连接 FIX 检测软件)
返回值 说明
非 NULL 通道句柄,后续所有 API 调用都需要传入此句柄
NULL 连接失败(通常是 FIX 检测软件未启动),所有资源已自动释放

通常直接传 NULL 即可:fsChannelCreate(NULL)

如需重连,先 fsChannelDestroy 再重新 fsChannelCreate(回调需重新设置)。


fsChannelIsConnected

c 复制代码
int fsChannelIsConnected(FSChannelHandle handle);

检查通道是否已连接到服务端。

参数 类型 说明
handle FSChannelHandle 通道句柄(传 NULL 安全,返回 0)
返回值 说明
1 已连接
0 未连接或句柄无效

fsChannelDestroy

c 复制代码
void fsChannelDestroy(FSChannelHandle handle);

销毁通道,释放所有资源。调用后句柄不可再使用。传 NULL 是安全的(无操作)。


2. 同步 API(阻塞等待结果)

fsChannelSendVolumeAndWait

c 复制代码
int fsChannelSendVolumeAndWait(
    FSChannelHandle handle,
    const void* volumeData,
    const char* volumeName,
    const char* teachingFile,
    const char* resultPath,
    uint32_t width, uint32_t height, uint32_t depth,
    int imageType,
    double voxelSizeX, double voxelSizeY, double voxelSizeZ,
    uint32_t timeoutMs,
    FSResultC* outResult,
    char* outMsg, size_t msgBufSize);

发送 3D 体数据到 FIX 软件进行检测,阻塞等待处理完成后返回。

参数说明:

参数 类型 必填 说明
handle FSChannelHandle 通道句柄
volumeData const void* 体数据指针。数据在内存中按切片连续排列,即 slice[0] 的全部像素紧接着 slice[1],以此类推。总大小 = width x height x depth x 每像素字节数
volumeName const char* 体数据名称标识符,用于 FIX 软件内部区分不同数据
teachingFile const char* 教学文件路径。如果指定,FIX 会按此教学文件的配置进行检测。传 NULL 或空字符串表示不使用教学文件
resultPath const char* 检测结果保存目录。FIX 会将检测报告输出到此路径。传 NULL 或空字符串表示不保存
width uint32_t 体数据 X 维度(像素数)
height uint32_t 体数据 Y 维度(像素数)
depth uint32_t 体数据 Z 维度(切片数)
imageType int 像素类型,使用 FSImageTypeC 枚举值(见下方图像类型表)
voxelSizeX double X 方向体素物理尺寸,单位 mm
voxelSizeY double Y 方向体素物理尺寸,单位 mm
voxelSizeZ double Z 方向体素物理尺寸,单位 mm
timeoutMs uint32_t 超时时间(毫秒)。传 0 使用默认值 60000 (60 秒)。根据数据大小和检测复杂度适当调大
outResult FSResultC* [输出] 接收结果详情的结构体指针。可传 NULL 表示不关心
outMsg char* [输出] 接收状态消息的缓冲区。可传 NULL 表示不关心
msgBufSize size_t outMsg 缓冲区大小(字节),建议 512

返回值:

返回值 说明
FS_API_OK (0) 检测完成
FS_API_ERROR_INVALID_HANDLE (-1) 句柄无效
FS_API_ERROR_NOT_CONNECTED (-2) 未连接到服务端
FS_API_ERROR_INVALID_PARAM (-3) 参数错误(volumeData 为 NULL 或尺寸为 0)
FS_API_ERROR_SEND_FAILED (-4) 发送失败或服务端处理报错
FS_API_ERROR_TIMEOUT (-5) 等待超时

体数据内存布局:

复制代码
volumeData 指向的内存:

  偏移 0:                    slice[0] — width * height 个像素
  偏移 sliceSize:            slice[1]
  偏移 sliceSize * 2:        slice[2]
  ...
  偏移 sliceSize * (depth-1): slice[depth-1]

  sliceSize = width * height * bytesPerPixel
  totalSize = sliceSize * depth

每像素字节数取决于 imageType

imageType 每像素字节数
FS_IMAGE_C_GRAY8 1
FS_IMAGE_C_GRAY16U / FS_IMAGE_C_GRAY16S 2
FS_IMAGE_C_FLOAT32 4
FS_IMAGE_C_RGB24 3
FS_IMAGE_C_RGBA32 4

fsChannelSendProjectionAndWait

c 复制代码
int fsChannelSendProjectionAndWait(
    FSChannelHandle handle,
    const void* projectionData,
    const char* projectionName,
    const char* teachingFile,
    const char* resultPath,
    const char* reconConfigJson,
    uint32_t width, uint32_t height, uint32_t depth,
    int imageType,
    double voxelSizeX, double voxelSizeY, double voxelSizeZ,
    uint32_t timeoutMs,
    FSResultC* outResult,
    char* outMsg, size_t msgBufSize,
    void* outVolumeData, size_t outVolumeSize,
    FSVolumeInfoC* outVolumeInfo);

发送投影数据到 FIX 软件进行重建 + 检测。参数大部分与 fsChannelSendVolumeAndWait 相同,以下仅说明差异参数:

参数 类型 必填 说明
projectionData const void* 投影数据指针,内存布局与体数据相同。depth 表示投影张数
projectionName const char* 投影数据名称标识符
reconConfigJson const char* JSON 格式的重建配置参数。传 NULL 或空字符串表示使用默认重建参数
timeoutMs uint32_t 默认值 120000 (120 秒)。重建耗时较长,建议根据实际情况设置
outVolumeData void* [输出] 接收重建体数据的缓冲区。传 NULL 表示不需要体数据。需先调用 fsChannelEnableVolumeReceiver
outVolumeSize size_t outVolumeData 缓冲区大小(字节)
outVolumeInfo FSVolumeInfoC* [输出] 接收体数据信息(尺寸、体素大小等),可传 NULL

reconConfigJson 获取方式:

在 FIX 软件的重建界面中调试好参数后,保存的 .fixrc 文件即为 JSON 格式的重建配置。可以直接将该文件内容作为 reconConfigJson 参数传入。

提示:建议先在 FIX 软件中完成一次完整的重建流程,确认参数正确后,再将 .fixrc 文件内容用于 SDK 调用。

reconConfigJson 完整示例:

json 复制代码
{
    "geometry": {
        "trajectory": "CBCT",
        "sdAxis": "Z+",
        "rotation": "Zccw",
        "sourceToObject": 500.0,
        "objectToDetector": 500.0,
        "obliqueAngle": 0.0,
        "startAngle": 0.0,
        "scanAngle": 360.0,
        "scanCount": 720
    },
    "detector": {
        "dataType": "UInt16",
        "sizeU": 1536,
        "sizeV": 1536,
        "physicalSizeU": 153.6,
        "physicalSizeV": 153.6,
        "offsetU": 0.0,
        "offsetV": 0.0,
        "tiltAngleU": 0.0,
        "tiltAngleV": 0.0,
        "tiltAngleN": 0.0,
        "flipU": false,
        "flipV": false
    },
    "volume": {
        "dataType": "UInt16",
        "sizeX": 512,
        "sizeY": 512,
        "sizeZ": 512,
        "physicalSizeX": 15.36,
        "physicalSizeY": 15.36,
        "physicalSizeZ": 15.36,
        "offsetX": 0.0,
        "offsetY": 0.0,
        "offsetZ": 0.0,
        "flipX": false,
        "flipY": false,
        "flipZ": false,
        "intensityMin": 0.0,
        "intensityMax": 1.0
    },
    "despeckle": {
        "filterType": "Bilateral",
        "bilateralRadius": 2,
        "bilateralSigmaSpace": 3.0,
        "bilateralSigmaRange": 30.0
    },
    "_metadata": {
        "version": "1.0",
        "dataName": "MySample",
        "loadToViewer": true
    }
}

reconConfigJson 字段详解:

geometry — 扫描几何参数

字段 类型 默认值 可选值 说明
trajectory string "Planar" "CBCT", "OCT", "Planar", "Linear_Parallel", "Linear_Cross" 扫描方式。CT 重建通常用 "CBCT"
sdAxis string "Z+" "X+", "X-", "Y+", "Y-", "Z+", "Z-" 射线源-探测器轴线方向
rotation string "Zccw" "Xccw", "Xcw", "Yccw", "Ycw", "Zccw", "Zcw" 旋转轴与方向(ccw=逆时针, cw=顺时针)
sourceToObject double 500.0 > 0 射线源到样品中心距离 (mm)
objectToDetector double 500.0 > 0 样品中心到探测器距离 (mm)。注意:SDD = sourceToObject + objectToDetector
obliqueAngle double 0.0 -180 ~ 180 倾斜角 (度)
startAngle double 0.0 0 ~ 360 起始扫描角度 (度)
scanAngle double 360.0 > 0 总扫描角度 (度)
scanCount int 360 >= 1 投影张数(通常与投影数据的 depth 一致)

detector — 探测器参数

字段 类型 默认值 说明
dataType string "UInt16" 投影数据类型:"UInt8", "UInt16", "Int16", "Float32"
sizeU int 1536 探测器水平像素数
sizeV int 1536 探测器垂直像素数
physicalSizeU double 153.6 探测器水平物理尺寸 (mm),像素间距 = physicalSizeU / sizeU
physicalSizeV double 153.6 探测器垂直物理尺寸 (mm),像素间距 = physicalSizeV / sizeV
offsetU double 0.0 探测器中心水平偏移 (mm)
offsetV double 0.0 探测器中心垂直偏移 (mm)
tiltAngleU double 0.0 探测器 U 方向倾斜角 (度)
tiltAngleV double 0.0 探测器 V 方向倾斜角 (度)
tiltAngleN double 0.0 探测器法线方向倾斜角 (度)
flipU bool false 水平翻转探测器
flipV bool false 垂直翻转探测器

volume — 输出体数据参数

字段 类型 默认值 说明
dataType string "UInt16" 输出体素类型:"UInt8", "UInt16", "Int16", "Float32"
sizeX int 1536 输出体数据 X 维度(体素数)
sizeY int 1536 输出体数据 Y 维度(体素数)
sizeZ int 1536 输出体数据 Z 维度(体素数)
physicalSizeX double 15.36 X 方向物理尺寸 (mm),体素间距 = physicalSizeX / sizeX
physicalSizeY double 15.36 Y 方向物理尺寸 (mm)
physicalSizeZ double 15.36 Z 方向物理尺寸 (mm)
offsetX double 0.0 体数据中心 X 偏移 (mm)
offsetY double 0.0 体数据中心 Y 偏移 (mm)
offsetZ double 0.0 体数据中心 Z 偏移 (mm)
flipX bool false X 方向翻转
flipY bool false Y 方向翻转
flipZ bool false Z 方向翻转
intensityMin double 0.0 灰度裁剪最小值 (0.0~1.0 归一化范围)
intensityMax double 1.0 灰度裁剪最大值 (0.0~1.0 归一化范围)

despeckle — 去斑点滤波器参数

对重建后的体数据进行降噪处理。如果省略整个 despeckle 对象,默认使用 Bilateral 滤波器。

字段 类型 默认值 说明
filterType string "Bilateral" 滤波算法:"None", "Hampel", "Median", "Bilateral", "NLM"

以下参数根据选择的滤波算法填写对应部分即可,其余可省略:

Hampel 滤波器参数:

字段 类型 默认值 说明
hampelRadius int 1 核半径
hampelThreshold double 2.0 异常值检测阈值

Median 中值滤波器参数:

字段 类型 默认值 说明
medianRadius int 1 核半径

Bilateral 双边滤波器参数:

字段 类型 默认值 说明
bilateralRadius int 2 核半径
bilateralSigmaSpace double 3.0 空间域标准差
bilateralSigmaRange double 30.0 灰度域标准差

NLM 非局部均值滤波器参数:

字段 类型 默认值 说明
nlmPatchRadius int 1 匹配块半径
nlmSearchRadius int 2 搜索窗口半径
nlmH double 5000.0 滤波强度
nlmSigma double 3.0 噪声标准差

_metadata — 元数据(可选)

字段 类型 默认值 说明
version string "1.0" 配置版本号
dataName string "" 配置名称(仅标识用)
loadToViewer bool true 重建完成后是否自动加载到 FIX 查看器

注意configJson 字段存储在共享内存固定缓冲区中(2048 字节),JSON 字符串长度不能超过此限制。建议精简格式(去掉缩进),只包含需要修改的参数。未指定的参数组(如省略整个 geometry 对象)将使用 FIX 软件当前的默认值。


3. 异步 API(非阻塞,回调通知)

异步 API 发送数据后立即返回一个 requestId,处理进度和完成结果通过回调函数通知。

fsChannelSetProgressCallback

c 复制代码
void fsChannelSetProgressCallback(
    FSChannelHandle handle, FSProgressFunc callback, void* userData);

设置进度回调函数。

参数 类型 说明
handle FSChannelHandle 通道句柄
callback FSProgressFunc 回调函数指针,传 NULL 取消回调
userData void* 用户自定义数据指针,每次回调时原样传回

回调函数签名:

c 复制代码
void myProgressCallback(uint32_t requestId,  // 请求 ID
                        double progress,      // 进度 0.0~1.0
                        const char* message,  // 进度描述文本
                        void* userData);      // 用户数据

注意:回调函数在 DLL 内部线程中调用,不在主线程。如需更新 UI,请使用线程安全的方式(如 PostMessage、信号量等)转发到主线程。


fsChannelSetCompletionCallback

c 复制代码
void fsChannelSetCompletionCallback(
    FSChannelHandle handle, FSCompletionFunc callback, void* userData);

设置完成回调函数。

参数 类型 说明
handle FSChannelHandle 通道句柄
callback FSCompletionFunc 回调函数指针,传 NULL 取消回调
userData void* 用户自定义数据指针

回调函数签名:

c 复制代码
void myCompletionCallback(uint32_t requestId,    // 请求 ID
                          uint32_t taskStatus,    // 任务状态码 (FSTaskStatusC)
                          const char* message,    // 状态描述文本
                          int64_t elapsedMs,      // 总耗时 (毫秒)
                          void* userData);        // 用户数据

taskStatus 值:

状态码 枚举值 说明
100 FS_TASK_C_STARTED 任务已开始
101 FS_TASK_C_PROGRESS 进度更新(仅通过 progressCallback 回调)
200 FS_TASK_C_COMPLETED 处理完成,有数据返回
201 FS_TASK_C_COMPLETED_NODATA 处理完成,无数据返回
400 FS_TASK_C_FAILED 处理失败
401 FS_TASK_C_CANCELLED 已取消
408 FS_TASK_C_TIMEOUT 超时

fsChannelEnableVolumeReceiver

c 复制代码
int fsChannelEnableVolumeReceiver(FSChannelHandle handle, size_t volumeDataSize);

启用体数据接收器,用于接收重建后的体数据。调用一次后,后续所有投影请求共用同一接收器。

参数 类型 说明
handle FSChannelHandle 通道句柄
volumeDataSize size_t 预期体数据大小(字节),如 512*512*512*2(16-bit 512^3 体数据)。DLL 内部自动加上协议头开销。传 0 关闭并释放接收器
返回值 说明
FS_API_OK (0) 成功
FS_API_ERROR_INVALID_HANDLE (-1) 句柄无效
FS_API_ERROR_INTERNAL (-6) 创建接收器失败

fsChannelSetVolumeCallback

c 复制代码
void fsChannelSetVolumeCallback(FSChannelHandle handle,
                                 FSVolumeDataFunc callback, void* userData);

设置体数据到达回调(异步模式使用)。当回调已设置且接收器已启用时,异步投影请求会自动向服务端请求体数据返回。

参数 类型 说明
handle FSChannelHandle 通道句柄
callback FSVolumeDataFunc 回调函数指针,传 NULL 取消回调
userData void* 用户自定义数据指针

回调函数签名:

c 复制代码
void myVolumeCallback(uint32_t requestId,           // 请求 ID
                      const void* volumeData,        // 体数据指针 (仅回调期间有效)
                      const FSVolumeInfoC* volInfo,  // 体数据信息
                      void* userData);               // 用户数据

注意volumeData 指向 DLL 内部缓冲区,仅在回调函数执行期间有效。如需保留体数据,必须在回调内将数据复制到自己的缓冲区。


fsChannelSendVolumeAsync

c 复制代码
uint32_t fsChannelSendVolumeAsync(
    FSChannelHandle handle,
    const void* volumeData,
    const char* volumeName,
    const char* teachingFile,
    const char* resultPath,
    uint32_t width, uint32_t height, uint32_t depth,
    int imageType,
    double voxelSizeX, double voxelSizeY, double voxelSizeZ);

异步发送体数据,立即返回。参数含义与 fsChannelSendVolumeAndWait 相同(无 timeout 和输出参数)。

返回值 说明
> 0 requestId,可用于 fsChannelCancelRequest 取消。结果通过完成回调通知
0 发送失败,用 fsChannelGetLastError 获取详情

重要:异步发送返回后,volumeData 指向的内存已被复制到共享内存中,调用方可以立即释放。


fsChannelSendProjectionAsync

c 复制代码
uint32_t fsChannelSendProjectionAsync(
    FSChannelHandle handle,
    const void* projectionData,
    const char* projectionName,
    const char* teachingFile,
    const char* resultPath,
    const char* reconConfigJson,
    uint32_t width, uint32_t height, uint32_t depth,
    int imageType,
    double voxelSizeX, double voxelSizeY, double voxelSizeZ);

异步发送投影数据。参数含义与 fsChannelSendProjectionAndWait 相同。返回值与 fsChannelSendVolumeAsync 相同。


fsChannelCancelRequest

c 复制代码
void fsChannelCancelRequest(FSChannelHandle handle, uint32_t requestId);

取消一个待处理的异步请求。这是客户端侧取消,仅停止等待服务端响应,不会中断服务端正在进行的处理。

参数 类型 说明
handle FSChannelHandle 通道句柄
requestId uint32_t 异步发送时返回的请求 ID

4. 状态查询

fsChannelGetLastError

c 复制代码
const char* fsChannelGetLastError(FSChannelHandle handle);

获取最近一次错误消息。返回的指针指向 DLL 内部缓冲区,在下一次 API 调用前有效。传 NULL 句柄返回空字符串。


fsChannelPendingCount

c 复制代码
size_t fsChannelPendingCount(FSChannelHandle handle);

返回当前待处理的异步请求数量。


fsGetVersion

c 复制代码
const char* fsGetVersion(void);

返回 SDK 版本号字符串,如 "1.0.0"。返回静态字符串,始终有效。


5. 结果结构体

c 复制代码
typedef struct FSResultC {
    uint32_t taskStatus;   // FSTaskStatusC 枚举值
    uint32_t requestId;    // 请求 ID
    double   progress;     // 最终进度 (通常为 1.0)
    int64_t  elapsedMs;    // 从发送到收到响应的总耗时 (毫秒)
} FSResultC;

同步 API 通过 outResult 参数填充此结构体。


5.1 体数据信息结构体

c 复制代码
typedef struct FSVolumeInfoC {
    uint32_t width;        // X 维度
    uint32_t height;       // Y 维度
    uint32_t depth;        // Z 维度
    int      imageType;    // 像素类型 (FSImageTypeC 值)
    double   voxelSizeX;   // X 方向体素尺寸 (mm)
    double   voxelSizeY;   // Y 方向体素尺寸 (mm)
    double   voxelSizeZ;   // Z 方向体素尺寸 (mm)
    size_t   dataSize;     // 实际体数据字节数
} FSVolumeInfoC;

通过 fsChannelSendProjectionAndWaitoutVolumeInfo 参数或异步体数据回调的 volumeInfo 参数返回。


6. 图像类型

枚举值 每像素字节数 对应 OpenCV 类型 说明
FS_IMAGE_C_GRAY8 1 1 CV_8UC1 8 位无符号灰度
FS_IMAGE_C_GRAY16U 2 2 CV_16UC1 16 位无符号灰度(最常用)
FS_IMAGE_C_GRAY16S 3 2 CV_16SC1 16 位有符号灰度
FS_IMAGE_C_FLOAT32 4 4 CV_32FC1 32 位浮点灰度
FS_IMAGE_C_RGB24 5 3 CV_8UC3 24 位 RGB 彩色
FS_IMAGE_C_RGBA32 6 4 CV_8UC4 32 位 RGBA 彩色

7. 错误码

错误码 说明
FS_API_OK 0 成功
FS_API_ERROR_INVALID_HANDLE -1 句柄为 NULL 或无效
FS_API_ERROR_NOT_CONNECTED -2 未连接到服务端
FS_API_ERROR_INVALID_PARAM -3 参数错误(数据指针为 NULL、尺寸为 0 等)
FS_API_ERROR_SEND_FAILED -4 发送失败或服务端返回处理失败
FS_API_ERROR_TIMEOUT -5 等待超时(同步 API)
FS_API_ERROR_INTERNAL -6 内部错误(初始化失败等)

典型使用流程

同步方式

复制代码
fsChannelCreate(NULL)        创建句柄 + 连接 (失败返回 NULL)
    |
fsChannelSendVolumeAndWait   发送数据, 阻塞等待
    |                        (检查返回值和 outResult)
    |
fsChannelDestroy             释放资源

异步方式

复制代码
fsChannelCreate(NULL)          创建句柄 + 连接 (失败返回 NULL)
    |
fsChannelSetProgressCallback   设置进度回调
fsChannelSetCompletionCallback 设置完成回调
    |
fsChannelSendVolumeAsync       发送数据, 立即返回 requestId
    |
    |--- (主线程继续做其他事情) ---
    |
    |   onProgress(requestId, 0.3, "处理中...", userData)    <- DLL 内部线程
    |   onProgress(requestId, 0.7, "处理中...", userData)
    |   onCompletion(requestId, 200, "完成", 1234, userData) <- DLL 内部线程
    |
fsChannelDestroy               释放资源

同步接收体数据

复制代码
fsChannelCreate(NULL)                     创建句柄 + 连接 (失败返回 NULL)
    |
fsChannelEnableVolumeReceiver(size)       启用体数据接收器 (一次)
    |
fsChannelSendProjectionAndWait(...,       发送投影, 阻塞等待
    buf, bufSize, &volInfo)               最后 3 个参数接收体数据
    |
    |  ret == FS_API_OK && volInfo.dataSize > 0
    |  → buf 中已有重建体数据
    |
    |  (可多次调用 sendProjectionAndWait, 接收器可复用)
    |
fsChannelDestroy                          释放资源

异步接收体数据

复制代码
fsChannelCreate(NULL)                     创建句柄 + 连接 (失败返回 NULL)
    |
fsChannelEnableVolumeReceiver(size)       启用体数据接收器 (一次)
fsChannelSetVolumeCallback(onVolume, ud)  设置体数据回调
fsChannelSetCompletionCallback(onDone, ud)
    |
fsChannelSendProjectionAsync(...)         异步发送投影
    |
    |   onVolume(reqId, data, &info, ud)    <- 体数据先到达
    |   onDone(reqId, 200, "完成", ms, ud)  <- 完成状态后到达
    |
fsChannelDestroy                          释放资源

注意事项

  • FIX 检测软件必须先启动并处于运行状态,fsChannelCreate 才能成功连接(返回非 NULL)
  • fsChannelCreate 传 NULL 默认连接 "FIXSharedMemory"(即 FIX 检测软件),如有特殊需求可传自定义名称
  • 如需重连,先 fsChannelDestroy 释放旧句柄,再 fsChannelCreate 创建新句柄(回调需重新设置)
  • 体数据内存由调用方管理,DLL 内部只读取不修改、不释放
  • 回调函数在 DLL 内部线程中调用,如需操作 UI 请自行转发到主线程
  • 一个进程中可以创建多个通道实例(多个句柄),互不干扰
  • 所有 const char* 参数传 NULL 是安全的(等同于空字符串)
  • 所有函数传 NULL 句柄是安全的(返回错误码或默认值,不会崩溃)

常见问题 (FAQ)

Q: fsChannelCreate 返回 NULL,怎么办?

最常见原因:FIX 检测软件没有启动。 请先启动 FIX 软件,等它完全加载后再调用 fsChannelCreate

其他可能:

  • 传了错误的 serverName(通常传 NULL 就行)
  • 系统内存不足(极罕见)

Q: fsChannelSendVolumeAndWait 返回 FS_API_ERROR_TIMEOUT (-5)

体数据太大或检测配置复杂,在超时时间内没处理完。解决方法:

c 复制代码
/* 把超时从 60 秒改大, 比如 5 分钟 */
fsChannelSendVolumeAndWait(ch, ..., 300000, ...);
/*                                  ^^^^^^ 300000 毫秒 = 5 分钟 */

Q: fsChannelSendVolumeAndWait 返回 FS_API_ERROR_SEND_FAILED (-4)

服务端处理报错了。用最后三个参数获取错误消息:

c 复制代码
FSResultC result = {0};
char msg[512] = {0};
int ret = fsChannelSendVolumeAndWait(ch, ..., &result, msg, sizeof(msg));
if (ret != FS_API_OK) {
    printf("错误消息: %s\n", msg);          /* 看服务端返回了什么 */
    printf("状态码: %u\n", result.taskStatus); /* 400=失败, 401=取消, 408=超时 */
}

Q: 体数据应该怎么组织内存?

体数据在内存中是一个连续的一维数组,按切片顺序排列:

复制代码
内存布局 (以 256x256x100, 16-bit 为例):

  总大小 = 256 * 256 * 100 * 2 = 13107200 字节 (12.5 MB)

  byte[0 ~ 131071]         = 第 0 张切片 (256*256*2 字节)
  byte[131072 ~ 262143]    = 第 1 张切片
  ...
  byte[12975128 ~ 13107199] = 第 99 张切片

用 C 代码准备数据:

c 复制代码
uint32_t width  = 256;
uint32_t height = 256;
uint32_t depth  = 100;

/* 16-bit 灰度: 每像素 2 字节 */
size_t totalSize = (size_t)width * height * depth * 2;
uint16_t* data = (uint16_t*)malloc(totalSize);

/* 访问第 z 张切片、第 y 行、第 x 列的像素: */
uint16_t pixel = data[z * width * height + y * width + x];

Q: imageType 应该传什么?

看你的数据是什么类型的:

你的数据 传什么 每像素字节数
uint8_t 数组(8 位灰度) FS_IMAGE_C_GRAY8 1
uint16_t 数组(最常见 FS_IMAGE_C_GRAY16U 2
int16_t 数组 FS_IMAGE_C_GRAY16S 2
float 数组 FS_IMAGE_C_FLOAT32 4

90% 的 CT 数据都是 16-bit 无符号,传 FS_IMAGE_C_GRAY16U

Q: voxelSizeX/Y/Z 不知道填什么?

体素尺寸是每个像素在物理空间中代表多少 mm。这个值取决于你的 CT 设备。

例如:扫描视野 (FOV) 是 12.8mm,重建分辨率 256 像素 → 体素尺寸 = 12.8 / 256 = 0.05 mm

如果真不知道,先随便填个值(如 0.05, 0.05, 0.05),检测功能能正常工作,只是物理尺寸标注不准确。

Q: teachingFileresultPath 可以不传吗?

可以。这两个参数都是可选的:

c 复制代码
/* 不用教学文件, 也不保存结果 */
fsChannelSendVolumeAndWait(ch, data, "sample",
    NULL,    /* teachingFile: 不使用教学文件 */
    NULL,    /* resultPath:   不保存结果 */
    ...);
  • teachingFile = NULL → FIX 使用当前加载的教学文件(如果有的话)
  • resultPath = NULL → 不保存检测结果文件

Q: 同步和异步该用哪个?

场景 推荐 理由
命令行工具 / 批处理脚本 同步 (SendVolumeAndWait) 简单,发了就等结果
有 UI 的程序 异步 (SendVolumeAsync + 回调) 不会卡死界面
需要显示进度条 异步 + SetProgressCallback 进度回调里更新进度条
不确定 / 先试试 同步 代码最少,先跑起来再说

Q: 程序退出时需要做什么?

只要调 fsChannelDestroy 就行,它会自动断开连接、释放所有资源:

c 复制代码
fsChannelDestroy(ch);   /* 之后 ch 不能再用 */
ch = NULL;              /* 好习惯: 置空防止误用 */

Q: 可以同时创建多个通道吗?

可以。每个句柄独立工作,互不干扰:

c 复制代码
FSChannelHandle ch1 = fsChannelCreate(NULL);        /* 连接默认 FIX */
FSChannelHandle ch2 = fsChannelCreate("MyServer");   /* 连接另一个服务 */
/* ... 各自独立使用 ... */
fsChannelDestroy(ch1);
fsChannelDestroy(ch2);
上一个
FIX SDK
下一个
FIX 训练系统 (FTS)
最近修改: 2026-02-24Powered by