腐蚀与膨胀
- 膨胀
跟卷积操作类似,假设有图像A和结构元素B,结构元素B在A上面移动,其中B定义其中心为锚点,计算B覆盖下A的最大像素值用来替换锚点的像素,其中B作为结构体可以是任意形状。
- 腐蚀
腐蚀跟膨胀操作的过程类似,唯一不同的是以最小值替换锚点重叠下图像的像素值。
就是一个封装好的可以拖动的滑块。
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
Mat src, dst;
char output_title[] = "output image";
int element_size = 3;
int max_size = 21;
void CallBack_Demo(int, void*);
int main(int argc, char** agrv)
{
src = imread("C:/Users/Administrator/Pictures/20160711084909.jpg");
if (!src.data) {
cout << "could not load image...0" << endl;
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
createTrackbar("Element Size", output_title, &element_size, max_size, CallBack_Demo);
CallBack_Demo(0, 0);
waitKey(0);
return 0;
}
void CallBack_Demo(int, void*)
{
int s = element_size * 2 + 1;
Mat structureElement = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1));
dilate(src, dst, structureElement, Point(-1, -1), 1);
imshow(output_title, dst);
}
代码解释:
createTrackbar(“Element Size”, output_title, &element_size, max_size, CallBack_Demo);
其中:element size是调节窗口的名称,output_title是控制哪个窗口,&element_size和max_size是调节参数,CallBack_Demo是自己写的操作函数。
下面介绍CallBack_Demo:
void CallBack_Demo(int, void*)
{
int s = element_size * 2 + 1;
Mat structureElement = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1));
dilate(src, dst, structureElement, Point(-1, -1), 1);
imshow(output_title, dst);
}
getStructureElement()是构造形态学使用的kernel,参数MORPH_RECT代表矩形,size(s, s)是参数,使用递归的方法调节。
dilate(src, dst, structureElement, Point(-1, -1), 1);
这是膨胀的API,参数分别传入原图,变化后的图,动态调节kernel,默认的锚点(-1, -1)和迭代运行几次(默认1次)。
图1-1 调节后的图(膨胀)
图1-2 调节满的图(膨胀)
- 腐蚀
腐蚀和迭代类似,只是变一个名字,参数一样。
erode(src, dst, structureElement, Point(-1, -1), 1);
图1-3 调节后的图(腐蚀)
图1-4 调节满的图(腐蚀)
- 开操作
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat src, dst;
src = imread("C:/Users/Administrator/Pictures/20190831132020.jpg");
if (!src.data) {
cout << "could not load image...0" << endl;
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
char output_title[] = "sorphology demo";
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(src, dst, CV_MOP_OPEN, kernel);
imshow(output_title, dst);
waitKey(0);
return 0;
}
开操作:morphologyEx(src, dst, CV_MOP_OPEN, kernel);
其中:morphologyEx()是形态学操作,CV_MOP_OPEN是开操作,在此之前需要声明一个结构化元素。
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
效果图:
图1-5 开操作
- 闭操作
闭操作与开操作类似,只需将形态学操作改为:
morphologyEx(src, dst, CV_MOP_CLOSE, kernel);
如果去除不完全,需要改结构化元素中Size()的值。
图1-6 闭操作
根据上一节动态调节结构化元素的联系,自制了一个小程序:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
Mat src, dst;
char output_title[] = "sorphology demo";
int element_size = 1;
int max_size = 21;
void CallBack_Demo(int, void*);
int main(int argc, char** argv)
{
src = imread("C:/Users/Administrator/Pictures/20190831132941.jpg");
if (!src.data) {
cout << "could not load image...0" << endl;
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
createTrackbar("Element Size", output_title, &element_size, max_size, CallBack_Demo);
CallBack_Demo(0, 0);
waitKey(0);
return 0;
}
void CallBack_Demo(int, void*)
{
int s = element_size * 2 + 1;
Mat structureElement = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1));
morphologyEx(src, dst, CV_MOP_CLOSE, structureElement);
imshow(output_title, dst);
}
可以实现动态调节闭操作的结构化元素。
- 形态学梯度
morphologyEx(src, dst, CV_MOP_GRADIENT, kernel);
图1-7 形态学梯度
- 顶帽
morphologyEx(src, dst, CV_MOP_TOPHAT, kernel);
图1-8 顶帽
- 黑帽
图1-9 黑帽