形态学通常表示生物学的一个分支,该分支主要研究动植物的形态和结构。图像处理中得形态学是指数学形态学。数学形态学(Mathematical morphology) 是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。其基本的运算包括:腐蚀和膨胀、开运算和闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换等。
形态学就是基于形状的一系列图像处理的操作。最基本的形态学有两种即膨胀(dilate)与腐蚀(erode)。膨胀与腐蚀可以实现很多功能,主要是以下几种:
- 消除噪声;
- 分割出独立的图像元素,连接相邻的元素;
- 寻找图像中得明显的极大值区域或极小值区域;
- 求图像的梯度。
腐蚀和膨胀是对于白色部分(高亮部分),而不是黑色部分。膨胀会使高亮部分区域更大,而腐蚀会让高亮区域更小。膨胀是求局部最大值的操作,而腐蚀则是求局部最小值的操作。膨胀的数学表达式如下:
![669098a703cf257c2f96955c84de2cd4.png](https://i-blog.csdnimg.cn/blog_migrate/756be9d7e60122d4e88263ff30d00d40.png)
腐蚀的数学表达式如下:
![e280c2d7f8780da00a68cb2d4c4700e2.png](https://i-blog.csdnimg.cn/blog_migrate/6d0e60754a4c532ec42f12afe9f67ae2.png)
在opencv中提供了膨胀和腐蚀的API,首先看一下函数原型:
膨胀:
void cv::dilate( InputArray src, OutputArray dst, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
腐蚀:
void cv::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 : 输出的目标图像,和原图像有相同尺寸和大小
kernel : 腐蚀或者膨胀的卷积核,当为NULL时,表示的使用锚点位于中心的3x3的卷积核
anchor : 锚点位置,当为(-1,-1)时候,表示位于中心
iteration:表示迭代的腐蚀或者膨胀的次数
borderType :用于推断图像外部像素的某种边界模式
borderValue:当边界为常数时的边界值
膨胀与腐蚀往往会结合getStructuringElement函数一起使用,看一下getStructingElement函数,函数原型如下:
cv::Mat getStructuringElement(int shape, cv::Size ksize, cv::Point anchor = Point(-1,-1))
函数功能:返回一个指定大小和形状的结构元素,用于形态学操作。
参数说明:
shape: 结构元素的形状,有以下三种:
MORPH_RECT : 矩形
MORPH_CROSS : 交叉形状
MORPH_ELLIPSE: 椭圆形
ksize :结构元素的大小
anchor : 指定锚点位置,当锚点为(-1,-1)表示锚点位于结构元素中心。
下面看一下膨胀和腐蚀的代码示例:
#include <iostream>
#include <opencv2/opencv.hpp>
cv::Mat srcImage;
cv::Mat srcImage1;
void OnErode(int pos,void *userdata)
{
cv::Mat dstImage;
cv::Mat element = cv::getStructuringElement(pos,cv::Size(5,5),cv::Point(-1,-1));
cv::erode(srcImage,dstImage,element);
cv::imshow("erode",dstImage);
}
void onDilate(int pos,void *userdata)
{
cv::Mat dstImage;
cv::Mat element = cv::getStructuringElement(pos,cv::Size(5,5),cv::Point(-1,-1));
cv::dilate(srcImage,dstImage,element);
cv::imshow("dilate",dstImage);
}
int main(int argc,char *argv[]) {
srcImage = cv::imread(argv[1]);
if (!srcImage.data)
{
std::cerr << "fail to load image" << std::endl;
return -1;
}
srcImage1 = srcImage.clone();
cv::namedWindow("dilate",cv::WINDOW_AUTOSIZE);
cv::namedWindow("erode",cv::WINDOW_AUTOSIZE);
cv::createTrackbar("Dilate","dilate",0,2,onDilate);
cv::createTrackbar("Erode","erode",0,2,OnErode);
cv::imshow("dilate",srcImage);
cv::imshow("erode",srcImage1);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
结果展示:
![a4a0e1f52c89c5ef997b1ebb62a5dda8.png](https://i-blog.csdnimg.cn/blog_migrate/b88177c7b4a08c6d4edfd5d71994d51b.jpeg)
![c33ad3153fdbf85d97788fc0811257cd.png](https://i-blog.csdnimg.cn/blog_migrate/fdc9799a655a0c02a9bc91aca382a07d.jpeg)