OpenCvSharp函数:Dilate膨胀、GetStructuringElement获取形态操作的结构元素、Erode腐蚀

Dilate膨胀

函数说明:用特定的结构元素膨胀图像。膨胀可以看成是最大值滤波,即用最大值替换中心像素点。该函数就地模式,可以指定迭代次数,多通道图像的话,每个通道分开处理。

用3x3矩形结构元素膨胀

//函数原型
void Dilate(InputArray src,
    OutputArray dst,
    InputArray? element,
    Point? anchor = null,
    int iterations = 1,
    BorderTypes borderType = BorderTypes.Constant,
    Scalar? borderValue = null)

参数

说明

InputArray src

输入图像,通道数可以任意,类型必须为CV_8U,CV_16U, CV_16S, CV_32F或CV_64F。

OutputArray dst

输出图像,与输入图像有相同的大小、类型和通道数。(支持就地模式)

InputArray? element

用于膨胀的结构元素。为null或空Mat时,默认使用3x3矩形结构元素。可通过GetStructuringElement函数生成。

Point? anchor = null

锚点,结构元素的锚点。默认为(-1,-1),表示结构元素的中心点

int iterations = 1

膨胀的次数

BorderTypes borderType = BorderTypes.Constant

边界填充方式。不支持Wrap方式

Scalar? borderValue = null

当边界填充方式为Constant时的填充值,默认是Scalar.All(double.MaxValue)

GetStructuringElement获取形态操作的结构元素

函数说明:返回一个指定大小、形状的结构元素,用于膨胀、腐蚀或其它形态操作。

//函数原型1
Mat GetStructuringElement(MorphShapes shape,
    Size ksize)

//函数原型2
Mat GetStructuringElement(MorphShapes shape, Size ksize, Point anchor)

参数

说明

MorphShapes shape

形态形状:Rect矩形、Cross十字、Ellipse椭圆

Size ksize

元素大小

Point anchor

元素内的锚定位置。默认值(-1,-1)表示锚点位于中心。注意,只有十字形元素的形状取决于锚点位置。在其他情况下,锚只是调节形态学操作的结果被转移了多少。

返回值Mat

结构元素矩阵

Erode腐蚀

函数说明:用特定的结构元素腐蚀图像。腐蚀可以看成是最小值滤波,即用最小值替换中心像素点。

该函数就地模式,可以指定迭代次数,多通道图像的话,每个通道分开处理。

用3x3矩形结构元素腐蚀

//函数原型
void Erode(InputArray src,
    OutputArray dst,
    InputArray? element,
    Point? anchor = null,
    int iterations = 1,
    BorderTypes borderType = BorderTypes.Constant,
    Scalar? borderValue = null)

参数

说明

InputArray src

输入图像,通道数可以任意,类型必须为CV_8U,CV_16U, CV_16S, CV_32F或CV_64F。

OutputArray dst

输出图像,与输入图像有相同的大小、类型和通道数。

(支持就地模式)

InputArray? element

用于腐蚀的结构元素。为null或空Mat时,默认使用3x3矩形结构元素。可通过GetStructuringElement函数生成。

Point? anchor = null

锚点,结构元素的锚点。

默认为(-1,-1),表示结构元素的中心点

int iterations = 1

腐蚀次数

BorderTypes borderType = BorderTypes.Constant

边界填充方式。

不支持Wrap方式

Scalar? borderValue = null

当边界填充方式为Constant时的填充值,默认是Scalar.All(double.MaxValue)

图像示例

原图

膨胀与腐蚀

定位下划线位置

源码示例

public void Run() {
    TestDilateAndErode();
    MorphologyDemo();
    LocateGapFilling();
}

/// <summary>
/// 定位下划线
/// </summary>
/// <exception cref="Exception"></exception>
private void LocateGapFilling() {
    using (var src = Cv2.ImRead(ImagePath.GapFilling, ImreadModes.Grayscale)) {
        if (src.Empty()) throw new Exception($"图像打开有误:{ImagePath.GapFilling}");
        Cv2.Threshold(src, src, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.BinaryInv);
        Cv2.ImShow("GapFilling", src);

        using var dst = new Mat();

        var element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(15, 1));
        //可消除部分垂直线
        Cv2.Erode(src, dst, element);
        ShowMat("Location", element, dst);

        Cv2.WaitKey();
        Cv2.DestroyAllWindows();
    }
}

/// <summary>
/// 膨胀、腐蚀
/// </summary>
/// <exception cref="Exception"></exception>
private void MorphologyDemo() {
    using (var src = Cv2.ImRead(ImagePath.Morphology, ImreadModes.Grayscale)) {
        if (src.Empty()) throw new Exception($"图像打开有误:{ImagePath.Morphology}");
        Cv2.Threshold(src, src, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary);
        Cv2.ImShow("gray", src);

        using var dst = new Mat();

        var element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(15, 15));
        //膨胀
        Cv2.Dilate(src, dst, element);
        ShowMat("Dilate Rect", element, dst);

        //腐蚀
        Cv2.Erode(src, dst, element);
        ShowMat("Erode Rect", element, dst);

        Cv2.WaitKey();
        Cv2.DestroyAllWindows();
    }
}

private void ShowMat(string winNameFix, Mat element, Mat dst) {
    Cv2.ImShow($"{winNameFix},{element.Size()}", dst);
}


/// <summary>
/// 演示Dilate与Erode,细看其中的不同。
/// 注意:一幅图像膨胀后再腐蚀的图像,不一定与原图一样。
/// </summary>
private void TestDilateAndErode() {
    using (var mat = new Mat(11, 15, MatType.CV_8UC1, new byte[] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                                                                   0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,
                                                                   0,0,1,1,1,0,0,0,0,0,1,1,1,0,0,
                                                                   0,0,1,1,1,0,0,0,0,0,1,1,1,0,0,
                                                                   0,0,0,1,1,0,0,0,0,0,1,1,1,0,0,
                                                                   0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,
                                                                   0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,
                                                                   0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,
                                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0})) {
        Helper.Dump(mat);

        var element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
        //膨胀
        Cv2.Dilate(mat, mat, null, iterations: 2);
        Console.WriteLine("Dilate X 2");
        Dump(mat);


        using var dst = new Mat();

        //加上空白边缘
        Cv2.CopyMakeBorder(mat, dst, 1, 1, 1, 1, BorderTypes.Constant, new Scalar(0, 0, 0));
        Cv2.Erode(mat, mat, null);
        Console.WriteLine("The first time of Erode");
        Dump(mat);
        Cv2.Erode(mat, mat, null);
        //可连接腐蚀多次
        //Cv2.Erode(mat,mat,null,iterations: 2);
        Console.WriteLine("The second time of Erode");
        Dump(mat);

        //加了空白边缘的图像
        Console.WriteLine("dst");
        Dump(dst);

        //对比前面的腐蚀结果
        //腐蚀
        Cv2.Erode(dst, dst, null);
        Console.WriteLine("ErodeX1");
        Dump(dst);

        Cv2.Erode(dst, dst, null);
        Console.WriteLine("ErodeX2");
        Dump(dst);
    }
}

#region Dump
/// <summary>
/// 控制台显示矩阵
/// </summary>
/// <param name="mat">待显示的矩阵</param>
/// <param name="dumpChannel">要显示通道</param>
public static void Dump(Mat mat, FormatType formatType = FormatType.Default) {
    Dump(mat, new OpenCvSharp.Range(0, mat.Channels() - 1), formatType);
}
/// <summary>
/// 控制台显示矩阵
/// </summary>
/// <param name="mat">等显示的矩阵</param>
/// <param name="channelRange">要显示的通道范围</param>
public static void Dump(Mat mat, OpenCvSharp.Range channelRange, FormatType formatType = FormatType.Default) {
    var nChannels = mat.Channels();
    if (nChannels == 1) {
        Console.WriteLine(mat.Dump(formatType));
        return;
    }
    var splits = mat.Split();
    for (int c = channelRange.Start; c <= channelRange.End; c++) {
        if (c < nChannels) {
            Console.WriteLine(splits[c].Dump(formatType));
        }
        else {
            Console.WriteLine($"通道值{c}必须小于{nChannels}");
        }
    }
}
#endregion

OpenCvSharp函数示例(目录)

参考

https://docs.opencv.org/

https://edu.csdn.net/learn/38286/608282

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

图南科技

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

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

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

打赏作者

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

抵扣说明:

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

余额充值