
本文共 8143 字,大约阅读时间需要 27 分钟。
前言
本文讲述图像处理的形态学操作
一、数学形态学图像处理基本概念
1.1、数学形态学简介
数学形态学(Mathematical morphology) 是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。其基本的运算包括: 二值腐蚀和膨胀、二值开闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换、灰值腐蚀和膨胀、灰值开闭运算、灰值形态学梯度等。
1.2、数学形态学组成
数学形态学是由一组形态学的代数运算子组成的,它的基本运算有4个: 膨胀(或扩张)、腐蚀(或侵蚀)、开启和闭合,它们在二值图像和灰度图像中各有特点。基于这些基本运算还可推导和组合成各种数学形态学实用算法,用它们可以进行图像形状和结构的分析及处理,包括图像分割、特征抽取、边缘检测、 图像滤波、图像增强和恢复等。数学形态学方法利用一个称作结构元素的“探针”收集图像的信息,当探针在图像中不断移动时, 便可考察图像各个部分之间的相互关系,从而了解图像的结构特征。数学形态学基于探测的思想,与人的FOA(Focus Of Attention)的视觉特点有类似之处。作为探针的结构元素,可直接携带知识(形态、大小、甚至加入灰度和色度信息)来探测、研究图像的结构特点。
1.3、数学形态学应用
数学形态学的基本思想及方法适用于与图像处理有关的各个方面,如基于击中/击不中变换的目标识别,基于流域概念的图像分割,基于腐蚀和开运算的骨架抽取及图像编码压缩,基于测地距离的图像重建,基于形态学滤波器的颗粒分析等。
数学形态学是一门建立在严格数学理论基础上的学科,其基本思想和方法对图像处理的理论和技术产生了重大影响。事实上,数学形态学已经构成一种新的图像处理方法和理论,成为计算机数字图像处理及分形理论的一个重要研究领域,并且已经应用在多门学科的数字图像分析和处理的过程中。这门学科在计算机文字识别, 计算机显微图像分析(如定量金相分析,颗粒分析), 医学图像处理(例如细胞检测、心脏的运动过程研究、脊椎骨癌图像自动数量描述),图像编码压缩,工业检测(如食品检验和印刷电路自动检测),材料科学, 机器人视觉,汽车运动情况监测等方面都取得了非常成功的应用。另外,数学形态学在指纹检测、经济地理、合成音乐和断层X光照像等领域也有良好的应用前景。形态学方法已成为图像应用领域工程技术人员的必备工具。二、二值图像
2.1、含义
二值图像是指每个像素点均为黑色或者白色的图像。二值图像一般用来描述字符图像,其优点是占用空间少;缺点是当表示人物,风景的图像时,二值图像只能展示其边缘信息,图像内部的纹理特征表现不明显。这时候要使用纹理特征更为丰富的灰度图像。
2.2、二值图像样例
2.3、图像二值化处理逻辑
图像的二值化处理是将图像上的点的灰度值为0或255,也就是将整个图像呈现出明显的黑白效果。即将256个亮度等级的灰度图像通过适当的阈值选取而获得仍然可以反映图像整体和局部特征的二值化图像。在数字图像处理中,要进行二值图像的处理与分析,首先要把灰度图像二值化,得到二值化图像,这样子有利于在对图像做进一步处理时,图像的集合性质只与像素值为0或255的点的位置有关,不再涉及像素的多级值,使处理变得简单,而且数据的处理和压缩量小。为了得到理想的二值图像,一般采用封闭、连通的边界定义不交叠的区域。所有灰度大于或等于阈值的像素被判定为属于特定物体,其灰度值为255表示,否则这些像素点被排除在物体区域以外,灰度值为0,表示背景或者例外的物体区域。
2.4、opencv二值化处理函数
2.4.1、threshold()函数
简介:对每个数组元素应用一个固定级别的阈值,手动指定一个阈值,以此阈值来进行二值化处理
函数定义:double threshold( InputArray src, OutputArray dst, double thresh, double maxval, int type );/*src输入数组(多通道,8位或32位浮点),即图像。dst输出数组的大小和类型与src的通道数相同。thresh参数阈值。maxval用于#THRESH_BINARY和#THRESH_BINARY_INV thresholding的最大值类型。type如果使用大津法或三角形法,则返回计算出的阈值。*/
2.4.2、adaptiveThreshold()函数
简介:对数组应用自适应阈值,通过设定最后两个参数来调整效果
函数定义:void adaptiveThreshold( InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C );/*src源8位单通道图像。dst目标映像与src大小和类型相同的param maxValue指定给满足条件的像素的非零值adaptiveMethod自适应阈值算法的使用#BORDER_REPLICATE |#BORDER_ISOLATED用于处理边界。thresholdType Thresholding type必须是#THRESH_BINARY或#THRESH_BINARY_INV,blockSize用于计算阈值的像素邻域的大小像素:3、5、7等等。参数C常数从平均值或加权平均值中减去。正常情况下为正,但也可能为零或负。*/
三、Opencv图像基本二值运算
3.1、腐蚀操作:erode()函数
简介:使用指定的结构元素来腐蚀源图像,该结构元素决定取最小值的像素邻域的形状
定义: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:用于扩展的内核结构元素;如果elemenat=Mat(),则为3 x 3矩形使用结构元素。anchor:可以使用#getStructuringElement创建内核anchor元素中锚点的位置;默认值(-1,-1)表示锚点位于元素中心。iterations:迭代次数应用腐蚀。borderType:像素外推方法,不支持边框环绕。borderValue:如果是常量border,则为border值*/
3.2、膨胀操作:dilate()函数
简介:使用指定的结构元素来扩展源图像,该结构元素确定取最大值的像素邻域的形状
定义:void dilate( 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:用于扩展的内核结构元素;如果elemenat=Mat(),则为3 x 3矩形使用结构元素。anchor:可以使用#getStructuringElement创建内核anchor元素中锚点的位置;默认值(-1,-1)表示锚点位于元素中心。iterations 迭代应用扩展的次数。borderType:像素外推方法,不支持边框环绕。borderValue:如果是常量border,则为border值*/
3.3、morphologyEx()函数
简介:morphologyEx可以使用侵蚀和扩张来执行高级形态转换基本操作。任何操作都可以在原地完成。在多通道图像的情况下,每个通道独立处理。
定义:void morphologyEx( InputArray src, OutputArray dst, int op, 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:目标映像的大小和类型与源映像相同。Type:形态学运算的类型,请参见#MorphTypeskernel:内核结构元素。可以使用#getStructuringElement创建它。anchor :锚定与内核的锚定位置。负值表示锚点位于内核中心。iterations :迭代应用腐蚀和膨胀的次数。borderType:像素外推方法,请参见#BorderTypes。#不支持边框自动换行。borderValue:如果是常量Border,则为Border值。默认值具有特殊的意思。迭代次数是应用侵蚀或膨胀操作的次数。例如,具有两次迭代的打开操作(#MORPH_OPEN)等价于apply*/
3.3.1、开操作:MORPH_OPEN
先腐蚀后膨胀的操作。
作用:消除细小物体,在纤细处分离物体和平滑较大物体边界。3.3.2、闭操作:MORPH_CLOSE
先膨胀后腐蚀的操作。
作用:填充物体内细小空洞,连接邻近物体和平滑边界。3.3.3、梯度运算:MORPH_GRADIENT
对二值图像进行这一操作可以将团块的边缘突出来。
作用:形态学梯度来保留物体的边缘轮廓3.3.4、顶帽操作:MORPH_TOPHAT
从原图中减去开运算后的图,得到的效果图突出了比原型轮廓周围的区域更明亮的区域
作用:分离比邻近点亮一些的斑块3.3.5、黑帽操作:MORPH_BLACKHAT
突出了比原图轮廓周围的区域更暗的区域
作用:分离比邻近点暗一些的斑块3.4、 getStructuringElement()函数
简介:返回用于形态学操作的指定大小和形状的结构元素
作用:我们一般利用这个函数来配合前面各个函数定义中的参数kernel来使用,构造一个符合的结构元素 定义:Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));/*shape:元素可以是#MorphShapes之一的形状ksize:结构元素的大小。anchor:锚定元素内的锚定位置。默认值\f$(-1,-1)\f$表示锚在中间。只有十字形元素的形状取决于锚点位置。在其他情况下,锚定只会调节结果的大小操作转移。*/
3.5、createTrackbar()函数
简介:函数createTrackbar创建具有指定名称的轨迹栏(滑块或范围控件)和范围,将变量值指定为与轨迹栏同步的位置,并指定要在轨迹栏位置更改时调用的回调函数onChange。创建的轨迹栏是显示在指定的窗口中。
定义:int createTrackbar(const String& trackbarname, const String& winname, int* value, int count,TrackbarCallback onChange = 0,void* userdata = 0);/*trackbarname:创建的轨迹栏的名称。winname:将用作所创建轨迹栏父级的窗口的名称。value:指向整数变量的可选指针,该整数变量的值反映滑块。创建时,滑块位置由该变量定义。count:滑块的最大位置。最小位置总是0。onChange:指向每次滑块改变位置时要调用的函数的指针。这个函数的原型应该是void Foo(int,void\*);其中第一个参数是trackbar位置,第二个参数是用户数据(见下一个参数)。如果回调是空指针,不调用回调,但只更新值。userdata:按原样传递给回调的用户数据。它可以用来处理轨迹栏不使用全局变量的事件。*/
3.6、形态学操作类型枚举:
enum MorphTypes{ MORPH_ERODE = 0, //!< see #erode MORPH_DILATE = 1, //!< see #dilate MORPH_OPEN = 2, //!< an opening operation MORPH_CLOSE = 3, //!< a closing operation MORPH_GRADIENT = 4, //!< a morphological gradient MORPH_TOPHAT = 5, //!< "top hat" MORPH_BLACKHAT = 6, //!< "black hat" MORPH_HITMISS = 7 //!< "hit or miss"};
四、代码演示:
4.1、腐蚀与膨胀
代码块
//腐蚀与膨胀#include#include using namespace std;using namespace cv;Mat src, dst;int element_size = 2;int max_size = 20;void CallBack_Demo(int, void*) { int s = element_size * 2 + 1; Mat structureElement = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1)); dilate(src, dst, structureElement, Point(-1, -1));//膨胀 //erode(src, dst, structureElement);//腐蚀 imshow("output_image", dst);}int main() { src = imread("D:\\Myfile\\素材照片\\opencv素材照片\\4.jpg"); if (!src.data) { cout << "could not load image..." << endl; return 0; } namedWindow("input_image", WINDOW_AUTOSIZE); imshow("input_image", src); namedWindow("output_image", WINDOW_AUTOSIZE); createTrackbar("Element Size :", "output_image", &element_size, max_size, CallBack_Demo); CallBack_Demo(0, 0); imshow("output_image", dst); waitKey(0); return 0;}
运行结果:

4.2、开、闭、梯度、顶帽、黑帽等操作
代码块:
//形态学操作#include#include #include "facedetectcnn.h"using namespace std;using namespace cv;int main() { Mat src, dst; src = imread("D:\\Myfile\\素材照片\\opencv素材照片\\11.jpg"); if (!src.data) { cout << "could not load image..." << endl; return 0; } namedWindow("input_image", WINDOW_AUTOSIZE); imshow("input_image", src); //Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));//结构元素 //morphologyEx(src, dst, MORPH_OPEN, kernel);//开操作,先腐蚀后膨胀 //morphologyEx(src, dst, MORPH_CLOSE, kernel);//闭操作,先膨胀后腐蚀 //梯度:膨胀减去腐蚀,基本梯度(内部梯度,方向梯度) //morphologyEx(src, dst, MORPH_GRADIENT, kernel); //顶帽 原图像和开操作图像 //morphologyEx(src, dst, MORPH_TOPHAT, kernel); //黑帽 原图像和闭操作图像 //morphologyEx(src, dst, MORPH_BLACKHAT, kernel); //提取水平和垂直线 cvtColor(src, dst, COLOR_BGR2GRAY); Mat Bin_dst; adaptiveThreshold(dst, Bin_dst, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);//二值化图像 Mat hline = getStructuringElement(MORPH_RECT, Size(src.cols / 16, 1), Point(-1, -1)); Mat vline = getStructuringElement(MORPH_RECT, Size(1, src.rows / 16), Point(-1, -1)); Mat kernels = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1)); //Mat temp; //erode(Bin_dst, temp, kernels); //dilate(temp, dst, kernels); morphologyEx(Bin_dst, dst, MORPH_OPEN, hline); bitwise_not(dst, dst); blur(dst, dst, Size(3, 3), Point(-1, -1)); namedWindow("output_image", WINDOW_AUTOSIZE); imshow("output_image", dst); waitKey(0); return 0;}
运行结果:

总结
本文讲述数学形态学操作:腐蚀、膨胀、开、闭、梯度、顶帽、黑帽
参考来源
如有疑问,请留言!
如有错误,敬请指正!