OpenCvSharp函数:Filter2D线性滤波、SepFilter2D可分离线性滤波

本文介绍了OpenCV中的Filter2D和SepFilter2D函数,用于实现图像的线性滤波。Filter2D执行相关运算而非卷积,SepFilter2D则用于可分离线性滤波,提高效率。文章详细阐述了函数参数及使用示例,包括内核定义、边界处理和效果展示。
摘要由CSDN通过智能技术生成

Filter2D线性滤波

函数说明:可实现对图像应用任意线性滤波器。支持就地操作。边界像素取值可参考CopyMakeBorder
该函数实际计算相关性,而非卷积:

dst ( x , y ) = ∑ 0 ≤ x ′ < kernel.cols 0 ≤ y ′ < kernel.rows kernel ( x ′ , y ′ ) ∗ src ( x + x ′ − anchor.x , y + y ′ − anchor.y ) \texttt{dst} (x,y) = \sum _{ \substack{0\leq x' < \texttt{kernel.cols}\\{0\leq y' < \texttt{kernel.rows}}}} \texttt{kernel} (x',y')* \texttt{src} (x+x'- \texttt{anchor.x} ,y+y'- \texttt{anchor.y} ) dst(x,y)=0x<kernel.cols0y<kernel.rowskernel(x,y)src(x+xanchor.x,y+yanchor.y)

即,内核不是围绕锚点镜像的。如果你需要做卷积,可使用Flip函数对核进行翻转并将锚点设置为(kernel.cols - anchro.x - 1,kernel.rows - anchor.y -1)。 当核大小大于等于(11x11)时,基于DFT(离散傅里叶变换)算法,小内核时使用直接算法。
//函数原型
void Filter2D(InputArray src,
	OutputArray dst,
	MatType ddepth,
	InputArray kernel,
	Point? anchor = null,
	double delta = 0.0,
	BorderTypes borderType = BorderTypes.Reflect101)`
参数说明                            
InputArray src输入图像
OutputArray dst输出图像。大小与通道数与输入图像一致
MatType ddepth期望的输出深度,具体见Depth combinations表
InputArray kernel卷积核(相关性内核):单通道浮点型矩阵。如果想对不同通道使用不同核,可先将图像用Split进行分离单独处理
Point? anchor核的锚点,默认值为null或(-1,-1),表示核的中心点
double delta计算结果上加该值,可理解为调亮(正数)或调暗(负数)
BorderTypes borderType边框外像素取值方法,不支持Wrap

Depth combinations

输入深度(Src.Depth()输出深度(-1表示与输入深度相同)                   
CV_8U-1/CV_16S/CV_32F/CV_64F
CV_16U/CV_16S-1/CV_32F/CV_64F
CV_32F-1/CV_32F
CV_64F-1/CV_64F

SepFilter2D可分离线性滤波

函数说明:对图像进行可分离线性滤波。首先用一维核KernelX对每一行进行滤波计算,再用一维核KernelY对每一列进行滤波计算,再将结果与Delta进行相加生成最终图像。

//函数原型
void SepFilter2D(InputArray src,
	OutputArray dst,
	MatType ddepth,
	InputArray kernelX,
	InputArray kernelY,
	Point? anchor = null,
	double delta = 0.0,
	BorderTypes borderType = BorderTypes.Reflect101)
参数说明                            
InputArray src输入图像
OutputArray dst输出图像。大小与通道数与输入图像一致
MatType ddepth期望的输出深度,具体见Depth combinations表
InputArray kernelX行滤波核(必须为一维,cols或rows等于1)
InputArray kernelY列滤波核(必须为一维,cols或rows等于1)
Point? anchor核的锚点,默认值为null或(-1,-1),表示核的中心点
double delta计算结果上加该值,可理解为调亮(正数)或调暗(负数)
BorderTypes borderType边框外像素取值方法,不支持Wrap

目的

使用指定大小的核对所选图像进行Filter2D和SepFilter2D线性滤波
当核为3x3时,计算公式如下

K = 1 3 ⋅ 3 [ 1 1 1 1 1 1 1 1 1 ] K = \dfrac{1}{3 \cdot 3} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix} K=331 111111111

程序可拖动滚动条指定核大小和Delta的值

图像示例

Filter2D示例
SepFilter2D示例

代码示例

Mat src;
string winName = "Filter2D Demo Esc:退出";

double delta = 0;
public void Run()
{
    //如果未选择图像,则用默认的Lena
    if (!Utils.SelectFile(out string fileName)) fileName = ImagePath.Lena;
    src = Cv2.ImRead(fileName, ImreadModes.Color);
    if (src.Empty()) throw new Exception($"图像打开有误:{fileName}");
    Cv2.NamedWindow(winName, WindowFlags.Normal);
    Cv2.CreateTrackbar("Size 2n+1", winName, 30, SizeOnChanged);
    Cv2.CreateTrackbar("Delta n-100", winName, 200, DeltaOnChanged);
    Cv2.SetTrackbarPos("Delta n-100", winName, 100);
    while(true)
    {
        //Esc退出
        if ((Cv2.WaitKey(50) == 27)) break;
    }
    Cv2.DestroyAllWindows();
}

private void OnChanged()
{
    Mat kernel = Mat.Ones(new Size(kernelSize, kernelSize), MatType.CV_32F) / (float)(kernelSize * kernelSize);
    using var filter2DResult = new Mat();
    Cv2.Filter2D(src, filter2DResult, -1, kernel, null, delta, BorderTypes.Default);
   
    Utils.PutText(filter2DResult, $"Size={kernelSize},delta={delta.ToString("0.0")}");
    Cv2.ImShow(winName, filter2DResult);

    using var sepFilter2DResult = new Mat();

    Mat kernelX = Mat.Ones(new Size(kernelSize, 1), MatType.CV_32F) / (float)kernelSize;
    Mat kernelY = Mat.Ones(new Size(1, kernelSize), MatType.CV_32F) / (float)kernelSize;
    //kernelX与kernelY必须是一维(cols或rows其中一个必须为1)
    Cv2.SepFilter2D(src, sepFilter2DResult, -1, kernelX, kernelY, null, delta, BorderTypes.Default);
    // 只要核的cols或rows为1,也可以这样调用,具体根据实际情况定义kernelX与kernelY
    //Cv2.SepFilter2D(src, dst2, -1, kernelY, kernelX, null, delta, BorderTypes.Default);

    Utils.PutText(sepFilter2DResult, $"Size={kernelSize},delta={delta.ToString("0.0")}");
    Cv2.NamedWindow("SepFilter2D", WindowFlags.Normal);
    Cv2.ImShow("SepFilter2D", sepFilter2DResult);
}

int kernelSize = 1;
/// <summary>
/// 改变核大小
/// </summary>
/// <param name="pos"></param>
/// <param name="userData"></param>
private void SizeOnChanged(int pos, IntPtr userData)
{
    kernelSize = pos * 2 + 1;
    OnChanged();
}
/// <summary>
/// 改变Delta值
/// </summary>
/// <param name="pos"></param>
/// <param name="userData"></param>
private void DeltaOnChanged(int pos, IntPtr userData)
{
    delta = pos -100;
    OnChanged();
}

OpenCvSharp函数示例(目录)
参考
https://docs.opencv.org/4.7.0/d4/dbd/tutorial_filter_2d.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图南科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值