形态学操作
(1)开操作:先腐蚀后膨胀,可以去掉小的对象。
(2)闭操作:先膨胀后腐蚀,可以填充小对象。
(3)形态学梯度:膨胀减去腐蚀。
(4)顶帽:顶帽是原图像与开操作图像之间的差值图像。
(5)黑帽:黑帽是闭操作图像与原图像之间的差值图像。
这几个形态学操作都是基于腐蚀和膨胀的
- 腐蚀:锚点替换为最小值;黑色增加白色减少
- 膨胀:锚点替换为最大值;白色增加黑色减少
开操作
开操作即为先腐蚀后膨胀。
我们以单通道的黑白图像为例讲解,也就是我们先通过腐蚀操作,将黑色区域腐蚀扩大,再通过膨胀操作,将白色区域膨胀扩大。
如果我有一个小白点,先通过腐蚀操作,就会被周围的黑色覆盖掉,再进行膨胀操作,因为小白点已经没有了,进行膨胀操作,也不会影响到周围的黑色,所以,开操作,可以去掉小白点。
也就是合适的开操作,可以去掉小的对象。
在二值图中,表现为去掉白色的小点或填充黑点
闭操作
闭操作即为先膨胀后腐蚀。
我们以单通道的黑白图像为例讲解,也就是我们先通过膨胀操作,白色区域膨胀扩大,再通过腐蚀操作,黑色区域腐蚀扩大。
如果我有一个小黑点,先通过膨胀操作,就会被周围的白色覆盖掉,再进行腐蚀操作,因为小黑点已经没有了,进行腐蚀操作,也不会影响到周围的白色,所以,闭操作,可以去掉小黑点。
也就是合适的闭操作,可以去掉小的对象。
在二值图中,表现为去掉黑色的小点或填充白点
形态学梯度
形态学梯度即为膨胀减去腐蚀。
我们以一个二维数组为例来讲解。对于下面左边的图像
进行膨胀之后的操作结果如下
而进行腐蚀操作如下:
形态学梯度就是膨胀减去腐蚀,如下:
顶帽
顶帽是原图像与开操作图像之间的差值图像。
开操作我们去掉了白色的小对象,其他地方没有变化,进行差值之后变成0,也就是变成黑色
不同的进行差值之后,我们就获得了去掉的白色的区域,然后我们就要考虑这个区域的颜色是什么颜色,因为原图是白色,对应的值是255,进行开操作之后变为黑色,对应的值是0,进行差值之后还是255,也就是还是白色,即原来的颜色。
所以顶帽操作,求到的就是去掉的白色大块的小对象。
黑帽
黑帽是原图像与闭操作图像之间的差值图像。
闭操作我们填充了黑色的小对象,其他地方没有变化,进行差值之后变成255,也就是变成黑色
其他地方进行差值之后,我们就获得了填充的黑色的区域,然后我们就要考虑这个区域的颜色是什么颜色,因为原图是黑色,对应的值是0,进行闭操作之后变为白色,对应的值是255,进行差值之后是255,也就是变成白色。所以顶帽操作,求到的就是去掉的白色的小对象。
顶帽黑帽结论
- 不管是顶帽还是黑帽,我们得到的都是原图像与开/闭操作的差值图像,差值地方是白色,其他地方是黑色。
opencv中形态学操作
核生成API
在形态学中,因为要涉及到区域像素操作,我们就要设计一个核,在核范围内对像素进行操作。所以我们需要创建一个核,在这里,我们用到一个新的API:
getStructuringElement()
Mat getStructuringElement(
int shape,
Size ksize,
Point anchor = Point(-1,-1)
);
(1)int类型的shape,元素形状,可以是cv::MorphShapes之一。
(2)Size类型的ksize,结构化元素的大小。
(3)Point类型的anchor,默认值(-1,-1),表示锚定位于中心。请注意,只有十字形元素的形状取决于锚定位置。在其他情况下,锚只是调节形态学操作结果的移动量。
这里主要说一下第一个参数,该参数主要有如下几种选择:
-(1)MORPH_RECT:矩形结构区域。
-(2)MORPH_CROSS,十字形结构区域。
-(3)MORPH_ELLIPSE,椭圆结构区域,内接于矩形Rect(0,0,esize.width,0.esize.height)的填充椭圆。
形态学操作
API
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()
);
(1)InputArray类型的src,输入图像。通道数可以任意,但深度应为CV_8U、CV_16U、CV_16S、CV_32F或CV_64F之一。
(2)OutputArray类型的dst,即目标图像,与输入图像有相同的尺寸和类型。
(3)int类型的op,形态学操作的类型,请参见cv::MorphTypes
(4)InputArray类型的kernel,用于膨胀的结构元素;如果elemenat=Mat(),则使用3 x 3矩形结构元素。可以使用getStructuringElement创建内核。
(5)Point类型的anchor:锚定在元素中的位置;默认值(-1,-1)表示锚定在元素中心。
(6)int类型的iterations:应用膨胀的次数。
(7)int类型的borderType:像素外推方法,参见cv::BorderTypes。
(8)Scalar类型的borderValue:恒定边框时的边框值。
相比较膨胀和腐蚀,只是增加了第三个参数,其他参数是完全一致的,第三个参数是操作,即所有的形态学操作。主要有:
enum MorphTypes{
MORPH_ERODE = 0, //腐蚀
MORPH_DILATE = 1, //膨胀
MORPH_OPEN = 2, //开操作
MORPH_CLOSE = 3, //闭操作
MORPH_GRADIENT = 4, //梯度操作
MORPH_TOPHAT = 5, //顶帽操作
MORPH_BLACKHAT = 6, //黑帽操作
};
前两个是我们之前讲过的膨胀和腐蚀,剩下的就是我们今天讲的五个形态学操作。
而我们的API,一般来说,我们只需要设置前四个参数,后面的参数默认即可。
代码
#include<opencv2\opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
Mat src, dst;
src = imread("ur path of pic");
if (!src.data)
{
cout << "could not load image !";
return -1;
}
imshow("src", src);
Mat kernel = getStructuringElement(MORPH_RECT, Size(7, 7), Point(-1, -1));
//开操作
morphologyEx(src, dst, CV_MOP_OPEN, kernel);
imshow("open-src", dst);
//闭操作
morphologyEx(src, dst, CV_MOP_CLOSE, kernel);
imshow("close-src", dst);
//形态学梯度
morphologyEx(src, dst, CV_MOP_GRADIENT, kernel);
imshow("gradient-src", dst);
//顶帽
morphologyEx(src, dst, CV_MOP_TOPHAT, kernel);
imshow("tophat-src", dst);
//黑帽
morphologyEx(src, dst, CV_MOP_BLACKHAT, kernel);
imshow("blackhat-src", dst);
waitKey(0);
return 0;
}
效果
原图
开操作
闭操作
形态学梯度
顶帽
黑帽