最基本的形态学操作:膨胀和腐蚀(所有操作都是对于高亮部分而言,即白色部分)
主要作用:
1.消除噪声
2.分割出独立的图像元素,连接图像中的相邻元素
3.寻找图像中明显的极大值区域或极小值区域
4.求出图像的梯度
膨胀:
通俗来说就是求出图片的局部最大值的操作,具体操作,是通过掩膜,与原图片卷积,是局部最大值(即掩膜中的中心点,所获得权值变大),这样操作使图像中的高亮区域逐渐增长。
腐蚀:
腐蚀相当于膨胀的相反操作,是一个求图像局部最小值的操作,具体操作同样是通过掩膜进行的。
(在源码中,膨胀和腐蚀的函数原型一直,进行哪种操作往往取决于一个参数值)
API使用:
膨胀:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src = imread("E://hashiqi.jpg");
Mat dst;
namedWindow("原始图像", 1);
imshow("原始图像", src);
namedWindow("膨胀图像", 1);
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
dilate(src, dst, element);
imshow("膨胀图像", dst);
waitKey(0);
}
dilate函数,一参二参为输入输出图像,三参为内核,通俗的理解就是掩膜
而创建element函数:getStructuringElement中,一参代表内核形状,共有三种选择
矩形:MORPH_RECT;
交叉形:MORPH_CROSS;
椭圆形:MORPH_ELLIPSE;
二参为尺寸,三参为默认锚点
这个一参的用途,主要就是会将膨胀点,以不同形态输出
还有一个迭代次数,默认值为1
腐蚀:
参数同上,用法同上,因为其函数原型一致
erode(src, dst, getStructuringElement(MORPH_ELLIPSE, Size(size_value, size_value)), Point(-1, -1), 1);
结果如下:
图像的开运算
本质上为先腐蚀后膨胀操作,dilate(erode(src,element));很明了,懂得都懂
开运算可以用来消除小物体,在纤细处分离物体,并且在平滑较大物体的边界同时不明显改变其面积
图形的闭运算
同上,本质上是这个:erode(dilate(src,element));
闭运算能够排除小型黑洞(黑色区域)
形态学梯度
本质上是膨胀图和腐蚀图之差,众所周知,膨胀图求出局部最大值,腐蚀图求出局部最小值,差值得话,在视觉体验上类似一种大幅度的梯度变化,对二值图像进行这一操作可以将团块(blod)的边缘突出出来,我们可以用形态学梯度来保留物体的边缘轮廓
顶帽运算
原图像与开图像的差值,突出了比原图轮廓周围的区域更明亮的区域,且这一操作与选择的核的大小相关
在一幅图像具有大幅的背景,而微小物品比较规律的情况下,可以使用顶帽运算进行背景提取
黑帽运算
原图像与闭运算的结果图之差,突出了比原图轮廓周围的区域更暗的区域,且这一操作与选择和核的大小相关
黑帽运算用来分离比邻近点暗一些的斑点块,效果图有着非常完美的轮廓
核心API函数morphologyEx()
从图像的开闭运算,形态学梯度运算,顶帽黑帽运算的源码开始观察,会发现其实现都是写在一个morphologyEx()函数的switch结构下,也可以理解为该函数是图像形态学运算的核心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() )
输入输出图像不用说,op为形态学运算的类型,MORPH_OPEN,CLOSE,GRANDIENT,TOPHAT,BLACKHAT,ERODE,DILATE
四参为内核(掩膜),后面就是锚点,迭代次数,边框类型,最后一个参数暂时不用管,与边界值相关
综合示例:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
static Mat src, dst1,dst2,dst3,dst4,dst5;
static int choosen = 0;
static int choosen2 = 0;
static int kannel_size = 10;
static int isgradient = 0;
void get_choosen(int, void*);
void get_choosen2(int, void*);
void change_size(int, void*);
void is_gradient(int, void*);
static void to_open();
static void to_close();
static void to_tophat();
static void to_blackhat();
int main(int argc, char** argv) {
src = imread("E://hashiqi.jpg",0);
namedWindow("原图", 1);
imshow("原图", src);
createTrackbar("开闭选择", "原图", &choosen, 1, get_choosen);
createTrackbar("顶帽黑帽选择", "原图", &choosen2, 1, get_choosen2);
createTrackbar("内核值", "原图", &kannel_size, 30, change_size);
createTrackbar("梯度展示", "原图", &isgradient, 1, is_gradient);
namedWindow("开运算", 1);
namedWindow("闭运算", 1);
namedWindow("顶帽", 1);
namedWindow("黑帽", 1);
namedWindow("梯度", 1);
change_size(kannel_size, 0);
get_choosen(choosen, 0);
waitKey(0);
}
void change_size(int temp, void*) {
kannel_size = temp;
}
void get_choosen(int, void*) {
if (choosen == 0) {
to_open();
}
else
{
to_close();
}
}
void get_choosen2(int, void*) {
if (choosen == 0) {
to_tophat();
}
else
{
to_blackhat();
}
}
void is_gradient(int, void*) {
if (isgradient == 1) {
morphologyEx(src, dst5, MORPH_GRADIENT, getStructuringElement(MORPH_CROSS, Size(kannel_size, kannel_size), Point(-1, -1)), Point(-1, -1));
imshow("梯度", dst5);
}
}
void to_open() {
morphologyEx(src, dst1, MORPH_OPEN, getStructuringElement(MORPH_CROSS, Size(kannel_size, kannel_size), Point(-1, -1)));
imshow("开运算", dst1);
}
void to_close() {
morphologyEx(src, dst2, MORPH_CLOSE, getStructuringElement(MORPH_CROSS, Size(kannel_size, kannel_size), Point(-1, -1)));
imshow("闭运算", dst2);
}
void to_tophat() {
morphologyEx(src, dst3, MORPH_TOPHAT, getStructuringElement(MORPH_CROSS, Size(kannel_size, kannel_size), Point(-1, -1)));
imshow("顶帽", dst3);
}
void to_blackhat() {
morphologyEx(src, dst4, MORPH_BLACKHAT, getStructuringElement(MORPH_CROSS, Size(kannel_size, kannel_size), Point(-1, -1)));
imshow("黑帽",dst4);
}
结果如图: