在图像处理技术中,有一些的操作会对图像的形态发生改变,这些操作一般称之为形态学操作(phology)。数学形态学是基于集合论的图像处理方法,最早出现在生物学的形态与结构中,图像处理中的形态学操作用于图像与处理操作(去噪,形状简化)图像增强(骨架提取,细化,凸包及物体标记)、物体背景分割及物体形态量化等场景中,形态学操作的对象是二值化图像。
有名的形态学操作中包括腐蚀,膨胀,开操作,闭操作等。其中腐蚀,膨胀是许多形态学操作的基础。
腐蚀和膨胀是最基本的形态学操作,腐蚀和膨胀都是针对白色部分(高亮部分)而言的。膨胀就是使图像中高亮部分扩张,效果图拥有比原图更大的高亮区域;腐蚀是原图中的高亮区域被蚕食,效果图拥有比原图更小的高亮区域。膨胀是求局部最大值的操作,腐蚀是求局部最小值的操作。
膨胀与腐蚀能实现多种多样的功能,主要如下:
腐蚀操作:
顾名思义,是将物体的边缘加以腐蚀。具体的操作方法是拿一个模板,对图像中的每一个像素x做如下处理:像素x置于模板的中心,根据模版的大小,遍历所有被模板覆盖的其他像素,修改像素x的值为所有像素中最小的值(只有二值:255,0)。这样操作的结果是会将图像外围的突出点加以腐蚀。
A⨀B={z|(B)z⊆A}
可以理解为,移动结构B,如果结构B与结构A的交集完全属于结构A的区域内,则保存该位置点,所有满足条件的点构成结构A被结构B腐蚀的结果。 (最上面那个绿色方框应该没有)
函数原型:
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() );
膨胀操作:
膨胀操作与腐蚀操作相反,是将图像的轮廓加以膨胀。操作方法与腐蚀操作类似,也是拿一个模板,对图像的每个像素做遍历处理。不同之处在于修改像素的值不是所有像素中最小的值,而是最大的值。这样操作的结果会将图像外围的突出点连接并向外延伸。
结构A被结构B膨胀的定义为:
A⨁B={z|(B^)z⋂A≠∅}
可以理解为,将结构B在结构A上进行卷积操作,如果移动结构B的过程中,与结构A存在重叠区域,则记录该位置,所有移动结构B与结构A存在交集的位置的集合为结构A在结构B作用下的膨胀结果。图示中红色框内的区域表示结构A在结构B的作用下膨胀的结果。
这里有另外一个例子:
函数原型:
CV_EXPORTS_W void dilate( InputArray src, OutputArray dst, InputArray kernel,
Point anchor=Point(-1,-1), int iterations=1,
int borderType=BORDER_CONSTANT,
const Scalar& borderValue=morphologyDefaultBorderValue() );
参数说明同erode函数 。
先腐蚀后膨胀的操作称之为开操作。作用:放大裂缝和低密度区域,消除小物体,在平滑较大物体的边界时,不改变其面积。消除物体表面的突起。它具有消除细小物体,在纤细处分离物体和平滑较大物体边界的作用。 采用上图的结构B对原件进行开操作,
先膨胀后腐蚀的操作称之为闭操作。它填充物体内细小空洞,连接邻近物体和平滑边界的。 作用:排除小型黑洞,突触了比原图轮廓区域更暗的区域,将两个区域连接起来,形成连通域。
闭操作就是对图像先膨胀,再腐蚀。闭操作的结果一般是可以将许多靠近的图块相连称为一个无突起的连通域。在我们的图像定位中,使用了闭操作去连接所有的字符小图块,然后形成一个车牌的大致轮廓。闭操作的过程我会讲的细致一点。为了说明字符图块连接的过程。在这里选取的原图跟上面三个操作的原图不大一样,是一个由两个分开的图块组成的图。原图首先经过膨胀操作,将两个分开的图块结合起来(注意我用偏白的灰色图块表示由于膨胀操作而产生的新的白色)。接着通过腐蚀操作,将连通域的边缘和突起进行削平(注意我用偏黑的灰色图块表示由于腐蚀被侵蚀成黑色图块)。最后得到的是一个无突起的连通域(纯白的部分)采用上图的结构对原件进行闭操作
开运算和闭运算可以通过分别调用dilate函数和erode函数进行实现,也可以使用morphologyEx函数实现。函数原型:
CV_EXPORTS_W 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() );
morphologyEx函数利用基本的膨胀和腐蚀技术,来执行更加高级形态学变换
src 输入图像,图像位深应该为以下五种之一:CV_8U, CV_16U,CV_16S, CV_32F 或CV_64F。
dst 输出图像,需和源图片保持一样的尺寸和类型。
op 表示形态学运算的类型:
MORPH_OPEN – 开运算(Opening operation)
MORPH_CLOSE – 闭运算(Closing operation)
MORPH_GRADIENT - 形态学梯度(Morphological gradient)
MORPH_TOPHAT - 顶帽(Top hat)
MORPH_BLACKHAT - 黑帽(Black hat)
kernel 形态学运算的内核。为NULL,使用参考点位于中心3x3的核。一般使用函数getStructuringElement配合这个参数的使用,
kernel参数填保存getStructuringElement返回值的Mat类型变量。
anchor 锚的位置,其有默认值(-1,-1),表示锚位于中心。
iterations 迭代使用函数的次数,默认值为1。
borderType 用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_CONSTANT。
borderValue 当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。
(1) 顶帽运算
为原图像与“开运算“的结果图 之差,数学表达式如下:
因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域,且这一操作和选择的核的大小相关。
顶帽运算往往用来分离比邻近点亮一些的斑块。当一幅图像具有大幅的背景的时候,而微小物品比较有规律的情况下,可以使用顶帽运算进行背景提取。
(2) 黑帽运算
为”闭运算“的结果图与原图像之差。数学表达式为:
黑帽运算后的效果图突出了比原图轮廓周围的区域更暗的区域,且这一操作和选择的核的大小相关。黑帽运算用来分离比邻近点暗一些的斑块。
(3) 一些形态学操作的宏定义
在进行实例之前,要先介绍一个函数getStructuringElement(),函数原型:
CV_EXPORTS_W Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1));
getStructuringElement函数会返回指定形状和尺寸的结构元素。这个函数的第一个参数表示内核的形状,有三种形状可以选择。
矩形:MORPH_RECT;
交叉形:MORPH_CORSS;
椭圆形:MORPH_ELLIPSE;
第二个参数是内核的尺寸。一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。
第三个参数是锚点的位置,对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心点。
getStructuringElement函数相关调用如下:
int g_nStructElementSize = 3; //结构元素(内核矩阵)的尺寸
Mat element = getStructuringElement(MORPH_RECT,
Size(g_nStructElementSize,g_nStructElementSize));
调用之后,调用膨胀与腐蚀函数的时候,第三个参数值保存了getStructuringElement返回值的Mat类型变量。也就是element变量
erode( src, dst, element );
#include
#include
#include
using namespace std;
using namespace cv;
int main(){
Mat src;
Mat img = imread("111.jpg", 1);
img.copyTo(src);
Mat dst7;
cvtColor(img, src, COLOR_RGB2GRAY);
Mat kernel=getStructuringElement(MORPH_RECT, Size(9, 9));//自定义核
morphologyEx(src,dst7,MORPH_TOPHAT,kernel);//顶帽操作
//resize(dst7, dst7, Size(src.cols * 0.5, src.rows * 0.5), 0, 0, INTER_LINEAR);
//Mat imgROI = img(Rect(1, 1, dst7.cols, dst7.rows));
//dst7.copyTo(imgROI,dst7);
imshow("dst7", dst7);
imshow("img", img);
waitKey(0);
}
结果:
from:https://www.cnblogs.com/zhp218/p/8530571.html
from:https://www.cnblogs.com/zhp218/p/8530571.html