理论:
形态学操作:腐蚀、膨胀、开、闭,形态学梯度,顶帽,其中膨胀与腐蚀是图像处理中最常用的形态学操作手段。
膨胀:跟卷积操作类似,假设有图像A和结构元素B,结构元素B在图像A上移动,其中B定义其中心为锚点,计算B覆盖下的A的最大像素值用来替换锚点的像素,其中B作为结构体可以是任意形状。(注:是用结构B覆盖下的最大像素值来代替锚点)
效果如下:(背景区域膨胀,图像内容i变细)
腐蚀:跟膨胀操作的过程类似,唯一不同的是以最小值替换锚点重叠下的图像的像素值。(注:是用结构B覆盖下的最小像素值来代替锚点)
效果如下:(背景区域腐蚀,图像内容i变粗)
开操作:先膨胀后腐蚀,可以去掉小对象。(结合上面两个图,我是这样记忆的,从门里照射一束光后形成一个光影,先关门-腐蚀操作光影变小,再开门-膨胀操作光影变大,最后的动作是开门所以记为开操作)。
效果如下:
闭操作:先腐蚀后膨胀,可以填充小洞。(记忆方法和开操作一样)。
效果图如下:
形态学梯度:又称基本梯度,膨胀减去腐蚀,其他的还有内部梯度和方向梯度。
效果图如下:
顶帽:原图像与开操作之间的差值图像。
效果图如下:
黑帽:闭操作与原图像的差值图像。
效果图如下:
API
第一步先定义核(模板)kernel=getStructuringElement(int shape,size ksize, point anchor)-第一个参数定义核的形状(MORPH_RECT矩形、MORPH_CROSS圆、MORPH_ELLIPSE椭圆)第二个参数表示大小,第三个参数定义锚点默认为point(-1,-1)中心点
第二步:
膨胀:dilate(src,dst,kernel);腐蚀:erode(src,dst,kernel);src-输入图像,dst-输出图像,kernel-核
形态学操作:morphologyEx(src,dst,CV_MOP_BLACKHAT,kernel,iteration),第一个参数输入图像,第二个参数输出图像,第三个参数形态学操作类型包括(CV_MOP_CLOSE闭操作,CV_MOP_OPEN开操作,CV_MOP_GRADIENT基本梯度操作,CV_MOP_TOPHAT顶帽操作,CV_MOP_BLACKHAT黑帽操作),第四个参数核,第五个参数跌打次数默认为1
程序示例
膨胀与腐蚀
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
Mat src, dst;
char OUTPUT_WIN[] = "output image";
int element_size = 3;
int max_size = 21;
void CallBack_Demo(int, void*);
int main(int argc, char** argv) {
src = imread("D:/test.png");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
createTrackbar("Element Size :", OUTPUT_WIN, &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);//膨胀
erode(src, dst, structureElement);//腐蚀
imshow(OUTPUT_WIN, dst);
return;
}
膨胀的效果图
腐蚀的效果图
形态学操作
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
int main(int argc, char** argv) {
Mat src, dst;
src = imread("D:/test.png");
if (!src.data) {
printf("could not load image...\n");
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
char output_title[] = "morphology demo";
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
Mat kernel = getStructuringElement(MORPH_RECT, Size(11, 11), Point(-1, -1));
morphologyEx(src, dst, CV_MOP_BLACKHAT, kernel);//CV_MOP_CLOSE闭操作,CV_MOP_OPEN开操作,CV_MOP_GRADIENT基本梯度操作,CV_MOP_TOPHAT顶帽操作,CV_MOP_BLACKHAT黑帽操作
imshow(output_title, dst);
waitKey(0);
return 0;
}
黑帽操作
顶帽操作
开操作
闭操作
基本梯度操作
当然以上操作都可以更改kernel的结构如下:
// 水平结构元素
Mat hline = getStructuringElement(MORPH_RECT, Size(src.cols / 16, 1), Point(-1, -1));
// 垂直结构元素
Mat vline = getStructuringElement(MORPH_RECT, Size(1, src.rows / 16), Point(-1, -1));
// 矩形结构
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
直接替换API中的kernel就可以实现,有兴趣的可以试试。