OpenCV 形态学

发布时间 2023-12-02 21:54:54作者: harrychinese

形态学处理

形态学处理之前需要将图像进行二值化处理, 然后我们需要设定一个卷积核, 最后将像素上每个点都完成卷积计算.

腐蚀 Erode

腐蚀作用和膨胀相反, 用来腐蚀减小白色区域, 常用来消除一些白色毛刺等细小区域, 也会腐蚀掉边缘部分.
卷积计算方法: 卷积核为一个全1的小矩阵, 计算过程为, 图像一个像素和卷积核对齐后, 如果卷积覆盖区域中图像有含0的像素, 则该像素取值为0, 即白色, 如果全部都为1, 则该像素值为1.

代码示例:

public void erodeTest()
{
    string file = @"D:\my_workspace\opencv\images\毛刺.jpg";
    var img = Cv2.ImRead(file, ImreadModes.Grayscale);
    var elements = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3));
    var newImg1 = img.Clone();
    newImg1 = newImg1.Erode(elements, null, iterations: 1);

    Cv2.ImShow("img", img);
    Cv2.ImShow("腐蚀1次", newImg1);
    Cv2.WaitKey();
    Cv2.DestroyAllWindows();
}

效果:

膨胀 Dilate

膨胀用来扩张白色区域, 减少黑色区域, 常用来消除区域中的黑色空隙, 也会扩大白色边缘部分.
卷积计算方法: 卷积核为一个全1的小矩阵, 计算过程为, 图像一个像素和卷积核对齐后, 如果卷积覆盖区域中图像有含1的像素, 则该像素取值为1, 即白色, 如果全部都为0, 则该像素值为0.

/// <summary>
/// 膨胀测试
/// 结论: 3次递归, 仍有少量空隙, 这时可增加递归次数, 或者增大卷积核size
/// </summary>
public void dilateTest()
{
    string file = @"D:\my_workspace\opencv\images\孔隙.jpg";
    var img = Cv2.ImRead(file, ImreadModes.Grayscale);
    var elements = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3));
    var newImg3 = img.Clone();
    newImg3 = newImg3.Dilate(elements, null, iterations: 3); //3次递归, 仍有少量空隙, 这时可增加递归次数, 或者增大卷积核size
    var newImg6 = img.Clone();
    newImg6 = newImg6.Dilate(elements, null, iterations: 6);  //6次递归, 空隙清除干净
    Cv2.ImShow("img", img);
    Cv2.ImShow("膨胀3次", newImg3);
    Cv2.ImShow("膨胀6次", newImg6);
    Cv2.WaitKey();
    Cv2.DestroyAllWindows();
}

效果:
经过膨胀后, 空隙被消除了, 但可以看到矩形也变大了.

开运算

开运算是先腐蚀后膨胀, 闭运算是先膨胀后腐蚀, 腐蚀和膨胀其实并不是逆运算, 所以开闭运算最终效果是不一样的.
我们使用开运算的主要目的是利用腐蚀的正向效果, 即消除毛刺和虚假联通部分, 同时使用膨胀来抵消腐蚀的副作用.

代码示例:

/// <summary>
/// 开运算, 先腐蚀后膨胀
/// </summary>
public void openTest()
{
    string file = @"D:\my_workspace\opencv\images\毛刺.jpg";
    var img = Cv2.ImRead(file, ImreadModes.Grayscale);
    var elements = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3));
    var newImg1 = img.Clone();
    Cv2.MorphologyEx(newImg1, newImg1, MorphTypes.Open, elements, anchor: null, iterations: 1);
    Cv2.ImShow("img", img);
    Cv2.ImShow("开运算", newImg1);
    Cv2.WaitKey();
    Cv2.DestroyAllWindows();
}

效果:

闭操作

闭运算是先膨胀后腐蚀, 开运算是先腐蚀后膨胀, 腐蚀和膨胀其实并不是逆运算, 所以开闭运算最终效果是不一样的.
我们使用闭运算的主要目的是利用膨胀的正向效果, 同时使用腐蚀来抵消膨胀的副作用.

代码:
///


/// 闭运算, 先膨胀后腐蚀
///

public void closeTest()
{
string file = @"D:\my_workspace\opencv\images\孔隙.jpg";
var img = Cv2.ImRead(file, ImreadModes.Grayscale);
var elements = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3));
var newImg1 = img.Clone();
Cv2.MorphologyEx(newImg1, newImg1, MorphTypes.Close, elements, anchor: null, iterations: 4);
Cv2.ImShow("img", img);
Cv2.ImShow("闭运算", newImg1);
Cv2.WaitKey();
Cv2.DestroyAllWindows();
}

效果:

梯度

梯度相当于膨胀后的图像减去腐蚀后的图像, 可以用来刻画出轮廓部分.

代码示例:

/// <summary>
/// 梯度: 膨胀-腐蚀
/// </summary>
public void gradientTest()
{
    string file = @"D:\my_workspace\opencv\images\circle.png";
    var img = Cv2.ImRead(file, ImreadModes.Grayscale);
    var newImg3 = img.Clone();
    var elements3 = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3));
    Cv2.MorphologyEx(newImg3, newImg3, MorphTypes.Gradient, elements3, anchor: null, iterations: 1);
    var newImg5 = img.Clone();
    var elements5 = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(5, 5));
    Cv2.MorphologyEx(newImg5, newImg5, MorphTypes.Gradient, elements5, anchor: null, iterations: 1);
    Cv2.ImShow("img", img);
    Cv2.ImShow("梯度3", newImg3);
    Cv2.ImShow("梯度5", newImg5);
    Cv2.WaitKey();
    Cv2.DestroyAllWindows();
}

效果:

礼帽和顶帽 Top Hat

礼帽也叫做顶帽 Top Hat: 原始图像-开运算, 能将一些细小的毛刺凸显出来
黑帽 Black Hat: 闭操作-原始图像, 能将一些黑色的空隙凸显出来.

代码示例:

/// <summary>
/// 礼帽(顶帽), 原始图像-开操作
/// </summary>
public void topHatTest()
{
    string file = @"D:\my_workspace\opencv\images\毛刺.jpg";
    var img = Cv2.ImRead(file, ImreadModes.Grayscale);
    var elements = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3));
    var newImg1 = img.Clone();
    Cv2.MorphologyEx(newImg1, newImg1, MorphTypes.TopHat, elements, anchor: null, iterations: 1);
    Cv2.ImShow("img", img);
    Cv2.ImShow("礼帽(顶帽)", newImg1);
    Cv2.WaitKey();
    Cv2.DestroyAllWindows();
}

效果:

黑帽 Black Hat

黑帽 Black Hat: 闭操作-原始图像, 能将一些黑色的空隙凸显出来.
礼帽也叫做顶帽 Top Hat: 原始图像-开运算, 能将一些细小的毛刺凸显出来

代码示例:

/// <summary>
/// 黑帽运算, 闭操作-原始图像
/// </summary>
public void blackHatTest()
{
    string file = @"D:\my_workspace\opencv\images\孔隙.jpg";
    var img = Cv2.ImRead(file, ImreadModes.Grayscale);
    var elements = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3));
    var newImg1 = img.Clone();
    Cv2.MorphologyEx(newImg1, newImg1, MorphTypes.BlackHat, elements, anchor: null, iterations: 4);
    Cv2.ImShow("img", img);
    Cv2.ImShow("黑帽运算", newImg1);
    Cv2.WaitKey();
    Cv2.DestroyAllWindows();
}

效果演示: