目录
形态学通用API:morphologyEx
一、基础理论
1、邻接关系
(1)四邻接:
(2)D邻接:
(3) 八邻接:
2、连通性
(1)四连通:
(2)八连通:
(3)m连通:
3、形态学基础
二、结构元
三、膨胀
1、基础理论
作用:
原理:
2、膨胀函数dilate()
3、代码
4、效果
四、腐蚀
1、原理
作用:
原理:
2、腐蚀函数erode()
3、代码、
4、效果
四、简便操作---回调函数与滑动条
1、回调函数
2、滑动条创建
3、代码
4、效果
参考资料
morphologyEx(Mat src, Mat dst, int op, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue)
参数介绍:
第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像位深应该为以下五种之一:CV_8U, CV_16U,CV_16S, CV_32F 或CV_64F。
第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。
第三个参数,int类型的op,表示形态学运算的类型,可以是如下之一的标识符:enum MorphTypes{ MORPH_ERODE = 0, //腐蚀 MORPH_DILATE = 1, //膨胀 MORPH_OPEN = 2, //开操作 MORPH_CLOSE = 3, //闭操作 MORPH_GRADIENT = 4, //梯度操作 MORPH_TOPHAT = 5, //顶帽操作 MORPH_BLACKHAT = 6, //黑帽操作 MORPH_HITMISS = 7 };
第四个参数,InputArray类型的kernel,形态学运算的内核。
在图像中,最小的单位是像素,每个像素周围有8个邻接像素,常见的邻接关系有3种:4邻接、D邻接和8邻接。
形态学是基于图像形状的一些操作,通常在二进制图像上进行。(腐蚀和膨胀是两个基本的形态学运算符, 它的变体形式如开运算、闭运算、礼帽和黑帽等等)
腐蚀和膨胀:
膨胀︰求局部最大值(消除内部噪声)
腐蚀:求局部最小值(使内部噪声变大)开闭运算:
开∶先腐蚀后膨胀(消除噪声)闭:先膨胀后腐蚀(填充孔洞)
礼帽和黑帽:
礼帽:原图像与开运算之差(找到亮区域)黑帽:闭运算与原图像之差(找到暗区域)
getStructuringElement()函数会返回指定形状和尺寸的结构元素。
Mat getStructuringElement(int shape, Size esize, Point anchor = Point(-1, -1));
参数介绍:
参数1:(卷积核形状)
矩形:MORPH_RECT;
交叉形:MORPH_CROSS;
椭圆形:MORPH_ELLIPSE;
参数2:内核的尺寸(宽,高)(必须为奇数)
参数3:锚点位置(默认值Point(-1,-1)表示锚点位于中心点)
实例:
C++;
//卷积核(结构元)
Mat structureElement = getStructuringElement(MORPH_RECT, Size(11, 11) , Point(-1,-1));
// 返回指定形状和尺寸的结构元素 形状 尺寸(宽, 高) 锚点(中心点)
作用:
将与物体接触的所有背景点融入物体中,使目标增大,可填补目标中的空洞。
原理:
取结构元领域内最大值,所以膨胀后输出图像的总体亮度的平均值比起原图会有所升高,扩张高亮区域,而较暗物体的尺寸会减小甚至消失(暗的地方被覆盖)。(红色是参考点/锚点)(类似于“或”操作,附近都为0,锚点才为0,否则为1)
c++:
//膨胀函数
dilate(img, dst, structureElement, Point(-1, -1), 1);
// 原图 新图 卷积核(结构元) 锚点 膨胀操作次数(默认1次)
python:
dilate = cv2.dilate(img, kernel=(7, 7), iterations=1)
# 卷积核大小 迭代次数
C++:
//膨胀
void Dilate()
{
//卷积核(结构元)
Mat structureElement = getStructuringElement(MORPH_RECT, Size(11, 11) , Point(-1,-1));
// 返回指定形状和尺寸的结构元素 形状 尺寸(宽, 高) 锚点(中心点)
//膨胀函数
dilate(img, dst, structureElement, Point(-1, -1), 1);
// 原图 新图 卷积核(结构元) 锚点 膨胀操作次数(默认1次)
}
python:
# 膨胀
def Dilate():
# 膨胀
dilate = cv2.dilate(img, kernel=(7, 7), iterations=1)
# 卷积核大小 迭代次数
cv2.imshow("dilate", dilate)
作用:
可以用于去除噪声。
原理:
腐蚀操作与膨胀操作类似,只是它取结构元所指定的领域内值的最小值作为该位置的输出灰度值。因为取每个位置领域内最小值,所以腐蚀后输出图像的总体亮度的平均值比起原图会有所降低,图像中比较亮的区域的面积会变小甚至消失(亮的地方被覆盖),而较暗区域的尺寸会扩大。(蚕食高亮区域)
(类似于“与”操作,附近只要有1个为0,锚点就位0)
//腐蚀函数
erode(img, dst, structureElement, Point(-1, -1), 1);
// 原图 新图 卷积核(结构元) 锚点 腐蚀操作次数(默认1次)
erode = cv2.erode(img, kernel=(7, 7), iterations=5)
# 卷积核大小 迭代次数
C++:
//腐蚀
void Erode()
{
//卷积核(结构元)
Mat structureElement = getStructuringElement(MORPH_RECT, Size(11, 11), Point(-1, -1));
// 返回指定形状和尺寸的结构元素 形状 尺寸(宽, 高) 锚点(中心点)
//腐蚀函数
erode(img, dst, structureElement, Point(-1, -1), 1);
// 原图 新图 卷积核(结构元) 锚点 腐蚀操作次数(默认1次)
}
python:
# 腐蚀
def Enrode():
# 腐蚀
erode = cv2.erode(img, kernel=(7, 7), iterations=5)
# 卷积核大小 迭代次数
cv2.imshow("erode", erode)
回调函数:把函数指针作为参数。
//回调函数膨胀
void CallBack_Dilate(int, void*)
// 轨迹条位置 用户数据
{
cont = element_size * 2 + 1; //结构元尺寸控制
Dilate(); //膨胀
imshow("Dilate:", dst); //显示
}
//回调函数腐蚀
void CallBack_Erode(int, void*)
// 轨迹条位置 用户数据
{
cont = element_size * 2 + 1; //结构元尺寸控制
Erode(); //腐蚀
imshow("Erode:", dst); //显示
}
createTrackbar(conststring& trackbarname, conststring& winname, int* value, int count, TrackbarCallback onChange=0,void* userdata=0);
参数解释:
1、trackbarname,表示轨迹条的名字,用来代表我们创建的轨迹条。
2、winname,填窗口的名字,表示这个轨迹条会依附到哪个窗口上,即对应namedWindow()创建窗口时填的某一个窗口名。(窗口名需与显示窗口一致)
3、value,一个指向整型的指针,表示滑块的位置。并且在创建时,滑块的初始位置就是该变量当前的值。
4、count,表示滑块可以达到的最大位置的值。滑块最小的位置的值始终为0。
5、onChange,首先注意他有默认值0。这是一个指向回调函数的指针,每次滑块位置改变时,这个函数都会进行回调。并且这个函数的原型必须为void XXXX(int,void*);其中第一个参数是轨迹条的位置,第二个参数是用户数据(看下面的参数)。如果回调是NULL指针,表示没有回调函数的调用,仅第三个参数value有变化。
6、userdata,他也有默认值0。这个参数是用户传给回调函数的数据,用来处理轨迹条事件。如果使用的第三个参数value实参是全局变量的话,完全可以不去管这个userdata参数。
//创建滑动条1(膨胀)
createTrackbar("结构元尺寸", "Dilate:", &element_size, max_size, CallBack_Dilate);
//创建滑动条2(腐蚀)
createTrackbar("结构元尺寸", "Erode:", &element_size, max_size, CallBack_Erode);
// 滑动条名字 窗口名字(必须和原窗口一致) 当前数值 最大数值 回调函数(函数指针作为参数)
//每次滑块位置改变,回调函数都会回调
C++:
//膨胀与腐蚀(回调函数)
#include
#include
using namespace cv;
using namespace std;
Mat img, dst;
int element_size = 3; //结构元大小(2*ele +1)
int max_size = 21; //最大容量
int cont; //控制结构元大小
//图像初始化
void Image_Init()
{
img = imread("Resource/test4.jpg");
dst = Mat::zeros(img.size(), img.type());
if (img.empty())
{
printf("图像加载失败");
exit(0);
}
}
//显示图像
void Show()
{
imshow("原图", img);
}
//膨胀
void Dilate()
{
//卷积核(结构元)
Mat structureElement = getStructuringElement(MORPH_RECT, Size(cont, cont), Point(-1, -1));
// 返回指定形状和尺寸的结构元素 形状 尺寸(宽, 高) 锚点(中心点)
//膨胀函数
dilate(img, dst, structureElement, Point(-1, -1), 1);
// 原图 新图 卷积核(结构元) 锚点 膨胀操作次数(默认1次)
}
//腐蚀
void Erode()
{
//卷积核(结构元)
Mat structureElement = getStructuringElement(MORPH_RECT, Size(cont, cont), Point(-1, -1));
// 返回指定形状和尺寸的结构元素 形状 尺寸(宽, 高) 锚点(中心点)
//腐蚀函数
erode(img, dst, structureElement, Point(-1, -1), 1);
// 原图 新图 卷积核(结构元) 锚点 腐蚀操作次数(默认1次)
}
//回调函数膨胀
void CallBack_Dilate(int, void*)
// 轨迹条位置 用户数据
{
cont = element_size * 2 + 1; //结构元尺寸控制
Dilate(); //膨胀
imshow("Dilate:", dst); //显示
}
//回调函数腐蚀
void CallBack_Erode(int, void*)
// 轨迹条位置 用户数据
{
cont = element_size * 2 + 1; //结构元尺寸控制
Erode(); //腐蚀
imshow("Erode:", dst); //显示
}
int main()
{
Image_Init(); //图像初始化
//Dilate(); //膨胀
//Erode(); //腐蚀
//回调函数(简便控制膨胀与腐蚀)
CallBack_Dilate(element_size, 0); //先显示图片(膨胀回调函数)
CallBack_Erode(element_size, 0); //先显示图片(腐蚀回调函数)
// 轨迹条位置 用户数据
//创建滑动条1(膨胀)
createTrackbar("结构元尺寸", "Dilate:", &element_size, max_size, CallBack_Dilate);
//创建滑动条2(腐蚀)
createTrackbar("结构元尺寸", "Erode:", &element_size, max_size, CallBack_Erode);
// 滑动条名字 窗口名字(必须和原窗口一致) 当前数值 最大数值 回调函数(函数指针作为参数)
//每次滑块位置改变,回调函数都会回调
Show(); //显示原图像
waitKey(0);
return 0;
}
python:
# 形态学(膨胀、腐蚀、开闭运算、顶帽与底帽)
import cv2
# 膨胀
def Dilate():
# 膨胀
dilate = cv2.dilate(img, kernel=(7, 7), iterations=1)
# 卷积核大小 迭代次数
cv2.imshow("dilate", dilate)
# 腐蚀
def Enrode():
# 腐蚀
erode = cv2.erode(img, kernel=(7, 7), iterations=5)
# 卷积核大小 迭代次数
cv2.imshow("erode", erode)
# 开运算(先腐后膨)
def Open():
open = cv2.morphologyEx(img, cv2.MORPH_OPEN, (7, 7), iterations=5)
# 类型 卷积核大小 迭代次数
cv2.imshow('open', open)
# 闭运算(先膨后腐)
def Close():
close = cv2.morphologyEx(img, cv2.MORPH_CLOSE, (7, 7), iterations=5)
# 类型 卷积核大小 迭代次数
cv2.imshow('close', close)
# 顶帽(原-开)
def TopHat():
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, (7, 7), iterations=5)
# 类型 卷积核 迭代次数
cv2.imshow('TopHat', tophat)
# 底帽(原-闭)
def BlackHat():
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, (7, 7), iterations=5)
# 类型 卷积核 迭代次数
cv2.imshow('BlackHat', blackhat)
if __name__ == '__main__':
# 读取图片
img = cv2.imread("Resource/test5.jpg")
cv2.imshow("img", img)
Dilate() #膨胀
Enrode() #腐蚀
Open() #开运算
Close() #闭运算
TopHat() #顶帽运算
BlackHat() #底帽运算
cv2.waitKey(0)
https://blog.csdn.net/weixin_41695564/article/details/79928835
https://www.bilibili.com/video/BV1uy4y1p7BR?from=search&seid=4644291277982613292