OpenCvSharp函数:Sobel边缘检测、Scharr边缘检测、GetDerivKernels获取图像导数的滤波系数

Sobel边缘检测

函数说明

使用扩展Sobel算子计算一阶、二阶、三阶或混合图像的导数。当核的大小ksize不为1时,用ksize X ksize的可分离核求导;为1时,用 3 X 1 或 1 X 3的核(不进行高斯平滑)只对一阶或二阶的x轴或y同求导。
当ksze = FILTER_SCHARR(即-1)时,使用Scharr 3x3的核获得更精确的结果,具体见下文
该函数通过将图像与适当的核卷积来计算图像导数:

dst = ∂ x o r d e r + y o r d e r src ∂ x x o r d e r ∂ y y o r d e r \texttt{dst} = \frac{\partial^{xorder+yorder} \texttt{src}}{\partial x^{xorder} \partial y^{yorder}} dst=xxorderyyorderxorder+yordersrc


Sobel算子组合了高斯平滑和微分,具有一定的搞噪能力。常用的参数有(xorder =1,yorder =0,ksize = 3)或(xorder = 0,yorder = 1,ksize = 3)来计算第一个x或y的图像导数。
水平方向(x轴)的核为

[ − 1 0 1 − 2 0 2 − 1 0 1 ] \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1\end{bmatrix} 121000121

垂直方向(y轴)的核为

[ − 1 − 2 − 1 0 0 0 1 2 1 ] \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1\end{bmatrix} 101202101

函数原型

void Sobel(InputArray src,
	OutputArray dst,
	MatType ddepth,
	int xorder,
	int yorder,
	int ksize = 3,
	double scale = 1.0,
	double delta = 0.0,
	BorderTypes borderType = BorderTypes.Reflect101)

参数说明

参数说明                            
InputArray src输入图像, 一般为灰度图
OutputArray dst输出图像。大小与通道数与输入图像一致
MatType ddepth期望的输出深度,具体见Depth combinations表
int xorder导数x的阶数
int yorder导数y的阶数
int ksize核大小,必须为-1、1、3、5或7(-1时使用Scharr 3X3)
double scale计算的导数值的可选比例因子,默认为1。
double delta计算结果上加该值,可理解为调亮(正数)或调暗(负数)
BorderTypes borderType边框外像素取值方法,不支持Wrap

图像示例

Sobel水平边缘
Sobel水平边缘

Sobel垂直边缘

Sobel垂直边缘
Sobel边缘检测结果
Sobel边缘检测结果

GetDerivKernels获取图像导数的滤波系数

函数说明

获取用于计算图像导数的滤波系数。当ksize=FILTER_SCHARR(即-1)时,返回 3 x 3的Scharr核,其它情况返回Soble内核。通常结果用于SepFilter2D。

函数原型

void GetDerivKernels(OutputArray kx,
	OutputArray ky,
	int dx,
	int dy,
	int ksize,
	bool normalize = false,
	MatType? ktype = null)

参数说明

 参数 说明                   
OutputArray kx行滤波系数的输出矩阵,类型为ktype
OutputArray ky列滤波系数的输出矩阵,类型为ktype
int dx导数x的阶数
int dy导数y的阶数
int ksize核大小,可为-1,1,3,5,7
bool normalize是否标准化(按比例缩小)滤波系数。理论上,系数应该有分母 = 2 k s i z e ∗ 2 − d x − d y − 2 =2^{ksize*2-dx-dy-2} =2ksize2dxdy2。如果对浮点图像滤波,则设为true。
如果是8位图像,结果为16位,则设为False。默认为False
MatType? ktype滤波系数的类型。CV_32F或CV_64F。null时为CV_32F

Scharr边缘检测

函数说明

使用Scharr算子计算图像的x、y轴一阶导数。

Scharr(src,   dst,   ddepth,   dx,   dy,   scale,   delta,   borderType) \texttt{Scharr(src, dst, ddepth, dx, dy, scale, delta, borderType)} Scharr(src, dst, ddepth, dx, dy, scale, delta, borderType)

等价于

Sobel(src,   dst,   ddepth,   dx,   dy,   -1,   scale,   delta,   borderType) \texttt{Sobel(src, dst, ddepth, dx, dy, -1, scale, delta, borderType)} Sobel(src, dst, ddepth, dx, dy, -1, scale, delta, borderType)

水平方向(x轴)的核为

[ − 3 0 3 − 10 0 10 − 3 0 3 ] \begin{bmatrix} -3 & 0 & 3 \\ -10 & 0 & 10 \\ -3 & 0 & 3\end{bmatrix} 31030003103

垂直方向(y轴)的核为

[ − 3 − 10 3 0 0 0 3 10 3 ] \begin{bmatrix} -3 & -10 & 3 \\ 0 & 0 & 0 \\ 3 & 10 & 3\end{bmatrix} 30310010303

函数原型

void Scharr(InputArray src,
	OutputArray dst,
	MatType ddepth,
	int xorder,
	int yorder,
	double scale = 1.0,
	double delta = 0.0,
	BorderTypes borderType = BorderTypes.Reflect101)

参数说明

参数说明                            
InputArray src输入图像, 一般为灰度图
OutputArray dst输出图像。大小与通道数与输入图像一致
MatType ddepth期望的输出深度,具体见Depth combinations表
int xorder导数x的阶数
int yorder导数y的阶数
double scale计算的导数值的可选比例因子,默认为1。
double delta计算结果上加该值,可理解为调亮(正数)或调暗(负数)
BorderTypes borderType边框外像素取值方法,不支持Wrap

图像示例

Scharr水平、垂直边缘
Scharr边缘检测

Sobel与Canny

Sobel边缘检测:效率高,有一定抗噪,但对纹理细节不够精确,
Canny边缘检测:精度比Sobel高,最效率没Sobel高

代码示例

Mat src;
string winName = "Sobel & Scharr Demo";
string funType = "S";

public void Run(ParamBase paramBase)
{
    //测试GetDerivKernels结果
    using var dx = new Mat();
    using var dy = new Mat();
    Cv2.GetDerivKernels(dx, dy, 1, 0, -1,false);
    //控制台输出dx、dy
    Utils.Dump(dx);
    Utils.Dump(dy);

    //弹出文件选择对话框
    if (!Utils.SelectFile(out string fileName)) fileName = ImagePath.Lena;
    //var fileName = ImagePath.Lena;
    src = Cv2.ImRead(fileName, ImreadModes.Color);
    if (src.Empty()) throw new Exception($"图像打开有误:{fileName}");

    //高斯滤波
    Cv2.GaussianBlur(src, src, new Size(3, 3), 0, 0);

    //一般对灰度图进行Sobel或SChar边缘检测
    Cv2.CvtColor(src, src, ColorConversionCodes.BGR2GRAY);

    Cv2.NamedWindow(winName, WindowFlags.Normal);
    Cv2.CreateTrackbar("kSize 2n-1", winName, 4, KSizeOnChanged);
    Cv2.SetTrackbarPos("kSize 2n-1", winName, 2);

    Cv2.CreateTrackbar("scale n/10", winName, 100, SCaleOnChanged);
    Cv2.SetTrackbarPos("scale n/10", winName, 10);

    Cv2.CreateTrackbar("Delta n-50", winName, 100, DeltaOnChanged);
    Cv2.SetTrackbarPos("Delta n-50", winName, 50);

    bool loop = true;
    while (loop)
    {
        var c = (Char)Cv2.WaitKey(50);
        switch(c)
        {
            case 's':
            case 'S':
                funType= "S";
                OnChanged();
                break;
            case 'c':
            case 'C':
                funType = "C";
                OnChanged();
                break;
            case 'q':
            case 'Q':
            case (Char)27:
                loop = false;
                break;
            default:
                break;
        }
    }
    Cv2.DestroyAllWindows();
}
private void OnChanged()
{
    using var gradX = new Mat();
    using var gradY = new Mat();
    string text = "";
    if (funType == "S")
    {
        Cv2.SetWindowTitle(winName, "Sobel 按S/C切换,Esc退出");
        Cv2.Sobel(src, gradX, MatType.CV_16S, 1, 0, kSize, scale, delta);
        Cv2.Sobel(src, gradY, MatType.CV_16S, 0, 1, kSize, scale, delta);
        text = $"kSize={kSize},scale={scale.ToString("0.0")},delta={delta}";
    }
    else
    {
        Cv2.SetWindowTitle(winName, "Scharr 按S/C切换,Esc退出");
        Cv2.Scharr(src, gradX, MatType.CV_16S, 1, 0, scale, delta);
        Cv2.Scharr(src, gradY, MatType.CV_16S, 0, 1, scale, delta);
        text = $"scale={scale.ToString("0.0")},delta={delta}";
    }
    Cv2.ConvertScaleAbs(gradX, gradX);
    Cv2.ImShow("水平边缘", gradX);
    Cv2.ConvertScaleAbs(gradY, gradY);
    Cv2.ImShow("垂直边缘", gradY);
    using var dst = new Mat();
    //合并水平、垂直图像
    Cv2.AddWeighted(gradX, 0.5, gradY, 0.5, 0, dst);
    Utils.PutText(dst, text);
    Cv2.ImShow(winName, dst);
}

int kSize = 3;
private void KSizeOnChanged(int pos, IntPtr userData)
{
    kSize = pos * 2 - 1;
    OnChanged();
}

double scale = 1;
private void SCaleOnChanged(int pos,IntPtr userData)
{
    scale = pos / 10.0D;
    OnChanged();
}

double delta = 0;
private void DeltaOnChanged(int pos,IntPtr userData)
{
    delta = pos - 50;
    OnChanged();
}

OpenCvSharp函数示例(目录)
参考
https://docs.opencv.org/4.7.0/d2/d2c/tutorial_sobel_derivatives.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenCVSharp 是一个用于计算机视觉的 C# 接口,它实现了 OpenCV 库的操作。在 OpenCVSharp 中,边缘检测是一项非常重要的任务,可以帮助我们找到图像中的物体轮廓,或者是进行图像分割等任务。 下面介绍几种 OpenCVSharp 中常用的边缘检测算法: 1. Canny 算法 Canny 算法是一种经典的边缘检测算法,它通过计算图像中像素点的梯度值,并进行非极大值抑制、双阈值处理等操作,最终得到图像中的边缘信息。在 OpenCVSharp 中,可以使用以下代码来进行 Canny 边缘检测: ```csharp Mat src = Cv2.ImRead("input.jpg", ImreadModes.Grayscale); Mat dst = new Mat(); Cv2.Canny(src, dst, 100, 200); Cv2.ImShow("Canny", dst); Cv2.WaitKey(0); ``` 2. Sobel 算法 Sobel 算法是一种基于梯度的边缘检测算法,它利用图像中像素点的梯度信息来检测边缘。在 OpenCVSharp 中,可以使用以下代码来进行 Sobel 边缘检测: ```csharp Mat src = Cv2.ImRead("input.jpg", ImreadModes.Grayscale); Mat dst = new Mat(); Cv2.Sobel(src, dst, MatType.CV_8U, 1, 1); Cv2.ImShow("Sobel", dst); Cv2.WaitKey(0); ``` 3. Laplacian 算法 Laplacian 算法是一种基于二阶导数边缘检测算法,它可以检测出图像中的高频部分,从而得到图像的边缘信息。在 OpenCVSharp 中,可以使用以下代码来进行 Laplacian 边缘检测: ```csharp Mat src = Cv2.ImRead("input.jpg", ImreadModes.Grayscale); Mat dst = new Mat(); Cv2.Laplacian(src, dst, MatType.CV_8U); Cv2.ImShow("Laplacian", dst); Cv2.WaitKey(0); ``` 以上是 OpenCVSharp 中常用的几种边缘检测算法,不同的算法适用于不同的场景,可以根据具体需求选择合适的算法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值