C#描述-计算机视觉OpenCV(6):形态学
前言
这是本系列第六节,主要是介绍基础的形态学运用。
形态学主要是分析图像中不同主题的形态,它定义了一系列运算,用预先定义的形状元素探测图像,从而实现图像的转换。这个形状元素与像素邻域的相交方式决定了运算的结果。从而可以进行切割、特征检测。
阈值化二值图像
因为形态学滤波器通常作用于二值图像,所以我们先对图像做阈值化的二值图像操作。我们以此图为例:
使用Threshold方法
res, dst = cv2.threshold(src, thresh, maxval, type)
来进行阈值化,参数详解:
src:输⼊图,只能输⼊单通道图像,通常是指灰度图
dst:输出图
thresh:阈值
maxval:当像素值超过了阈值(或⼩于阈值,根据type来决定),所赋予的值
type:⼆值化操作类型,包含以下五种类型:
cv2.THRESH_BINARY 超过阈值部分取maxval(最⼤值),否则取0
cv2.THRESH_BINARY_INV THRESH_BINARY 上述反转
cv2.THRESH_TRUNC ⼤于阈值部分设为阈值,否则不变
cv2.THRESH_TOZERO ⼤于阈值部分不改变,否则设为0
cv2.THRESH_TOZERO_INV THRESH_TOZERO 上述反转
在阈值的选择上,我们需要观察原图的直方图(直方图算法详见:C#描述-计算机视觉OpenCV(5):直方图算法),根据直方图示,我们可以先选择中端峰值左侧的点,也就是100作为阈值参考。
代码:
csharp
Cv2.Threshold(img1, res, 100, 255,ThresholdTypes.Binary);
Cv2.ImShow("11", res);
生成图像:
一般来说,在形态学中,我们习惯用高像素值(白色)表示前景物体,用低像素值(黑色)表示背景物体,这张图的切割效果是大概符合我们的要求的(实际上是,测试了多个数值,基本这是最好效果)。
腐蚀与膨胀算法
腐蚀与膨胀是基本的形态学运算操作。
OpenCV 用简单的函数实现了腐蚀和膨胀运算,它们分别是 cv:erode 和 cv:dilate,用法也很简单:
csharp
Mat eroded = new Mat();
Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(5, 5), new OpenCvSharp.Point(-1, -1));
Cv2.Erode(res, eroded,kernel);
Cv2.ImShow("12", eroded);
Mat dilated = new Mat();
Cv2.Dilate(res, dilated, kernel);
Cv2.ImShow("13", dilated);
通过腐蚀与膨胀运算,我们可以对图片中的物体形态进行突出、分割等操作。顾名思义,腐蚀就是从背景向前景物去侵蚀,膨胀就是前景物形态膨胀。
腐蚀图例:
膨胀图例:
形态学滤波器开启和闭合运算
调用以下方法对图像做闭合运算:
csharp
Cv2.MorphologyEx(img, res, MorphTypes.Close,kernel);
其中,MorphTypes.Close为运算符
原理:
开启和闭合滤波器的定义只与基本的腐蚀和膨胀运算有关:闭合的定义是对图像先膨胀后腐蚀,开启的定义是对图像先腐蚀后膨胀。也就是等同于:
// 膨胀原图像
Cv2.Dilate(img, dilated, kernel);
// 就地腐蚀膨胀后的图像
Cv2.Erode(dilated, res,kernel);
调换这两个函数的调用次序,就能得到开启滤波器。
查看闭合滤波器的结果,可看到白色的前景物体中的小空隙已经被填满。闭合滤波器也会把邻近的物体连接起来。基本上,所有小到不能容纳完整结构元素的空隙或间隙都会被闭合滤波器消除。
与闭合滤波器相反,开启滤波器消除了背景中的几个小物体。所有小到不能容纳完整结构元素的物体都会被移除。
这些滤波器常用于目标检测。闭合滤波器可把错误分裂成小碎片的物体连接起来,而开启滤波器可以移除因图像噪声产生的斑点。因此最好按一定的顺序调用这些滤波器。如果优先考虑过滤噪声,可以先开启后闭合,但这样做的坏处是会消除掉部分物体碎片。
先使用开启滤波器,再使用闭合滤波器,会得到如下结果:
原理概括
数学形态学中最基本的概念是结构元素。结构元素可以简单地定义为像素的组合,在对应的像素上定义了一个原点(也称锚点)。形态学滤波器的应用过程就包含了用这个结构元素探测图像中每个像素的操作过程。把某个像素设为结构元素的原点后,结构元素和图像重叠部分的像素集就是特定形态学运算的应用对象。
当我们进行腐蚀与膨胀运算时,可考虑背景(黑色)和前景(白色)的物体。腐蚀时,如果结构元素放到某个像素位置时碰到了背景(即交集中有一个像素是黑色的),那么这个像素就变为背景;膨胀时,如果结构元素放到某个背景像素位置时碰到了前景物体,那么这个像素就被标为白色。正因如此,图像腐蚀后物体尺寸会缩小(形状被腐蚀),而图像膨胀后物体会扩大。
在腐蚀图像中,有些面积较小的物体(可看作背景中的"噪声"像素)会彻底消失。与之类似,膨胀后的物体会变大,而物体中一些"空隙"会被填满。
所以也在这里解释结果元素的生成,
Mat kernel = Cv2.GetStructuringElement
(MorphShapes.Rect,
new OpenCvSharp.Size(5, 5),
new OpenCvSharp.Point(-1, -1));
这个函数的第一个参数表示内核的形状,有三种形状可以选择。
矩形:MORPH_RECT;
交叉形:MORPH_CROSS;
椭圆形:MORPH_ELLIPSE;
第二和第三个参数分别是内核的尺寸以及锚点的位置。
可以自行调整结构元素的设计来分析运用的效果。