OpenCvSharp函数:MorphologyEx形态操作

MorphologyEx形态操作

函数说明:高级形态操作,包含膨胀、腐蚀、开运算、闭运算、梯度、顶帽、黑帽和击中击不中操作。支持就地操作,可处理多通道图像,各通道分开处理。

//函数原型
void MorphologyEx(InputArray src,
    OutputArray dst,
    MorphTypes op,
    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。HitMiss时只能CV_8UC1。

OutputArray dst

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

MorphTypes op

形态操作类型

InputArray? element

结构元素,可通过GetStructuringElement生成

Point? anchor

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

int iterations

形态操作次数,默认为1次

BorderTypes borderType

边缘填充方式,不支持Wrap。

Scalar? borderValue

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

MorphTypes形态操作类型

说明

Erode

腐蚀

Dilate

膨胀

Open

开运算:先腐蚀,再膨胀。效果:删除小干扰块

dst=open(src,element)=dilate(erode(src,element))

Close

闭运算:先膨胀,再腐蚀。效果:填充封闭区域

dst=close(src,element)=erode(dilate(src,element))

Gradient

梯度操作:膨胀的结果减腐蚀的结果

dst=morph_grad(src,element)=dilate(src,element)−erode(src,element)

TopHat

顶帽操作:原图减开运算

dst=tophat(src,element)=src−open(src,element)

BlackHat

黑帽操作:闭运算 减 原图

dst=blackhat(src,element)=close(src,element)−src

HitMiss

击中与击不中操作:只支持CV-8UC1的二值图

图像示例

HitMiss击中与击不中

分析:图A为待测试的原图,使用图B当HitMiss的结构元素时得到图C,使用图D当HitMiss的结构元素时得到图E(注意,图C和图E右下角,有个边缘填充数字123)。图F、图G为击中时的两个示例。

网上关于HitMiss介绍的资料不多,自己分析,认为HitMiss的算法大概是,使用结构元素大小的核扫描原图,若结构元素中为1的位置在原图中也为1(结构元素为0的位置,不校验;结构元素为-1的位置,匹配原图的0),则在锚点位置标为1,表示击中;若不能完全匹配,则在锚点位置标为0,表示不击中。边缘的填充与填充方式和结构元素有关。

源码示例

private string winName = "MorphologyEx Demo";
int morph_elem = 0;//结构元素形状
int morph_size = 3;//结构元素大小,实际大小为2*morph_size+1
int morph_operator = 0;//形态操作类型
const int max_operator = 7;
const int max_elem = 2;
const int max_kernel_size = 21;

Mat src;
public void Run() {

    TestHitMiss();

    src = Cv2.ImRead(ImagePath.Morphology, ImreadModes.Color);
    if (src.Empty()) throw new Exception($"图像打开有误:{ImagePath.Morphology}");
    Cv2.ImShow("src", src);

    Cv2.NamedWindow(winName, WindowFlags.GuiExpanded);

    //滚动条拉动太多次时,会导致 morph_operator 值无法与pos一致?原因待分析。
    //形态操作类型
    Cv2.CreateTrackbar("Operator", winName, ref morph_operator, max_operator, Morphology_Operations);

    //结构元素形状
    Cv2.CreateTrackbar("Shapes", winName, ref morph_elem, max_elem, Morphology_Operations);

    //结构元素大小
    Cv2.CreateTrackbar("Size:2n +1", winName, ref morph_size, max_kernel_size, Morphology_Operations);

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

/// <summary>
/// 测试HitMiss
/// </summary>
private void TestHitMiss() {
    using (var src = 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,
                                                                   1,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})) {
        //控制台中输出矩阵,可参考https://blog.csdn.net/TyroneKing/article/details/129484746
        Helper.Dump(src);

        var element = new Mat(3, 3, MatType.CV_8UC1, new Byte[] {0,0,0,
                                                                 0,0,1,
                                                                 0,1,1});

        Helper.Dump(element);
        using var dst = new Mat();
        Cv2.MorphologyEx(src, dst, MorphTypes.HitMiss, element, borderValue: new Scalar(123));
        Helper.Dump(dst);


        element = new Mat(3, 3, MatType.CV_8UC1, new Byte[] {0,0,1,
                                                             0,0,1,
                                                             1,1,1});
        Helper.Dump(element);
        Cv2.MorphologyEx(src, dst, MorphTypes.HitMiss, element, borderValue: new Scalar(123));
        Helper.Dump(dst);

        //全0结构元素测试,结果与原图一样
        element = new Mat(3, 3, MatType.CV_8UC1, new Byte[] {0,0,0,
                                                             0,0,0,
                                                             0,0,0});
        Helper.Dump(element);
        Cv2.MorphologyEx(src, dst, MorphTypes.HitMiss, element, borderValue: new Scalar(123));
        Helper.Dump(dst);
    }
}


/// <summary>
/// 形态操作,
/// </summary>
/// <param name="pos"></param>
/// <param name="userdata"></param>
private void Morphology_Operations(int pos, IntPtr userdata) {

    //结构元素的大小
    var mSize = 2 * morph_size + 1;
    //获取结构元素
    Mat element = Cv2.GetStructuringElement((MorphShapes)morph_elem, new Size(mSize, mSize), new Point(morph_size, morph_size));
    var dst = new Mat();
    if (morph_operator == 7) {
        //HitMiss只支持CV_8UC1
        Cv2.CvtColor(src, dst, ColorConversionCodes.BGR2GRAY);
        Cv2.MorphologyEx(dst, dst, (MorphTypes)morph_operator, element);
        dst = dst.CvtColor(ColorConversionCodes.GRAY2BGR);
    }
    else {
        //形态操作
        Cv2.MorphologyEx(src, dst, (MorphTypes)morph_operator, element);
    }

    var texts = new string[] { $"MorphTypes={(MorphTypes)morph_operator}", $"MorphShapes={(MorphShapes)morph_elem}", $"ElementSize={mSize}" };
    var colors = new Scalar[] { Scalar.Red, Scalar.Green, Scalar.Blue };
    DrawLabels(dst, texts, colors);
    Cv2.ImShow(winName, dst);
}

public void DrawLabels(Mat dst,string[] texts, Scalar[] colors) {
    int vPos = 0;
    for (int i = 0; i < texts.Length; i++) {
        Size textsize = Cv2.GetTextSize(texts[i], HersheyFonts.HersheyComplex, 1, 1, out int baseLine);
        vPos += (int)(textsize.Height * 1.4);
        Point org = new Point((src.Cols - textsize.Width), vPos);
        Cv2.PutText(dst, texts[i], org, HersheyFonts.HersheyComplex, 1, colors[i], 1, LineTypes.Link8);
    }
}

OpenCvSharp函数示例(目录)

参考

https://docs.opencv.org/

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

图南科技

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

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

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

打赏作者

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

抵扣说明:

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

余额充值