OpencvSharp 算子学习教案之 - Cv2.Subtract 重载2

OpencvSharp 算子学习教案之 - Cv2.Subtract 重载2

重载2:Subtract(InputArray src1, Scalar src2, OutputArray dst, InputArray? mask = null, int dtype = -1)

大家好,Opencv在很多工程项目中都会用到,而OpencvSharp则是以C#开发与实现的Opencv操作库,对.NET开发人员友好,但很多API的中文资料、应用场景及常见坑点等缺乏系统性归纳,因此这系列博客将给大家带来Cv2及Mat对象全系列算子学习教案,供大家参考学习。

Cv2.Subtract

  • 教案版本:V1.0
  • 面向对象:OpenCvSharp 初学者
  • 所属模块:core
  • 源码位置:OpenCvSharp/Cv2/Cv2_core.cs:131

1. 函数名称(带参数签名)

csharp 复制代码
public static void Subtract(
    InputArray src1,
    Scalar src2,
    OutputArray dst,
    InputArray? mask = null,
    int dtype = -1)

2. 函数用途

这是 Subtract 的"数组减标量"重载,用来把一个常量从整张矩阵里逐元素减掉。

常见用途包括:

  1. 亮度偏置修正。
  2. 统一减去背景常数。
  3. 做阈值偏移或基准线扣除。
  4. 配合 mask 只让局部区域发生变化。

3. 函数公式

当 src2 是标量时,可以理解为把这个标量扩展成与输入同形状的常量数组,然后再执行逐元素相减:

dst(I)=saturate⁡(src1(I)−src2) dst(I) = \operatorname{saturate}(src1(I) - src2) dst(I)=saturate(src1(I)−src2)

如果提供 mask,只有 mask(I) \ne 0 的位置才会写入:

dst(I)←{saturate⁡(src1(I)−src2),mask(I)≠0dst(I),mask(I)=0 dst(I) \leftarrow \begin{cases} \operatorname{saturate}(src1(I) - src2), & mask(I) \ne 0 \\ dst(I), & mask(I) = 0 \end{cases} dst(I)←{saturate(src1(I)−src2),dst(I),mask(I)=0mask(I)=0

对于多通道数组,Scalar 会按通道参与运算;如果只有一个通道,则只使用第一个标量分量。

4. 函数原理说明

OpenCV 对这个重载的处理可以概括为:

  1. 把标量转换成可参与运算的内部表示。
  2. 对每个元素做减法。
  3. 根据 dtype 进行类型转换或饱和裁剪。
  4. 如果有 mask,只在命中的位置写入 dst。

对初学者来说,这个重载最有价值的地方是:

  1. 你不需要显式创建一张"全是常数"的矩阵。
  2. 在做偏移修正时,它比先构造常量矩阵更直接。
  3. 如果输出类型选择得当,负数可以保留下来,便于观察真实差值。

5. 参数含义解析

参数名 类型 必填 含义
src1 InputArray 是 左操作数矩阵
src2 Scalar 是 被减去的标量常数
dst OutputArray 是 输出结果
mask InputArray? 否 8 位单通道掩码,只允许非零位置写入 dst
dtype int 否 输出深度,默认 -1 表示尽量沿用输入深度

6. 应用场景列表

场景名 场景说明 典型用途
场景A:偏置扣除 从每个像素中减去固定偏移量 亮度校正、零点修正
场景B:局部偏移修正 只在 mask 命中的区域做减法 ROI 亮度校准
场景C:保留负值 输出设为 signed 或 float,观察真实差值 残差、误差分析
场景D:标量基准线 把一条常量基准线减到图像里 基线校正、模板比较

7. 函数使用示例(与 WPF 场景一一对应)

说明:下面代码与 WPF 控件中的场景B对应。这个场景专门演示数组减标量,并把结果写到 CV_16S,这样负值也能保留下来。

csharp 复制代码
using OpenCvSharp;

// 输入矩阵,使用 8 位无符号整型保存。
var src1Data = new byte[,]
{
    { 10, 60, 100 },
    { 5, 200, 15 },
};

// 预先准备一个有明显数字的 dst,便于观察 mask 未命中的位置是否保留原值。
var seedData = new short[,]
{
    { 999, 999, 999 },
    { 999, 999, 999 },
};

var maskData = new byte[,]
{
    { 255, 0, 255 },
    { 0, 255, 0 },
};

using var src1 = Mat.FromPixelData(2, 3, MatType.CV_8UC1, src1Data);
using var mask = Mat.FromPixelData(2, 3, MatType.CV_8UC1, maskData);
using var dst = Mat.FromPixelData(2, 3, MatType.CV_16SC1, seedData);

// 这里减去常数 40,并把输出深度显式设为 CV_16S,便于保留负值。
Cv2.Subtract(src1, new Scalar(40), dst, mask, dtype: MatType.CV_16S);

// 例如 10 - 40 = -30,5 - 40 = -35,这些负值在 16S 中会被保留下来。

8. 函数使用注意事项

  1. Scalar 会按标量常数参与运算,不需要你手工扩展成矩阵。
  2. 如果输出是无符号类型,负值会被裁剪到 0。
  3. 如果你要保留负值,优先考虑 CV_16S 或 CV_32F。
  4. mask 只控制写入,不改变减法本身。
  5. 当 src1 深度与目标输出深度差异较大时,显式设置 dtype 更安全。

9. 参数调优建议

  1. 亮度偏移类任务通常可以先试 CV_16S,看差值是否有负数。
  2. 如果后续还要做浮点运算,直接输出 CV_32F 更省一步转换。
  3. 用 mask 做局部修正时,先准备一个容易看出变化的 dst 初值。
  4. 若只是想看图像显示效果,CV_8U 也可以,但要接受负值裁剪为 0。

10. 示例代码运行说明(按场景关键逻辑)

  1. 准备一个 CV_8UC1 输入矩阵。
  2. 准备一个 8 位单通道 mask,只让部分位置写入。
  3. 把 dst 预填成 999,方便观察未命中的像素是否保留原值。
  4. 调用 Cv2.Subtract(src1, new Scalar(40), dst, mask, dtype: MatType.CV_16S)。
  5. 检查负值是否保留,以及 mask 没命中的位置是否保持 999。

11. 常见错误排查

  1. 错误:以为标量会自动变成一张常量矩阵
    • 排查:Scalar 本身就会在内部参与运算,不需要自己扩展成矩阵。
  2. 错误:希望负值在 CV_8U 里保留
    • 排查:改用 CV_16S 或 CV_32F。
  3. 错误:mask 不是 8 位单通道
    • 排查:使用 CV_8UC1 掩码。
  4. 错误:忘记显式指定输出深度
    • 排查:尤其在输入和输出类型不一致时,请写明 dtype。
  5. 错误:把 src2 看成矩阵而不是常量
    • 排查:这是"数组减标量",常量是对每个元素重复应用的。

对应 WPF 演示控件与样例代码:

  • Features/Cv2Subtract/Cv2SubtractControl.xaml
  • Samples/Cv2Subtract/SubtractArrayScalarSample.cs
相关推荐
星恒随风8 小时前
Linux线程概念详解:从分页存储、页表、MMU与TLB,深入理解线程和进程的区别与联系
linux·运维·笔记·学习·状态模式
qq_284274058 小时前
数控机床编程基础与坐标系:编程六步流程、程序号/程序段/程序字格式,与右手定则下车床铣床XYZ轴判定(含考点)
笔记·学习·自动化·制造
德林恩宝8 小时前
On-Policy Distillation(OPD)学习文档
人工智能·学习·机器学习·大模型·llm·大模型微调
xxwl5859 小时前
区域赛分类题解
c++·笔记·学习·算法
用户7884773163411 小时前
用 C# 把每周 6 小时的 PDF 录入干到 20 分钟:一份可复制的桌面 OCR 方案
c#
csdn_aspnet13 小时前
C# .NetCore Swagger ISchemaFilter 处理枚举、特殊类型
c#·.netcore·swagger
滴滴答答哒13 小时前
C# 技巧:优雅实现对象的“局部更新”与“字段合并”
开发语言·c#
xxwl58513 小时前
区域赛算法模版第八章---贪心(Greedy)
c++·笔记·学习·算法
qq_2842740514 小时前
S7-1200 PLC硬件与启保停实训:CPU选型与DC/DC/DC、循环扫描五阶段、博途组态及电动机启停自锁梯形图(含考点)
笔记·学习·自动化·制造
dear_bi_MyOnly15 小时前
栈和队列:从原理到应用全解析
c语言·开发语言·c++·学习·分类