OpenCV C++记录(十):形态学处理基础
形态学处理
在传统图像处理中,形态学处理可算是最为强大的功能之一,只要你稍微有一些粗略的识别-分类需求需要对图像进行前处理,形态学都能帮上大忙,而且具备极高的计算效率。
这得益于其计算原理的简单,腐蚀和膨胀是两种基本操作,注意这里形态学处理的对象都是二值图;
腐蚀与膨胀
腐蚀的基本原理是以二值卷积核和二值图卷积,只要一个位置的相乘结果为0,那么中心像素即为0:

腐蚀函数原型是: 1
2
3
4
5
6
7
8
9void erode(
cv::InputArray src, //输入二值图像
cv::OutputArray dst, //输出二值图像
cv::InputArray kernel, //卷积核
cv::Point anchor = cv::Point(-1, -1), //处理锚点,默认中心点
int iterations = 1, //腐蚀次数
int borderType = 0, //边值处理:默认常数填充
const cv::Scalar &borderValue = morphologyDefaultBorderValue() //仅borderType = 0生效, 填充常数,默认为Scalar(0)
)
膨胀是腐蚀的逆运算,其计算与腐蚀完全相反,即二值卷积核和二值图进行卷积,只要其中一个位置像素为1,那么中心像素就赋值为1:

所以其效果是和腐蚀相反的,往往用于填充黑色结构,例如补足物体中间的黑色小洞,其函数原型是:
1
2
3
4
5
6
7
8
9void dilate( //参数意义同erode,不赘述
cv::InputArray src,
cv::OutputArray dst,
cv::InputArray kernel,
cv::Point anchor = cv::Point(-1, -1),
int iterations = 1,
int borderType = 0,
const cv::Scalar &borderValue = morphologyDefaultBorderValue()
)cv::getStructuringElement
提供了矩形、椭圆(圆)、十字形三种常用的结构,适用于不同的目标(例如圆形目标使用椭圆能维持光滑性):
1
2
3
4
5
6
7
8
9
10cv::Mat getStructuringElement(
int shape,
cv::Size ksize,
cv::Point anchor = cv::Point(-1, -1)
)
其中shape类型:
- cv::MORPH_ELLIPSE:椭圆卷积核
- cv::MORPH_RECT:矩形卷积核
- cv::MORPH_CROSS:十字卷积核
示例: 1
2
3
4
5
6
7
8Mat rawPic = imread("D:/Documents/Desktop/holeTest/test.png",0);
Mat binary;
cv::threshold(rawPic,binary,0,255,cv::THRESH_BINARY|cv::THRESH_OTSU);
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(17, 17));
Mat eroded;
erode(binary, eroded, kernel);
Mat dilated;
dilate(eroded, dilated ,kernel);
开运算与闭运算
单独的腐蚀或者膨胀都会对图像产生有害操作,要么目标腐蚀后黑色像素变多,白色结构减少;要么目标膨胀后白色像素变多,白色结构外扩;然而,腐蚀和膨胀都是逆运算,意味着当使用同一个卷积核进行膨胀和腐蚀,不会对目标像素产生损害,而仅仅去除冗余的黑色结构或者白色结构;
先腐蚀后膨胀称为开运算,去除白色结构:
1
2
3cv::Mat opened;
Mat kernel1 = 5*getStructuringElement(cv::MORPH_ELLIPSE,Size(26,26));
morphologyEx(dilated,opened,cv::MORPH_OPEN,kernel1);
先膨胀再腐蚀称为闭运算,填充黑色结构:
1
2
3cv::Mat opened;
Mat kernel1 = 5*getStructuringElement(cv::MORPH_ELLIPSE,Size(26,26));
morphologyEx(dilated,opened,cv::MORPH_OPEN,kernel1);
其余处理
它们反应了图像的轮廓特征,比较少用。 ### 形态学梯度
当处理参数为cv::MORPH_GRADIENT
时,所求结果为形态学梯度,它是图像开运算和闭运算的差值:
1
2
3
4
5
6Mat rawPic = imread("D:/Documents/Desktop/holeTest/S000029_P1.png",0);
cv::Mat gradient;
Mat kernel = 5*getStructuringElement(cv::MORPH_ELLIPSE,Size(10,10));
morphologyEx(rawPic,gradient,cv::MORPH_GRADIENT,kernel);
namedWindow("gradient",cv::WINDOW_NORMAL);
imshow("gradient", gradient);
黑帽
处理参数为cv::MORPH_BLACKHAT
,结果是原图和闭运算图的差值,即填充掉的黑色结构:
1
2
3
4
5
6Mat rawPic = imread("D:/Documents/Desktop/holeTest/S000029_P1.png",0);
cv::Mat blackHat;
Mat kernel = 5*getStructuringElement(cv::MORPH_ELLIPSE,Size(25,25));
morphologyEx(rawPic,blackHat,cv::MORPH_BLACKHAT,kernel);
namedWindow("blackHat",cv::WINDOW_NORMAL);
imshow("blackHat", blackHat);
礼帽
处理参数为cv::MORPH_TOPHAT
,结果是开运算和原图的差值,即腐蚀掉的白色结构:
1
2
3
4
5
6Mat rawPic = imread("D:/Documents/Desktop/holeTest/S000029_P1.png",0);
cv::Mat topHat;
Mat kernel = 5*getStructuringElement(cv::MORPH_ELLIPSE,Size(25,25));
morphologyEx(rawPic,topHat,cv::MORPH_TOPHAT,kernel);
namedWindow("topHat",cv::WINDOW_NORMAL);
imshow("topHat", topHat);