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

猜你喜欢

转载自blog.csdn.net/TyroneKing/article/details/130181962