filter.* 命令族接口手册本文档专门讲
filter.*命令家族(像素级 2D 图像处理)。协议总览、命令家族分布、错误码表、共享内存配置等通用内容请看
fixSharedMemory_dll_README.md。适用版本:fixSharedMemoryDll v2.0.0+,FIX 主程序 build ≥ 3685。
| 命令 | 用途 | 输出尺寸 |
|---|---|---|
filter.sr |
FIX 超分辨率(×1 增强 / ×2 / ×3 / ×4 上采样;psnrMode=true 走自然模式,不出现锐化伪影) |
scale1 同尺寸;scale2 ×2(快速档);scale3 ×3;scale4 ×4 |
filter.sm |
Smart Denoising(非局部均值降噪) | 同输入 |
filter.um |
Unsharp Mask 锐化 | 同输入 |
filter.clahe |
限制对比度自适应直方图均衡(与 W/L 同语义,RGB 走 Lab L 通道) | 同输入 |
filter.hef |
High-Emphasis Filter(频域高通强调) | 同输入(输出 8U 单通道,彩色经 Lab L 处理后回 BGR) |
filter.edgeEnhance |
边缘增强(5×5 拉普拉斯类核) | 同输入 |
filter.anisoDiffusion |
各向异性扩散(Perona-Malik 保边降噪) | 同输入 |
filter.gamma |
Gamma 校正(亮度非线性映射) | 同输入 |
filter.exposure |
曝光补偿(线性 EV stops) | 同输入 |
filter.bc |
亮度 + 对比度(Photoshop 经典) | 同输入 |
filter.shadowHighlight |
暗部提升 + 亮部压缩(参数化 tone curve) | 同输入 |
filter.gauss |
OpenCV 高斯模糊(基础工具,与 W/L 无关) | 同输入 |
filter.applyEffect |
复现 FIX W/L 控件保存的 .json 效果(curve + 多 filter 一次性应用) | 取决于栈中是否含 SR(同输入 / ×N) |
所有
filter.*命令的输入图像通过共享内存传给服务端,输出图像通过共享内存返回客户端。
并发模型:服务端 FIFO 串行处理所有图像处理请求,无背压。RGB 支持:除
filter.sr外的所有 W/L 滤镜都通过applyOnLuminance走 Lab L 通道处理彩色图(不偏色)。filter.edgeEnhance通过cv::filter2D直接 per-channel 处理。与 W/L 控件等价:
filter.{sm,um,clahe,hef,edgeEnhance,anisoDiffusion,gamma,exposure,bc,shadowHighlight}的算法与参数语义与 W/L 控件的"已应用滤镜栈"完全一致,可直接用同一份 JSON 在 SHM 通道复现 UI 看到的效果。
typedef struct FSImageProcParamsC {
const char* command; // 必填:"filter.sr"
const char* paramsJson; // 可空:命令参数 JSON(UTF-8)
const char* teachingFile; // 可空:teach.* 用
const char* resultPath; // 可空:服务端落盘路径(filter.* 也支持,命中后跳过 SHM 回传)
// paramsJson["option.resultPath"] 优先级更高
int timeoutMs; // 0=默认 300000ms
} FSImageProcParamsC;
typedef struct FSImageProcResultC {
int32_t procStatus; // 0=OK;详见错误码表
int32_t taskStatus;
uint32_t outRows, outCols, outChannels; // 服务端落盘模式下全为 0(SHM 跳过)
int outImageType; // FS_IMAGE_C_RGB24 / FS_IMAGE_C_GRAY8 ...
uint64_t outStride;
void* outImage; // DLL 分配,必须 fsChannelFreeImageProcResult 释放
// 服务端落盘 / option.returnImage=false 时为 NULL
char* resultJson; // 落盘模式下含 savedPath/savedRows/savedCols/savedChans
char* errorMsg; // 失败时填充
uint64_t queuedUs; // 入队等待时间
uint64_t computeUs; // 服务端实际计算时间
uint64_t totalUs; // 服务端总时间
int64_t elapsedMs;
} FSImageProcResultC;
#include "fixSharedMemory_api.h"
// 1. 建通道(FIX 必须已运行)
FSChannelHandle ch = fsChannelCreate(nullptr); // 默认共享内存名 "FIXSharedMemory"
if (!ch) { /* 处理失败 */ }
// 2. 启用接收缓冲(容纳输出图像 + JSON + 余量)
fsChannelEnableImageProcReceiver(ch, 512ULL * 1024 * 1024);
// 3. 配参数
FSImageProcParamsC params{};
params.command = "filter.sr";
params.paramsJson = R"({"filter.sr.scaleMode":"scale1"})";
params.timeoutMs = 600000;
// 4. 调用(阻塞)
FSImageProcResultC result{};
int rc = fsChannelSendImageProcAndWait(ch, ¶ms,
inputBgrBytes, rows, cols, 3,
FS_IMAGE_C_RGB24,
static_cast<uint64_t>(cols) * 3,
&result);
// 5. 用 result.outImage(DLL 分配)
// 6. 释放 + 关闭
fsChannelFreeImageProcResult(&result);
fsChannelDestroy(ch);
// 注册回调(注册即生效;不注册=不接收对应消息)
fsChannelSetImageProcProgressCallback(ch,
[](uint32_t requestId, uint32_t stepDone, uint32_t stepTotal,
const char* message, void*) {
std::printf("req#%u %u/%u: %s\n", requestId, stepDone, stepTotal, message);
}, nullptr);
fsChannelSetImageProcCompleteCallback(ch,
[](uint32_t requestId, const FSImageProcResultC* r, void*) {
if (r->procStatus == FS_PROC_C_OK) { /* 用 r->outImage */ }
}, nullptr);
// 发送(立即返回 requestId,0=失败)
uint32_t reqId = fsChannelSendImageProcAsync(ch, ¶ms,
inputBgrBytes, rows, cols, 3, FS_IMAGE_C_RGB24,
static_cast<uint64_t>(cols) * 3);
option.* 字段(跨命令共享)paramsJson 里以 option. 为前缀的字段适用于所有命令,由框架统一解析,不归命令 handler 管。
| 字段 | 类型 | 默认 | 含义 |
|---|---|---|---|
option.returnImage |
bool | true |
false = 服务端完全跳过 SHM 图像回传,仅返回 procStatus + resultJson。适合"只要检测结果不要输出图"的场景 |
option.resultPath |
string | "" |
服务端落盘路径。非空时 FIX 用 cv::imwrite 直接写盘,跳过 SHM 回传。优先级高于 FSImageProcParamsC.resultPath 结构体字段 |
paramsJson["option.resultPath"] |
FSImageProcParamsC.resultPath |
服务端实际落盘路径 |
|---|---|---|
| 非空 | 任意 | JSON 中的路径 |
| 空 / 未设 | 非空 | 结构体里的路径 |
| 空 / 未设 | 空 | 不落盘(走 SHM 回传) |
为什么要双源:结构体字段方便 C 客户端直接用;JSON 字段允许新参数(如 option.resultFormat、option.resultQuality)在不破坏协议的前提下扩展,未来加新落盘选项不必改 FSImageProcParamsC。
r->outImage = NULL,r->outRows = outCols = outChannels = 0,r->outStride = 0r->procStatus = FS_PROC_C_OKr->resultJson 含:
{
"savedPath": "z:/output/foo.jpg",
"savedRows": 10997,
"savedCols": 15360,
"savedChans": 3
}
客户端不能用
r->outImage != NULL判断成功——服务端落盘成功后这字段是 NULL。要看procStatus == FS_PROC_C_OK或resultJson.savedPath。
cv::imwrite 失败时(路径无权限、磁盘满、扩展名不识别):
option.returnImage |
fallback |
|---|---|
true(默认) |
走 SHM 回传,客户端能拿到完整 outImage;resultJson 加 savePathRequested + saveError 标记 |
false |
不 fallback,仅 resultJson 报错 |
// 方式 A:结构体字段(C 客户端最方便)
FSImageProcParamsC p{};
p.command = "filter.sr";
p.paramsJson = "{\"filter.sr.scaleMode\":\"scale4\"}";
p.resultPath = "z:/sr_x4.jpg";
// 方式 B:JSON 字段(推荐,便于一次塞所有参数)
p.command = "filter.sr";
p.paramsJson = "{"
"\"filter.sr.scaleMode\":\"scale4\","
"\"option.resultPath\":\"z:/sr_x4.jpg\""
"}";
p.resultPath = nullptr;
// 方式 C:只要 resultJson,不要图、不落盘
p.command = "filter.sr";
p.paramsJson = "{\"option.returnImage\":false}";
filter.sr — FIX 超分辨率对 2D 图像做画质增强 / 上采样:
scale1:与输入同尺寸的画质增强scale2:×2 上采样快速档(速度更快,视觉质量弱于 scale4 但强于普通插值放大;适合显示用、对极细纹理不敏感的场景)scale3:×3 上采样(输入 W×H → 输出 3W×3H);内部 ×4 模型推理后 INTER_CUBIC 缩到 ×3scale4:×4 上采样(输入 W×H → 输出 4W×4H)字段(必须带 filter.sr. 前缀) |
类型 | 默认 | 含义 |
|---|---|---|---|
filter.sr.scaleMode |
string | "scale4" |
"scale1"=同尺寸增强;"scale2"=×2 快速档;"scale3"=×3 上采样;"scale4"=×4 上采样 |
filter.sr.blendRatio |
float | 1.0 | Soft↔Hard 混合比例 [0,1];0 = Soft(柔和/去噪),1 = Hard(锐利)。psnrMode=true 时被忽略 |
filter.sr.psnrMode |
bool | false | 自然模式(Natural mode):true = 输出更自然、无锐化伪影,渐变保留好;blendRatio 被忽略 |
filter.sr.tileSize |
int | 1024 | tile 尺寸(≥ 1024;更小的值会被强制提升到 1024) |
filter.sr.batchHint |
int | 1 | 一次处理的 tile 数;服务端内存吃紧时会自动减半到 1 |
⚠️ 字段名拼写:服务端读
filter.sr.batchHint;写成batchHint会拿不到值,掉默认 1。所有filter.sr.*字段均带前缀。
psnrMode 与 blendRatio 的关系:
psnrMode=true时blendRatio完全失效(不影响输出)。需要 Soft↔Hard 混合时把psnrMode留空或设为false。
channels=3,imageType=FS_IMAGE_C_RGB24(实际是 BGR24 字节序)fsChannelEnableImageProcReceiver(ch, N),N 至少容纳 outRows * outStride + 64KB 余量procStatus = FS_PROC_C_GPU_UNAVAIL| 场景 | 输入 | 输出 | 共享内存最低 | EnableImageProcReceiver 最低 |
|---|---|---|---|---|
| scale1 / 15360×10997 BGR | 483 MB | 483 MB | ≥ 1 GB | ≥ 600 MB |
| scale2 / 15360×10997 BGR | 483 MB | 1.93 GB | ≥ 2.5 GB | ≥ 2 GB |
| scale4 / 15360×10997 BGR | 483 MB | 7.7 GB | ≥ 9 GB ⚠️ | ≥ 8 GB |
| scale1 / 4K (3840×2160) BGR | 24 MB | 24 MB | ≥ 256 MB | ≥ 64 MB |
| scale4 / 4K BGR | 24 MB | 384 MB | ≥ 512 MB | ≥ 512 MB |
scale4 大图需要客户端先在 fiSettings 调大
sd_EC_SharedMemoryX/Y/Z,详见主 README。
filter.sr 在处理过程中按 tile 发 progress:
done = 已完成的 tile 数
total = 总 tile 数 ≈ ⌈rows/tileSize⌉ × ⌈cols/tileSize⌉
message = "SR tile {done}/{total} batch={N}"
15360×10997 / tile=1024 → 16×12 = 192 tiles。
FSImageProcParamsC params{};
params.command = "filter.sr";
params.paramsJson =
"{\"filter.sr.scaleMode\":\"scale4\","
" \"filter.sr.blendRatio\":1.0,"
" \"filter.sr.psnrMode\":false," // true = 自然模式(无锐化伪影),blendRatio 被忽略
" \"filter.sr.tileSize\":1024," // ≥1024,更小会被强制提升到 1024
" \"filter.sr.batchHint\":1}";
params.timeoutMs = 600000; // 10 分钟,大图必备
FSImageProcResultC result{};
int rc = fsChannelSendImageProcAndWait(ch, ¶ms,
bgrBytes, /*rows*/ 10997, /*cols*/ 15360, /*channels*/ 3,
FS_IMAGE_C_RGB24, /*stride*/ 15360 * 3, &result);
if (rc == FS_API_OK && result.procStatus == FS_PROC_C_OK) {
printf("SR done: %ux%u in %.2fs (compute=%.2fs)\n",
result.outCols, result.outRows,
result.totalUs / 1e6, result.computeUs / 1e6);
// 处理 result.outImage
} else {
printf("SR failed: rc=%d procStatus=%d msg=%s\n",
rc, result.procStatus,
result.errorMsg ? result.errorMsg : "(null)");
}
fsChannelFreeImageProcResult(&result);
服务端 option.resultPath 路径或客户端 SHM 回传后落盘,最终都走 cv::imwrite(OpenCV 内部按扫描线流式写入)。编码本身是 CPU bound、单线程,速度强烈受输出格式影响。
以 scale4 / 15360×10997 输出(7.7 GB BGR8)为例:
| 后缀 | 实际做什么 | 估算耗时 | 输出文件大小 | 适用 |
|---|---|---|---|---|
.jpg (quality=95) |
libjpeg 单线程编码 | ~25 s | ~300-500 MB | 默认;视觉无差 |
.jpg (quality=75) |
同上,更激进压缩 | ~17 s | ~150-250 MB | 偶尔可接受 |
.bmp |
无压缩,直接 dump 字节 | ~5-7 s | 7.7 GB | 最快;磁盘空间换速度 |
.tif (无压缩) |
无压缩 + TIFF 元数据 | ~5-7 s | 7.7 GB | 同 BMP,元数据更丰富 |
.tif (LZW) |
LZW 单线程压缩 | ~30 s+ | ~4-5 GB | 慢,不推荐 |
.png |
libpng + zlib | ~60 s+ | ~3-5 GB | 真实图像压缩比低且很慢,不推荐 |
scale2 输出是 scale4 的 1/4 大小(1.93 GB vs 7.7 GB),所有保存格式的耗时按比例降低 ~4×。组合最优:scaleMode=scale2 + .bmp ≈ 1-2 秒落盘。
两条路径都走 cv::imwrite,编码耗时本质相同。差别只在 SHM 大数据传回这段:
| 路径 | 传输 SHM 大数据 | 服务端 cv::imwrite | 客户端 cv::imwrite |
|---|---|---|---|
option.resultPath 命中(服务端落盘) |
跳过 | ~5-25 s(按格式) | — |
| 默认(SHM 回传 + 客户端落盘) | ~5-8 s(7.7 GB 通过 receiver SHM) | — | ~5-25 s(按格式) |
scale4 大图想最快,用 option.resultPath 让服务端直接写盘——免了 SHM 7.7 GB 的来回。
filter.sm — Smart Denoising非局部均值降噪。
| 字段 | 类型 | 默认 | 含义 |
|---|---|---|---|
filter.sm.h |
float | 3.0 | 滤波强度,越大越平滑;典型 3~20 |
filter.sm.templateWindowSize |
int | 7 | 模板窗口(奇数,自动 +1) |
filter.sm.searchWindowSize |
int | 21 | 搜索窗口(奇数,自动 +1) |
支持通道:1ch 走 cv::fastNlMeansDenoising;3/4ch 走 cv::fastNlMeansDenoisingColored(4ch 时 alpha 原样保留)。
params.paramsJson = R"({"filter.sm.h":5.0, "filter.sm.templateWindowSize":7, "filter.sm.searchWindowSize":21})";
filter.um — Unsharp Mask经典锐化(原图 - 高斯模糊高频 → 加权回去)。RGB 经 Lab L 通道处理。
| 字段 | 类型 | 默认 | 含义 |
|---|---|---|---|
filter.um.radius |
float | 3.0 | 高斯模糊 σ;典型 0.5~10 |
filter.um.amount |
float | 0.7 | 锐化强度;典型 0.3~1.5 |
filter.clahe — CLAHE(限制对比度自适应直方图均衡)与 W/L 控件 CLAHE 同语义。RGB 经 Lab L 通道处理。
| 字段 | 类型 | 默认 | 含义 |
|---|---|---|---|
filter.clahe.windowSize |
int | 100 | tile 边长(像素),算法内部据此推 tileGridSize = cols / windowSize |
filter.clahe.clipLimit |
float | 150.0 | 对比度限制;典型 4~150 |
filter.clahe.iterations |
int | 1 | 迭代次数(重复施加 CLAHE);典型 1,最多 5 |
filter.clahe.tileGridSize |
int | — | legacy 兼容字段:仅在没传 windowSize 时启用,按 windowSize = cols / tileGridSize 反推 |
params.paramsJson = R"({"filter.clahe.windowSize":80, "filter.clahe.clipLimit":40.0, "filter.clahe.iterations":1})";
filter.hef — High-Emphasis Filter频域 DFT + 高斯高通 + 直方图均衡。结果是 8U 单通道;彩色图由 applyOnLuminance 包成 Lab L → 回 BGR。
| 字段 | 类型 | 默认 | 含义 |
|---|---|---|---|
filter.hef.d0 |
float | 60.0 | 截止频率;典型 10~90 |
filter.hef.a |
float | 0.5 | 低频权重 k1;一般 0.5~1.0 |
filter.hef.b |
float | 1.2 | 高频权重 k2;一般 0.5~1.5 |
filter.edgeEnhance — 边缘增强5×5 拉普拉斯类核 + 与原图插值混合。cv::filter2D 直接 per-channel 处理,不经 Lab。
| 字段 | 类型 | 默认 | 含义 |
|---|---|---|---|
filter.edgeEnhance.amount |
float | 1.0 | 锐化强度 [0, ∞);1.0 ≈ 原 kernel 效果 |
filter.edgeEnhance.mix |
float | 1.0 | 与原图混合比 [0, 1];1=全增强,0=全原图 |
filter.anisoDiffusion — 各向异性扩散(Perona-Malik)保边降噪。RGB 经 Lab L 通道处理。注意:迭代次数高、图像大时较慢(C++ 双层 for 循环)。
| 字段 | 类型 | 默认 | 含义 |
|---|---|---|---|
filter.anisoDiffusion.iterations |
int | 10 | 迭代次数 [1, 50];典型 5~30 |
filter.anisoDiffusion.kappa |
float | 30.0 | 边缘敏感度 [1, 100] |
filter.anisoDiffusion.lambda |
float | 0.25 | 扩散速率 [0, 0.25](稳定性要求 ≤ 0.25) |
filter.anisoDiffusion.option |
int | 1 | 扩散函数:1 = exp(-(d/k)²),2 = 1/(1+(d/k)²) |
filter.gamma — Gamma 校正out = (in/255)^(1/γ) × 255,LUT 实现。RGB 经 Lab L 通道处理。
| 字段 | 类型 | 默认 | 含义 |
|---|---|---|---|
filter.gamma.gamma |
float | 1.0 | γ ∈ [0.1, 5.0];< 1 提亮暗部,> 1 压暗 |
// X-ray 暗部画 BGA 焊点:γ = 0.5
params.paramsJson = R"({"filter.gamma.gamma":0.5})";
filter.exposure — 曝光补偿(EV)out = in × 2^EV,线性乘法 + 饱和。RGB 经 Lab L 通道处理。每 +1 EV 亮度翻倍,−1 EV 减半。
| 字段 | 类型 | 默认 | 含义 |
|---|---|---|---|
filter.exposure.ev |
float | 0.0 | EV stops ∈ [-3.0, +3.0] |
filter.bc — Brightness + Contrast经典 Photoshop 亮度+对比度:out = α·(in - 128) + 128 + β = α·in + (128(1-α) + β)。RGB 经 Lab L 通道处理。
| 字段 | 类型 | 默认 | 含义 |
|---|---|---|---|
filter.bc.brightness |
float | 0.0 | β ∈ [-100, +100],加性偏移 |
filter.bc.contrast |
float | 1.0 | α ∈ [0.0, 5.0],乘性增益(1.0 = 不变) |
filter.shadowHighlight — 暗部提升 / 亮部压缩参数化 tone curve(LUT):
t' = t + sLift · (1-t)² · (1-t) -- 暗部抬起
- hComp · t² · t -- 亮部压低
RGB 经 Lab L 通道处理。
| 字段 | 类型 | 默认 | 含义 |
|---|---|---|---|
filter.shadowHighlight.shadowLift |
float | 0.0 | [0, 1],提暗部强度(0=不动) |
filter.shadowHighlight.highlightCompress |
float | 0.0 | [0, 1],压亮部强度(0=不动) |
适合 X-ray 板上同时看 BGA 焊点(暗)和金属屏蔽罩(亮)的场景。
filter.applyEffect — 一次性复现 FIX W/L 效果把 FIX 主程序里 Tools → Save Effect to JSON... 保存的 .json 一次性应用到客户端输入图。等价于:W/L 曲线 + 已应用滤镜栈按 UI 中的顺序在服务端跑一遍。
客户在 FIX UI 里调好曲线 + 一串滤镜(CLAHE → Gamma → UM …)后 Save 出 .json,第三方客户端拿到这个 .json 就能在自己的图像上复现同样的视觉效果,不用自己 parse JSON、不用自己逐个 SHM 命令调。
| 字段 | 类型 | 含义 |
|---|---|---|
filter.applyEffect.jsonInline |
object | 完整 JSON 对象内联(推荐,便于 client 直接构造) |
filter.applyEffect.jsonPath |
string | 服务端可读的 .json 文件路径(便利模式:client 知道 FIX 存盘路径时直接传) |
可读 + 可手写格式,filter 名与 SHM 单 filter 命令名(filter.<name> 的 <name> 部分)严格对应;params 是真正的 JSON 对象。
{
"version": 1,
"wlPoints": ["0,0", "127.5,127.5", "255,255"],
"stack": [
{ "filter": "filter.clahe", "params": { "windowSize": 80, "clipLimit": 40.0, "iterations": 1 } },
{ "filter": "filter.gamma", "params": { "gamma": 0.5 } },
{ "filter": "filter.exposure", "params": { "ev": -0.5 } },
{ "filter": "filter.sr", "params": { "outputScale": 4, "ratio": 1.0, "psnrMode": true, "tileSize": 1024 } }
]
}
| 字段 | 类型 | 说明 |
|---|---|---|
version |
int | 当前 1,预留 |
wlPoints |
string[] | W/L 曲线控制点,每点 "x,y"。缺失或 size < 2 时跳过曲线阶段(等价 identity 直通) |
stack |
object[] | 滤镜栈,按数组顺序依次应用(index 0 先跑) |
stack[i].filter |
string | filter 名(不区分大小写),与 SHM 单 filter 命令名严格一致,见下方对照表 |
stack[i].params |
object | 参数对象,键 = 参数名,值 = JSON number / bool / string |
filter 名 = §1 命令一览里的命令名(带 filter. 前缀)。客户从 SHM 单命令切到 stack 时,只要把命令名搬到这里即可。
| filter | 参数(键 : 类型) |
|---|---|
filter.sr |
outputScale: 1/2/3/4,ratio: 0.0~1.0,psnrMode: bool,tileSize: int (≥1024);nativeMode 字段会被忽略 |
filter.sm |
h: float,templateWindowSize: int 奇数,searchWindowSize: int 奇数 |
filter.um |
radius: float,amount: float |
filter.clahe |
windowSize: int,clipLimit: float,iterations: int |
filter.hef |
d0: float,a: float,b: float |
filter.edgeEnhance |
amount: float,mix: 0.0~1.0 |
filter.anisoDiffusion |
iterations: int,kappa: float,lambda: 0.0~0.25,option: 1 或 2 |
filter.gamma |
gamma: float |
filter.exposure |
ev: -3.0~+3.0 |
filter.bc |
brightness: -100~+100,contrast: 0.0~5.0 |
filter.shadowHighlight |
shadowLift: 0.0~1.0,highlightCompress: 0.0~1.0 |
接受的别名:除完整命令名(首选),filter 字段还接受去掉
filter.前缀的短名("clahe"≡"filter.clahe")和早期大写枚举名("FIXSR"、"CLAHE"),大小写不敏感。向后兼容:服务端同时接受旧格式(
"filter": 4整数 +"params": ["windowSize=80",...]字符串数组)。新代码建议用新格式。
input
↓
应用 W/L 曲线(wlPoints 缺失则跳过)
↓
按 stack 数组顺序,依次应用每个 filter
↓
output
filter.sr 字段映射:JSON 里的 outputScale(int 1/2/4)映射成 SHM 的 scaleMode;ratio 映射成 blendRatio;psnrMode 同名透传;tileSize 同名透传(强制 ≥ 1024,小于该值会被自动提升);nativeMode 字段被忽略。SR 内部的 tileOverlap 固定 32、batchHint 固定 1。
⚠️
filter.srFast / Native 差异:W/L UI 的 SR 默认走 Fast preview 模式(视觉略损细节);SHM 通道永远走 Native tile(更细腻)。所以"Save Effect to JSON 后在 SHM 复现"得到的 SR 效果会比 UI Fast 预览更细腻。需要 UI 与 SHM 严格一致时,在 widget 把 SR 模式切到 "Native (tile)" 再 Save。
步骤失败行为:若 stack 中某一步返回空(如 SR 推理失败),该命令报 FS_PROC_C_INTERNAL 并清空 outImage。
入参校验:若 JSON 既无有效 wlPoints(size ≥ 2)也无非空 stack,命令直接报 FS_PROC_C_BAD_PARAMS —— 避免"成功直通什么也没做"的歧义返回。空 {}、{ "version": 1 }、{ "stack": [] } 都属此类。
FIX 端 spdlog 记录:
[ImageProc.filter.applyEffect] src=inline version=1 wlPts=3 (apply=true) stack[3]: filter.clahe → filter.gamma → filter.um
[ImageProc.filter.applyEffect] step 1/3 filter=filter.clahe params=windowSize=80,clipLimit=40.0,iterations=1 took 142ms
[ImageProc.filter.applyEffect] step 2/3 filter=filter.gamma params=gamma=0.5 took 3ms
[ImageProc.filter.applyEffect] step 3/3 filter=filter.um params=radius=2.0,amount=0.8 took 18ms
resultJson 不额外回写元信息(避免无谓字节);客户端拿到 procStatus == OK 即视为成功。
filter.applyEffect 在每一步开始前和整命令完成时发 progress 信号,让客户端能显示 step-level 进度:
progress(0, N, "applyEffect: step 1/N filter.clahe")
progress(1, N, "applyEffect: step 2/N filter.gamma")
...
progress(N, N, "applyEffect: done")
参数:done、total = stack 长度、message 是 "applyEffect: step i/N <filterName>" 格式,<filterName> 与 stack[i].filter 一致。
嵌套:filter.sr 内部还会发自己的 tile 级进度(
"SR tile X/Y batch=N"),所以 done 数值不严格单调 —— 进入 SR 步骤时 done 会回到 0~tileCount 范围。客户端如果做进度条,建议按 message 前缀判断:"applyEffect: step"= 整体进度;"SR tile"= 当前 SR 内部进度。
方式 A:inline(推荐,最灵活)
FSImageProcParamsC p{};
p.command = "filter.applyEffect";
p.paramsJson = R"({
"filter.applyEffect.jsonInline": {
"version": 1,
"wlPoints": ["0,0", "127.5,127.5", "255,255"],
"stack": [
{ "filter": "filter.clahe", "params": { "windowSize": 80, "clipLimit": 40.0, "iterations": 1 } },
{ "filter": "filter.gamma", "params": { "gamma": 0.5 } }
]
}
})";
p.timeoutMs = 60000;
FSImageProcResultC r{};
int rc = fsChannelSendImageProcAndWait(ch, &p,
inputBytes, rows, cols, channels,
FS_IMAGE_C_RGB24,
static_cast<uint64_t>(cols) * channels,
&r);
方式 B:jsonPath(client 已知 FIX 存的文件位置)
p.paramsJson = R"({
"filter.applyEffect.jsonPath": "Z:/effects/teach_2026_05_15.json"
})";
方式 C:从 FIX UI 端直接抓 .json 内容塞进 inline
QFile f("Z:/effects/foo.json");
f.open(QIODevice::ReadOnly);
QJsonDocument doc = QJsonDocument::fromJson(f.readAll());
QJsonObject top;
top["filter.applyEffect.jsonInline"] = doc.object();
QByteArray bytes = QJsonDocument(top).toJson(QJsonDocument::Compact);
p.paramsJson = bytes.constData();
互补关系:
filter.<X> 单命令:参数键风格 SHM-native (filter.sr.scaleMode 等),适合"只跑一次 CLAHE"filter.applyEffect:参数键风格 W/L widget-native (outputScale/ratio/gamma 等),适合"复现整套 UI 效果"两条路最终调用相同的滤镜实现,结果一致。
| 值 | 名称 | 含义 | 处理建议 |
|---|---|---|---|
| 0 | FS_PROC_C_OK |
成功 | 用 result.outImage |
| -100 | FS_PROC_C_BAD_COMMAND |
命令名错(拼写错或前缀不对) | 检查 params.command |
| -101 | FS_PROC_C_BAD_PARAMS |
JSON 参数解析失败 | 检查 JSON 语法、字段名前缀 |
| -102 | FS_PROC_C_BAD_INPUT |
图像类型/通道不支持 | 转 BGR24 / GRAY8 |
| -103 | FS_PROC_C_GPU_UNAVAIL |
服务端 SR 推理能力不可用 | filter.sr 才会触发;其它命令不应出现此错 |
| -104 | FS_PROC_C_OOM |
服务端内存耗尽 | 改用更小的 scaleMode(如 scale2/scale1) |
| -105 | FS_PROC_C_CANCELED |
客户端取消 | 检查取消逻辑 |
| -106 | FS_PROC_C_TIMEOUT |
超时 | 提高 timeoutMs |
| -200 | FS_PROC_C_INTERNAL |
推理/处理内部错 | 看 result.errorMsg |
客户端 fsChannelSendImageProcAndWait("filter.<name>", ...)
│
│ 共享内存写包 (协议头 + JSON 参数 + 图像字节)
▼
服务端入队(FIFO 串行)
│
▼
按 cmd 路由到对应 filter 处理器
│
▼
output → 共享内存回传 / 服务端落盘 → 客户端
fixSharedMemory_dll_README.md — 协议总览、命令家族分布、共享内存配置