形态学操作本身是图像处理要研究的内容,而计算机视觉要实现相关功能,也要实现图像的处理。在图像处理技术中,有一些的操作会对图像的形态发生改变,这些操作一般称之为形态学操作。
讲的再专业一些:
图像形态学操作是基于形状的一系列图像处理操作的合集,主要是基于集合论基础上的形态学数学。
两个基本操作:
- (1)膨胀:跟卷积操作类似,假设有图像A和结构元素B,结构元素B在A上面移动,其中B定义其中心为锚点,计算B覆盖下A的最大像素值用来替换锚点的像素,其中B作为结构体可以是任意形状。
- (2)腐蚀:腐蚀跟膨胀操作的过程类似,唯一不同的是以最小值替换锚点重叠下图像的像素值。
基于基本操作的操作:
(1)开操作:先腐蚀后膨胀,可以去掉小的对象。
(2)闭操作:先膨胀后腐蚀,可以填充小对象。
(3)形态学梯度:膨胀减去腐蚀。
(4)顶帽:顶帽是原图像与开操作图像之间的差值图像。
(5)黑帽:黑帽是闭操作图像与原图像之间的差值图像。
在形态学中,因为要涉及到区域像素操作,我们就要设计一个核,在核范围内对像素进行操作。所以我们需要创建一个核,在这里,我们用到一个新的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)的填充椭圆。
膨胀就是计算B覆盖下A的最大像素值用来替换锚点的像素。
我们要使用像素最大值,来替换锚点的像素,也就是用区域内的像素最大的值代替区域内锚点的值,所谓锚点,就是区域的中心点。
我们考虑最简单的区域,一个3×3的正方形区域,锚点就是正方形区域的中心点,假设我们有下图中这个一维像素数组,
对于图中黄色区域,由于其中的最大值为255,所以其锚点处(红色数字)由9变为255。
当所有的都执行完该操作之后,生成的图像如下:
注意:图像的膨胀是基于原图的
如果膨胀一个点,替换值之后再做下一个点,那么整张图都是255
即
这个点是基于原图的9来进行膨胀的,而不是膨胀过后左上角255来膨胀
所以锚点位置是9而不是255
再如《数字图像处理(冈萨雷斯)》中
用算子的锚点沿着图像的边界画一圈,算子扫过的地方就是图像膨胀的地方
膨胀是将周围像素值小的一圈替换为大的一圈,即白色变多黑色变少
void dilate(
InputArray src,
OutputArray dst,
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)InputArray类型的kernel,用于膨胀的结构元素;如果elemenat=Mat(),则使用3 x
3矩形结构元素。可以使用getStructuringElement创建内核。(4)Point类型的anchor:锚定在元素中的位置;默认值(-1,-1)表示锚定在元素中心。。
(5)int类型的iterations:应用膨胀的次数。。
(6)int类型的borderType:像素外推方法,参见cv::BorderTypes。
(7)Scalar类型的borderValue:恒定边框时的边框值。
一般来说,我们只需要设置前三个参数,后面的参数默认即可。
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat src, dst;
src = imread("ur own 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));
//算子的大小可以根据需要进行调整
dilate(src, dst, kernel);
imshow("dilate-src", dst);
waitKey(0);
return 0;
}
腐蚀就是计算B覆盖下A的最小像素值用来替换锚点的像素。
我们要使用像素最小值,来替换锚点的像素,也就是用区域内的像素最小的值代替区域内锚点的值,所谓锚点,就是区域的中心点。
我们考虑最简单的区域,一个3×3的正方形区域,锚点就是正方形区域的中心点,假设我们有下图中这个一维像素数组,
对于图中黄色区域,由于其中的最大值为1,所以其锚点处(红色数字)由9变为1。
注意:图像的腐蚀是基于原图的
如果腐蚀一个点,替换值之后再做下一个点,那么整张图都是1
再如《数字图像处理(冈萨雷斯)》中
算子的锚点沿着图像扫一圈,剩下的区域就是腐蚀过后的图像
再回到我们这张图
腐蚀是将周围像素值大的一圈替换为小的一圈,即白色变少黑色变多
void erode(
InputArray src,
OutputArray dst,
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类型的d,滤波过程中使用的每个像素邻域的直径。如果是非正的,则从sigmaSpace计算。
(4)double类型的sigmaColor
,颜色空间中过滤器sigma。参数值越大,意味着像素邻域(参见sigmaSpace)中的更多颜色将混合在一起,从而产生更大的半等色区域。(5)double类型的sigmaSpace,在坐标空间中过滤器sigma。参数值越大,意味着更远的像素将相互影响,只要它们的颜色足够接近(参见sigmaColor)。当d大于0时,它指定邻域大小,而不考虑sigmaSpace。否则,d与sigmaSpace成比例。
(6)int类型的borderType,用于在图像外部外推像素的边框模式,具体请参见cv::BorderTypes。
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat src, dst;
src = imread("path");
if (!src.data)
{
cout << "could not load image !";
return -1;
}
imshow("src", src);
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
erode(src, dst, kernel);
imshow("erode-src", dst);
waitKey(0);
return 0;
}