基于C++的OpenCV4入门基础–图像形态学

不管现实多么惨不忍睹,都要持之以恒地相信,这只是黎明前短暂的黑暗而已。不要惶恐眼前的难关迈不过去,不要担心此刻的付出没有回报,别再花时间等待天降好运。真诚做人,努力做事!你想要的,岁月都会给你。基于C++的OpenCV4入门基础–图像形态学,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

1,图像形态学介绍
形态学的应用: 主要针对二值图进行,消除噪声、边界提取、区域填充、连通分量提取、凸壳、细化、粗化等;分割出独立的图像元素,或者图像中相邻的元素;求取图像中明显的极大值区域和极小值区域;求取图像梯度。

2,结构和元素形状
膨胀和腐蚀操作的核心内容是结构元素,(后面的开闭运算等重要的也是结构元素的设计,一个合适的结构元素的设计可以带来很好的处理效果)一般来说结构元素是由元素为1或者0的矩阵组成。结构元素为1的区域定义了图像的领域,领域内的像素在进行膨胀和腐蚀等形态学操作时要进行考虑。
一般来说,二维或者平面结构的结构元素要比处理的图像小得多。结构元素的中心像素,即结构元素的原点,与输入图像中感兴趣的像素值(即要处理的像素值)相对应。三维的结构元素使用0和1来定义x-y平面中结构元素的范围,使用高度值定义第三维。

CV_EXPORTS_W Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));

 //shape: \MORPH_CROSS(十字交叉形核) \MORPH_ELLIPSE(椭圆形核));
// ksize: 结构元素大小;
// anchor: 锚点 默认是Point(-1, -1)意思就是中心像素,也可以自己指定
	//结构元素设计
	Mat elementRect, elementCross, elementEllipse;

	elementRect = getStructuringElement(MORPH_RECT, cv::Size(3, 3), cv::Point(-1, -1));//矩形
	elementCross =  getStructuringElement(MORPH_CROSS, cv::Size(3, 3), cv::Point(-1, -1));//十字
	elementEllipse = getStructuringElement(MORPH_ELLIPSE, cv::Size(5, 5), cv::Point(-1, -1));//椭圆

	cout << "3X3矩形核:" << endl << elementRect << endl;
	cout << "3X3十字交叉形核:" << endl << elementCross << endl;
	cout << "5X5椭圆形核:" << endl << elementEllipse << endl << endl;

在这里插入图片描述
3,腐蚀和膨胀
膨胀
膨胀操作是形态学中另外一种基本的操作。膨胀操作和腐蚀操作的作用是相反的,膨胀操作能对图像的边界进行扩张。膨胀操作将与当前对象(前景)接触到的背景点合并到当前对象内,从而实现将图像的边界点向外扩张
如果图像内两个对象的距离较近,那么在膨胀的过程中,两个对象可能会连通在一起。膨胀操作对填补图像分割后图像内所存在的空白相当有帮助。二值图像的膨胀示例如图所示。
在这里插入图片描述
膨胀使图像中的白色高亮部分进行膨胀,“邻域扩张”,膨胀效果拥有比原图更大的高亮区域,可以填补图像缺陷,用来扩充边缘或填充小的孔洞,也可以用来连接两个分开的物体。

膨胀的原理是求局部最大值的操作,将 1 值扩充到邻近像素,从而扩大白色值范围、压缩黑色值范围。

用卷积来描述膨胀操作,中心为 1、其它为 0 的卷积核沿着图像滑动卷积,与卷积核对应的原图像的像素值中只要有一个为 1, 则图像的中心元素的像素值为 1,否则(全 0)为 0。

用卷积来描述膨胀操作,结构元素 B 是中心为 1、其它为 0 的卷积模板(核):
(1)卷积核 B 沿着图像滑动,扫描图像 A 的每一个像素;
(2)用结构元素与其覆盖的二值图像进行 “与操作”;
(3)如果图像与卷积核对应区域的所有像素值都是 0,则图像的该像素值仍为 0;否则为 1。

在去噪声时通常先进行腐蚀,在去掉白噪声的同时,使前景对象变小;然后再对进行膨胀,此时噪声已经被去除,可以增加前景。

void dilate(
    InputArray src,//输入图像,即源图像,填Mat类的对象即可。图像通道的数量可以是任意的,但图像深度应为CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一
    OutputArray dst,//目标图像,需要和源图片有一样的尺寸和类型
    InputArray kernel,//操作的核。若为NULL时,表示的是使用参考点位于中心3x3的核,可以使用getStructuringElement来创建结构元素
    Point anchor=Point(-1,-1),//锚点的位置,其有默认值(-1,-1),表示锚位于中心
    int iterations=1,//迭代使用该函数的次数,默认值为1
    int borderType=BORDER_CONSTANT,//用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT
    const Scalar& borderValue=morphologyDefaultBorderValue() //当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释
);
//使用dilate函数时,一般我们只需要填前面的三个参数,后面的四个参数都有默认值。而且往往结合getStructuringElement一起使用。

参数说明:
src:输入图像,可以为单通道或多通道,图像深度必须为 CV_8U, CV_16U, CV_16S, CV_32F 或 CV_64F
dst:输出图像,大小和类型与 src 相同
kernel:结构元(卷积核),null 时使用 3*3 矩形卷积核
anchor:卷积核的锚点位置,默认值 (-1, -1) 表示以卷积核的中心为锚点
iterations:应用膨胀的次数,可选项,默认值为 1
borderType:边界扩充的类型
borderValue:当 borderType=BORDER_CONSTANT 时以常量 value 填充扩充边界,默认值为 (0,0,0)

注意事项:
函数支持就地模式,腐蚀操作可以迭加使用多次。
在多通道图像的情况下,每个通道独立处理 。

腐蚀
腐蚀和膨胀是图像处理中最基本的形态学操作,是很多高级处理方法的基础。

腐蚀和膨胀是对白色部分(高亮部分)而言的,膨胀就是图像中的高亮部分进行膨胀,腐蚀就是原图中的高亮部分被腐蚀。

腐蚀使图像中白色高亮部分被腐蚀,“邻域被蚕食”,腐蚀的效果拥有比原图更小的高亮区域,可以去掉毛刺,去掉孤立的像素,提取骨干信息。

腐蚀的原理是求局部最小值的操作,将 0 值扩充到邻近像素,从而扩大黑色值范围、压缩白色值范围。

腐蚀是最基本的形态学操作之一,它能够将图像的边界点消除,使图像沿着边界向内收缩,也可以将小于指定结构体元素的部分去除。腐蚀用来“收缩”或者“细化”二值图像中的前景,借此实现去除噪声、元素分割等功能。例如,在图中,左图是原始图像,右图是对其腐蚀的处理结果。
在这里插入图片描述
腐蚀的具体操作:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为1,则该像素为1,否则为0。用最小值来替换中心像素
腐蚀的作用:是消除物体边界点,使目标缩小,可以消除小于结构元素的噪声点;腐蚀了就意味着图像中物体的边界被侵蚀了,轮廓向内收缩,体积变小了。

CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel,
                         Point anchor = Point(-1,-1), int iterations = 1,
                         int borderType = BORDER_CONSTANT,
                         const Scalar& borderValue = morphologyDefaultBorderValue() );

参数说明:
src:输入图像,可以为单通道或多通道,图像深度必须为 CV_8U, CV_16U, CV_16S, CV_32F 或 CV_64F
dst:输出图像,大小和类型与 src 相同
kernel:结构元(卷积核),null 时使用 3*3 矩形结构元素
anchor:卷积核的锚点位置,默认值 (-1, -1) 表示以卷积核的中心为锚点
iterations:应用腐蚀操作的次数,可选项,默认值为 1
borderType:边界扩充的类型
borderValue:当 borderType=BORDER_CONSTANT 时以常量 value 填充扩充边界,默认值为 (0,0,0)

注意事项:
函数支持就地模式,腐蚀操作可以迭加使用多次。
在多通道图像的情况下,每个通道独立处理 。

参考示例

	Mat src = imread("F:/code/images/hist_02.jpg");
    namedWindow("input", WINDOW_AUTOSIZE);
	imshow("input", src);

    //二值图
    Mat gray, binary;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
    namedWindow("binary", WINDOW_AUTOSIZE);
    imshow("binary", binary);

    //腐蚀
    Mat elementRect = getStructuringElement(MORPH_RECT, cv::Size(3, 3), cv::Point(-1, -1));//矩形
    erode(binary, binary, elementRect);
    namedWindow("erode", WINDOW_AUTOSIZE);
    imshow("erode", binary);

    //膨胀
    Mat elementRect2 = getStructuringElement(MORPH_RECT, cv::Size(3, 3), cv::Point(-1, -1));//矩形
    dilate(binary, binary, elementRect2);
    namedWindow("dilate", WINDOW_AUTOSIZE);
    imshow("dilate", src);

在这里插入图片描述
在这里插入图片描述
4,开闭操作
开操作- open
先腐蚀后膨胀
可以去掉小的对象,假设对象是前景色,背景是黑色
用于移除一些小物体(假设图像中物体是亮的,背景是暗的)。如下图所示,左侧是原始图像,上面有一些小亮斑。在进行开运算之后,去掉了斑点。
在这里插入图片描述
闭操作-close
先膨胀后腐蚀(bin2)
可以填充小的洞(fill hole),假设对象是前景色,背景是黑色
用于移除一些小的孔洞(图像中较亮目标中的暗点)
在这里插入图片描述

CV_EXPORTS_W void morphologyEx( InputArray src, OutputArray dst,
                                int op, //操作的类型:MORPH_ERODE    = 0, //腐蚀
   										 MORPH_DILATE   = 1, //膨胀
    									 MORPH_OPEN     = 2, //开操作
      									 MORPH_CLOSE    = 3, //闭操作
    									 MORPH_GRADIENT = 4, //梯度操作
    									 MORPH_TOPHAT   = 5, //顶帽操作
									     MORPH_BLACKHAT = 6, //黑帽操作
    									 MORPH_HITMISS  = 7  
                                InputArray kernel,//结构元素
                                Point anchor = Point(-1,-1), //锚点
                                int iterations = 1,//迭代使用函数的次数
                                int borderType = BORDER_CONSTANT,
                                const Scalar& borderValue = morphologyDefaultBorderValue() );

参数说明:
src:输入图像,可以为单通道或多通道,图像深度必须为 CV_8U, CV_16U, CV_16S, CV_32F 或 CV_64F
dst:输出图像,大小和类型与 src 相同
op:形态学运算类型
cv.MORPH_ERODE:腐蚀
cv.MORPH_DILATE:膨胀
cv.MORPH_OPEN:开运算, 先腐蚀再膨胀
cv.MORPH_CLOSE:闭运算, 先膨胀再腐蚀
cv.MORPH_GRADIENT:形态学梯度, 膨胀图与腐蚀图之差
cv.MORPH_TOPHAT:顶帽变换, 原图像与开运算之差
cv.MORPH_BLACKHAT:黑帽变换, 闭运算图与原图像之差
cv.MORPH_HITMISS: 击中击不中运算
kernel:结构元(卷积核),null 时使用 3*3 矩形卷积核
anchor:卷积核的锚点位置,负值表示以卷积核的中心为锚点
iterations:应用腐蚀和膨胀的次数,可选项,默认值为 1
borderType:边界扩充的类型
borderValue:当 borderType=BORDER_CONSTANT 时以常量 value 填充扩充边界,默认值为 (0,0,0)

注意事项:
函数支持就地模式,开运算操作可以迭加使用多次。
迭代次数是应用腐蚀和膨胀操作的次数,注意两次迭代的开操作相当于应用“腐蚀→腐蚀→膨胀→膨胀”,而不是“腐蚀→膨胀→腐蚀→膨胀”

示例

	 Mat src = imread("F:/code/images/cells.png");
    CV_Assert(!src.empty());

    Mat gray, binary;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    threshold(gray, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
    bitwise_not(binary, binary, Mat());
    imshow("binary", binary);

    //开操作
    Mat dst;
    Mat kernel = getStructuringElement(MORPH_RECT, Size(7, 7), Point(-1, -1));//Size(15,1)为水平方向结构元素 Size(1, 15)为垂直方向结构元素
    morphologyEx(binary, dst, MORPH_OPEN, kernel, Point(-1, -1), 1);
    imshow("open-demo", dst);

    //闭操作
    Mat dst2;
    Mat kerne2 = getStructuringElement(MORPH_RECT, Size(15, 15), Point(-1, -1));
    morphologyEx(binary, dst2, MORPH_CLOSE, kerne2, Point(-1, -1), 1);
    imshow("close-demo", dst2);

开运算结果
在这里插入图片描述
闭运算结果
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/182009.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!